本主题讨论透视相机以及如何为远距离环境设置合适的视锥体。
推荐:用 NSDT编辑器 快速搭建可编程3D场景
透视相机是一种投影模式,旨在模仿人类在现实世界中看待事物的方式。 这是渲染 3D 场景最常用的投影模式。 - three.js
如果你看一下 Three.js 文档中的透视相机构造函数,它会是这样的:
new THREE.PerspectiveCamera( fov, aspect, near, far )
其中:
- fov:相机视野
- aspect: 相机宽高比;
- near:相机近平面
- far:相机远平面。
这些参数共同定义了相机的视锥体 - 3D 场景的区域将被渲染并出现在屏幕上。
例如:
const camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 );
基本上,你可以将 fov、near、far 设置为你想要的任何范围。 例如,将 fov 调整到 10 或 20 左右,你将很容易看到物体的正面,或者实际上所有内容都放大到屏幕上,而如果将 fov 设置为 100 中的 90 左右,则场景中的所有内容都会移得很远。
那么 near 和 far 呢?
当然,你也可以设置近平面和远平面的任意值,但如果近远范围很大,那么近距离时会出现更多的 z-fighting,而如果范围太小,则会破坏场景。
理想情况下,如果你设置 near = 0.01,那么far应该是1000,或者 near = 1,那么你可以进一步设置 far = 10000。
但是,如果你确实需要像长距离这样的东西,可以使用 near = 0.0000000001 和 far = 10000000000000。但在这种情况下,您可能需要另一个选项来配置 WebGLRenderer。
为什么?
原因是 GPU 的精度有限,无法确定某个物体是在其他物体的前面还是后面。 这种精度分布在近处和远处。 更糟糕的是,默认情况下靠近相机的精度是详细的,而远离相机的精度是粗略的。 这些单位从近开始,随着接近远而慢慢扩展。 - Threejsfundamentals.org
为了说明这种情况,我们有一个带有 3D 模型的简单场景,相机、渲染器的设置如下:
// camera
this.camera = new THREE.PerspectiveCamera(
45,
window.innerWidth / window.innerHeight,
0.00000001,
10000
);
this.camera.position.set(10, 6, 10);
// renderer
this.renderer = new THREE.WebGLRenderer({ antialias: true });
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.physicallyCorrectLights = true;
this.renderer.outputEncoding = THREE.sRGBEncoding;
你认为会发生什么?
3D 模型出了问题,你可以看到纹理全部损坏。 这是 z -fighting的示例,其中计算机上的 GPU 没有足够的精度来确定哪些像素在前面、哪些像素在后面。
有一个解决方案是你需要告诉 Three.js 使用不同的方法来计算哪些像素在前面,哪些像素在后面。 我们可以通过在 WebGLRenderer 构造函数中启用 logarithmicDepthBuffer 来做到这一点。
所以我们的渲染器现在看起来像这样:
// renderer
this.renderer = new THREE.WebGLRenderer({
antialias: true,
logarithmicDepthBuffer: true
});
// ...
检查结果,它应该可以工作...
logarithmicDepthBuffer 显然可以解决这个问题,但并不总是建议使用它,因为它可能比标准解决方案慢,尤其是在大多数移动设备中。
这意味着你应该始终调整近距和远距以满足你的需要。 现在,请注意,如果想绘制一个距离很远的巨大场景而不破坏场景中的任何对象,你可以尝试一下还有一个替代选项。
希望这可以帮助!