用白色 PlaneGeometry 填充精确尺寸的视口

问题描述 投票:0回答:1

我正在尝试使用planeGeometry 将 Threejs 中的视口涂成白色。原因是我需要具有大小和变换(旋转和位置)的视图平面。

这是我的两次失败尝试:

    function createFullScreenPlane() {
        const aspect = camera.aspect;
        const frustumHeight = 2 * Math.tan(THREE.MathUtils.degToRad(camera.fov) / 2) * camera.position.z;
        const frustumWidth = frustumHeight * aspect;

        const planeGeometry = new THREE.PlaneGeometry(frustumWidth, frustumHeight);
        const planeMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff });
        const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);

        planeMesh.lookAt(camera.position);

        scene.add(planeMesh);
    }

并且:

    function createFullScreenPlane() {

        const topLeft = new THREE.Vector3(-1, 1, -1);
        const bottomRight = new THREE.Vector3(1, -1, -1);

        topLeft.unproject(camera);
        bottomRight.unproject(camera);

        const width = bottomRight.x - topLeft.x;
        const height = topLeft.y - bottomRight.y;

        const planeGeometry = new THREE.PlaneGeometry(width, height);
        const planeMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff, side: THREE.DoubleSide });
        const plane = new THREE.Mesh(planeGeometry, planeMaterial);

        plane.position.copy(camera.position).add(camera.getWorldDirection(new THREE.Vector3()).multiplyScalar(1));

        const posCamera = new THREE.Vector3(0, 0, 0);
        posCamera.unproject(camera);
        console.log(topLeft, bottomRight, posCamera, camera.position);

        plane.lookAt(camera.position);

        scene.add(plane);
    }
three.js camera viewport
1个回答
0
投票

如果我理解正确,您需要用响应平面覆盖视口...您可以通过多种方式渲染它,具体取决于您的需求和平面应该做什么。如果它是一个仅覆盖视口的简单网格,在我看来没有必要使用

PerspectiveCamera
,更容易简化你的生活并使用更适合这些的
OrthographicCamera
[2D] 情况。

*{margin:0};
<script type="importmap">
  {
"imports": {
  "three": "https://unpkg.com/[email protected]/build/three.module.js",
  "three/addons/": "https://unpkg.com/[email protected]/examples/jsm/"
}
  }
</script>

<script type="module">
import * as THREE from "three";

const scene = new THREE.Scene();
const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0.1, 10);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const g = new THREE.PlaneGeometry(2, 2);
const m = new THREE.MeshBasicMaterial({ color: 0xf11fff });
const p = new THREE.Mesh(g, m);
scene.add(p);

camera.position.z = 1;

function responsive() {
    renderer.setSize(window.innerWidth, window.innerHeight);
    camera.left = -1;
    camera.right = 1;
    camera.top = 1;
    camera.bottom = -1;
    camera.updateProjectionMatrix();
}

window.addEventListener('resize', responsive, false);

function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
}
animate();


</script>

但是当您需要透视相机时,请尝试这个解决方案,它是第一个片段的扩展。尝试基于

camera.near
计算视锥体(这会产生情况,当相机到最近物体的距离在您的案例平面中保持恒定时),而不是基于位于 z 轴上的相机,您如何尝试渲染.

*{margin:0};
<script type="importmap">
  {
    "imports": {
      "three": "https://unpkg.com/[email protected]/build/three.module.js",
      "three/addons/": "https://unpkg.com/[email protected]/examples/jsm/"
    }
  }
</script>

<script type="module">
import * as THREE from "three";

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.z = 5;

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

function createFullScreenPlane() {
    const aspect = camera.aspect;
    const frustumHeight = 2 * Math.tan(THREE.MathUtils.degToRad(camera.fov) / 2) * camera.near;
    const frustumWidth = frustumHeight * aspect;

    const planeMaterial = new THREE.MeshBasicMaterial({ color: 0xf11fff, side: THREE.DoubleSide });
    const planeMesh = new THREE.Mesh(new THREE.PlaneGeometry(frustumWidth, frustumHeight), planeMaterial);
    planeMesh.renderOrder = -1;
    planeMesh.material.depthTest = false;
    
    planeMesh.position.copy(camera.position).add(camera.getWorldDirection(new THREE.Vector3()).multiplyScalar(camera.near));
    planeMesh.lookAt(camera.position.clone().add(camera.getWorldDirection(new THREE.Vector3())));

    scene.add(planeMesh);
}

createFullScreenPlane();

function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
}

animate();

window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
    scene.clear();
    createFullScreenPlane();
});
</script>

奖励技巧。

我最近有一个项目,我必须使用您描述的功能,不同之处在于我必须使用

ShaderMaterial
。当你遇到这样的情况时,你不必使用
projectionMatrix
modelViewMatrix
来变换顶点位置,只需缩短
gl_Position
来自:

gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);

至:

gl_Position = vec4(position, 1.0);

但这只是一个旁注......

© www.soinside.com 2019 - 2024. All rights reserved.