【问题标题】:Three.js Objects 'shimmering' at large DistancesThree.js 对象在远距离“闪烁”
【发布时间】:2015-06-30 03:57:15
【问题描述】:

我目前正在从事一个项目,该项目涉及在对象大小范围为 10 到 1000000 的场景中工作。我一直有一个问题,当我在这些尺寸的大范围内时,物体开始“闪烁”这只发生在物体相交时,然后随着相机远离物体它变得越来越“暴力” .

我在这里上传了一张问题图片:http://imgur.com/SOeemng

虽然我不知道是什么原因造成的,但我有一些可能的想法:

首先,我只是在处理对 three.js / webgl 来说太大的尺寸

我认为可能存在问题的第二种可能性是使用以下我制作的相机控件:

    if(mouseIsDown == true){
        if(this.movementSpeed < this.maxSpeed){
            this.movementSpeed += this.acceleration
        }else{
            this.movementSpeed = this.maxSpeed
        }

    }else{
        if(this.movementSpeed > this.minSpeed){
            this.movementSpeed = this.movementSpeed/this.deceleration
        }else{
            this.movementSpeed = this.minSpeed  
        }

    }

其中 this.minSpeed = 0,而 this.movementSpeed 用于像这样移动相机:

var actualSpeed = delta * this.movementSpeed;
this.object.translateZ( -actualSpeed * forwardOrAuto );
this.object.translateX( actualSpeed * sideSpeed );
this.object.translateY( actualSpeed * upSpeed );

我不认为这会是问题,但由于移动速度实际上永远不会等于零,这可能是一个问题。即使移动速度为 10^-20 或 -30,仍然会发生闪烁。

如果这很重要,我也在 r.55 上。

【问题讨论】:

    标签: javascript three.js webgl


    【解决方案1】:

    听起来像是精度问题。运动可以放大舍入误差的影响。在three.js中处理太阳系模型(uom:米)时,我自己遇到了许多“闪烁”纹理/模型的问题。 gaitat 绝对正确,您遇到了 z 缓冲区深度精度问题。我和我的搭档有几种处理方法。

    z 缓冲区不是线性的。 gaitat 提到的 sjbaker 的网站将像几个月前对我所做的那样清楚地说明这一点。大多数 z 缓冲区精度都在附近。如果您的对象的大小达到 1000000 个单位,那么对象本身,更不用说它们之间的空间,已经超出了有效精度的范围。许多很多视频游戏使用的一种解决方案是移动玩家(相机),而是移动世界。这样,随着物体靠近相机,它的精度就会提高。这对于远处的大型重叠对象上的纹理(闪烁/遮挡)或远离轴向原点的小网格最为重要,在这些情况下,舍入问题变得严重到足以将网格跳出视野。不过,说起来容易做起来难,因为您要么必须进行“及时”计算以移动与玩家相关的所有内容(并且仍然会遇到舍入错误),要么提出更优雅的解决方案。

    对于非常高的远距离数字,您将损失很少的近精度,但您将在中等范围内获得相当大的精度,而近数字略大。即使您正在使用的网格可以小到 10 个单位,近摄像机设置为 10 或 100 也可能会让您松懈。相机设置不是处理 z-buffer 的唯一方法。

    polygonOffset - 你有效地告诉 z 缓冲区哪个东西(网格上的材料)属于顶部。它可以引入尽可能多的问题,因为它解决了,并且可能需要相当多的调整。认为它类似于 css 中的 z-index,但更易变。增加一种材质的偏移量以确保它渲染在远处的某物上,可能会使其渲染到附近的某物上。它会滚雪球,迫使您在大多数对象上设置偏移量。对于 polygonOffset,因子和单位数通常介于 -1.0 和 1.0 之间,可能需要调整。

    depthWrite=false - 这意味着“不要写入深度缓冲区”,非常适合应该始终在所有内容“后面”呈现的材质。天空盒和背景就是很好的例子。

    我们的项目使用了上述所有方法,但结果仍然很平庸,尽管我们处理的数字大到 40 个以米为单位的天文单位(冥王星)。

    “他们”称其为“z-fighting”,所以要打好仗!

    【讨论】:

    • 感谢您提供如此长且内容丰富的回答。这绝对是我需要进一步了解的主题!
    • 是否可以/良好的做法动态更改相机的远近,这取决于它需要看到什么
    • 您将有效地破坏和重新分配可能会产生闪烁的相机。 (您将更改投影矩阵)。
    【解决方案2】:

    由于您的范围如此之大,因此您必须将相机设置为接近 0 的平面和接近 1000000 的远平面。但是 z 分辨率不够。你可以在http://www.sjbaker.org/steve/omniv/love_your_z_buffer.html阅读更多关于它的信息。

    【讨论】:

    • 精彩的评论和精彩的文章。非常感谢您提供的信息!
    • 这自古以来就被称为 z-battle - 基本上,如果你有一个 16 位 z 缓冲区(分辨率 = 65536)和 100000(范围 = 100K)的截锥体深度,那么较低您清楚区分 z 的能力的限制是您的分辨率的倒数 * 您的范围 - 小于该数字,并且前后平面可以有效地改变每个渲染通道上的位置
    【解决方案3】:

    一个我不知道如何实现但可能可行的解决方案是使用两个场景和两个摄像头。

    一个场景是近距离的,另一个是远距离的。每个场景都使用具有适合所需内容的 zNear 和 zFar 的相机进行渲染。即近景有一个 zNear = 0.1 和 zFar = 10,000 的相机,远景有一个 zNear = 10,000 和 zFar = 6,000,000 的相机

    困难在于将 TrackballControls 连接到两个摄像机以同步场景。

    【讨论】:

      猜你喜欢
      • 2021-10-15
      • 2015-05-18
      • 2013-02-11
      • 2013-07-04
      • 1970-01-01
      • 2010-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多