• Three.js相机参数及Z-Fighting问题的解决方案


    本主题讨论透视相机以及如何为远距离环境设置合适的视锥体。

    在这里插入图片描述

    推荐:用 NSDT编辑器 快速搭建可编程3D场景

    透视相机是一种投影模式,旨在模仿人类在现实世界中看待事物的方式。 这是渲染 3D 场景最常用的投影模式。 - three.js

    如果你看一下 Three.js 文档中的透视相机构造函数,它会是这样的:

    new THREE.PerspectiveCamera( fov, aspect, near, far )
    
    • 1

    其中:

    • fov:相机视野
    • aspect: 相机宽高比;
    • near:相机近平面
    • far:相机远平面。

    这些参数共同定义了相机的视锥体 - 3D 场景的区域将被渲染并出现在屏幕上。

    例如:

    const camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 );
    
    • 1

    基本上,你可以将 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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    你认为会发生什么?

    3D 模型出了问题,你可以看到纹理全部损坏。 这是 z -fighting的示例,其中计算机上的 GPU 没有足够的精度来确定哪些像素在前面、哪些像素在后面。
    在这里插入图片描述

    有一个解决方案是你需要告诉 Three.js 使用不同的方法来计算哪些像素在前面,哪些像素在后面。 我们可以通过在 WebGLRenderer 构造函数中启用 logarithmicDepthBuffer 来做到这一点。

    所以我们的渲染器现在看起来像这样:

    // renderer
    this.renderer = new THREE.WebGLRenderer({ 
      antialias: true,
      logarithmicDepthBuffer: true
    });
    // ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    检查结果,它应该可以工作…
    在这里插入图片描述

    logarithmicDepthBuffer 显然可以解决这个问题,但并不总是建议使用它,因为它可能比标准解决方案慢,尤其是在大多数移动设备中。

    这意味着你应该始终调整近距和远距以满足你的需要。 现在,请注意,如果想绘制一个距离很远的巨大场景而不破坏场景中的任何对象,你可以尝试一下还有一个替代选项。

    希望这可以帮助!


    原文链接:相机参数及z-fighting解决方案 — BimAnt

  • 相关阅读:
    java毕业设计采购系统mybatis+源码+调试部署+系统+数据库+lw
    rust学习—— 不一样的break
    VP Atcoder Beginner Contest 265
    Nuxt 菜鸟入门学习笔记五:CSS 样式
    Golang context包的源码分析
    vue3中弹框中的el-select下拉组件显示value而不显示label
    继续折腾Centos7开启BBR加速有效提升访问和下载速度(亲测有效)
    Python技法:实现简单的递归下降Parser
    【日记】gulp之删除文件
    推荐系统工业界顶会论文总结——WSDM 2021
  • 原文地址:https://blog.csdn.net/shebao3333/article/details/132586971