我正在尝试使用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);
}
如果我理解正确,您需要用响应平面覆盖视口...您可以通过多种方式渲染它,具体取决于您的需求和平面应该做什么。如果它是一个仅覆盖视口的简单网格,在我看来没有必要使用
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);
但这只是一个旁注......