简体   繁体   English

Three.js - 用于 THREE.Points 上透明画布纹理贴图的 depthWrite 与 depthTest

[英]Three.js - depthWrite vs depthTest for transparent canvas texture map on THREE.Points

Question问题

Is there a significant difference between depthWrite: false and depthTest: false ? depthWrite: falsedepthTest: false之间是否存在显着差异? Does using depthTest offer a performance advantage?使用depthTest是否提供性能优势? Is there any sacrifice in functionality choosing one or the other?选择一个或另一个在功能上有任何牺牲吗?

Original problem原问题

I wanted to render a THREE.Points object with translucent circles as each point.我想渲染一个THREE.Points对象,每个点都带有半透明圆圈。 I used a THREE.Texture loaded from a canvas element and passed it to the map property on the THREE.PointsMaterial .我使用了从canvas元素加载的THREE.Texture并将其传递给THREE.PointsMaterial上的map属性。

The transparency did not completely work, some circles overlapped fine but others behaved as if they were solid.透明度并没有完全起作用,一些圆圈重叠得很好,但其他的表现得好像它们是实心的。

I fixed it after learning about depthWrite: false and depthTest: false on the THREE.PointsMaterial .我了解后修好了depthWrite: falsedepthTest: falseTHREE.PointsMaterial

Where I'm at我在哪里

I have a code example (embedded at bottom) that shows the overlapping points error, and can use depthTest or depthWrite to fix it:我有一个代码示例(嵌入在底部)显示重叠点错误,并且可以使用depthTestdepthWrite来修复它:

var points = new THREE.Points(
    new THREE.Geometry(),
    new THREE.PointsMaterial({
        //depthTest: false,
        //depthWrite: false,
        map: circleTexture,
        size: circleDiameter,
        transparent: true
    })
);

I'm new to all this, but I tried reading up on the subject, and from what I can tell (correct me if I'm wrong) the depth buffer is used to determine what fragments are occluded and do not need rendering.我对这一切都很陌生,但我尝试阅读该主题,并且根据我的了解(如果我错了,请纠正我),深度缓冲区用于确定哪些片段被遮挡并且不需要渲染。 Turning off either depthWrite or depthTest will exempt an object from this process.关闭depthWritedepthTest将使对象免于此过程。 They differ in that:它们的不同之处在于:

  • depthWrite: false still calculates depth, but renders the entire object regardless depthWrite: false仍然计算深度,但不考虑渲染整个对象

  • depthTest: false does not even calculate depth depthTest: false甚至不计算深度

So it sounds like I would lose some object qualities by turning off depthTest instead of depthWrite , but possibly get a performance boost by skipping the calculation altogether?所以听起来我会通过关闭depthTest而不是depthWrite失去一些对象质量,但可能通过完全跳过计算来提高性能? But, what qualities would I be losing?但是,我会失去哪些品质? And is there actually a performance difference?实际上是否存在性能差异? Here my ignorance shines through.在这里,我的无知闪耀。

 // Sizes var sceneWidth = 200; var sceneHeight = 200; var lineLength = 50; var circleRadius = 32; var circleDiameter = circleRadius * 2; // Renderer var renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); renderer.setSize(sceneWidth, sceneHeight); document.body.appendChild(renderer.domElement); // Scene var scene = new THREE.Scene(); // Camera var d = 100; var aspect = sceneWidth / sceneHeight; var camera = new THREE.OrthographicCamera( -d * aspect, d * aspect, d, -d, 1, 12000 ); camera.position.set(140, 140, 140); scene.add(camera); // Controls var controls = new THREE.OrthographicTrackballControls( camera, renderer.domElement ); controls.rotateSpeed = 0.2; controls.addEventListener('change', function () { renderer.render(scene, camera); }); window.addEventListener('resize', function() { controls.handleResize(); }); // Circle texture var canvasEl = document.createElement('canvas'); var context = canvasEl.getContext('2d'); canvasEl.width = circleDiameter; canvasEl.height = circleDiameter; context.fillStyle = 'rgba(255, 255, 255, 0.5)'; context.beginPath(); context.arc(circleRadius, circleRadius, circleRadius, 0, Math.PI * 2); context.fill(); var circleTexture = new THREE.Texture(canvasEl); circleTexture.needsUpdate = true; // Points var points = new THREE.Points( new THREE.Geometry(), new THREE.PointsMaterial({ //depthTest: false, //depthWrite: false, map: circleTexture, size: circleDiameter, transparent: true }) ); points.geometry.vertices.push(new THREE.Vector3(0, 0, 0)); points.geometry.vertices.push(new THREE.Vector3(0, lineLength, 0)); points.geometry.vertices.push(new THREE.Vector3(0, lineLength, lineLength)); points.geometry.vertices.push(new THREE.Vector3(0, 0, lineLength)); scene.add(points); // Lines var lines = new THREE.Line( new THREE.Geometry(), new THREE.LineBasicMaterial({ linewidth: 1.2, color: 0xffffff, transparent: true, opacity: 0.25 }) ); lines.geometry.vertices.push(new THREE.Vector3(0, 0, 0)); lines.geometry.vertices.push(new THREE.Vector3(0, lineLength, 0)); lines.geometry.vertices.push(new THREE.Vector3(0, lineLength, 0)); lines.geometry.vertices.push(new THREE.Vector3(0, lineLength, lineLength)); lines.geometry.vertices.push(new THREE.Vector3(0, lineLength, lineLength)); lines.geometry.vertices.push(new THREE.Vector3(0, 0, lineLength)); lines.geometry.vertices.push(new THREE.Vector3(0, 0, lineLength)); lines.geometry.vertices.push(new THREE.Vector3(0, 0, 0)); scene.add(lines); // Render function render() { window.requestAnimationFrame(render); renderer.render(scene, camera); controls.update(); } render();
 * { margin: 0; padding: 0; } body { background-color: #333; }
 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>Document</title> </head> <body> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r76/three.min.js"></script> <script src="http://threejs.org/examples/js/controls/OrthographicTrackballControls.js"></script> </body> </html>

Depth test off means to turn off depth testing all together.深度测试关闭意味着一起关闭深度测试。 (reading/testing and writing) (阅读/测试和写作)

Depth write off means to prevent the depth buffer from being written.深度注销是指防止深度缓冲区被写入。

So first of all, what is depth test?那么首先,什么是深度测试? Suppose if you are to draw 2 identical shapes directly in front of you but of different distance to you.假设您要直接在您面前绘制 2 个相同的形状,但与您的距离不同。 In real life, you expect to only see the shape that is closer to you, correct?在现实生活中,您希望只看到离您更近的形状,对吗?

Well if you were to try to do this without a depth test, you will only get the desired effect half the time: if the distant object is drawn before the closer object, no problem, same as real life;好吧,如果你在没有深度测试的情况下尝试这样做,你只会得到一半的效果:如果在较近的物体之前绘制远处的物体,没问题,和现实生活一样; but if the closer object is drawn before the distance object, oh-oh, the distant object is visible when it should be not.但是如果在远处物体之前绘制更近的物体,哦,哦,远处的物体在不应该看到的时候是可见的。 Problematic.有问题。

Depth test is a tool built in today's GPUs to allow to get the desired draw output regardless of the order which the objects are drawn .深度测试是一种内置于当今 GPU 中的工具,无论对象的绘制顺序如何,它都能获得所需的绘制输出。 This is normally very useful but it comes with a critical weakness: depth and blending(transparency) do not work together .这通常非常有用,但它有一个严重的弱点:深度和混合(透明度)不能一起工作 Why is this the case?为什么会这样? Well what depth test does is that for every pixel that is drawn, the distance(depth) of that pixel to the camera is compared to the depth value stored in that the pixel.那么深度测试的作用是,对于绘制的每个像素,将该像素到相机的距离(深度)与存储在该像素中的深度值进行比较。 If the distance is less that the stored depth value, the pixel is drawn, otherwise that pixel is discarded.如果距离小于存储的深度值,则绘制像素,否则丢弃该像素。

This explains why you sometimes see the black quads in your demo.这解释了为什么您有时会在演示中看到黑色四边形。 When those quads are drawn first, their depth values are written into the depth buffer.当首先绘制这些四边形时,它们的深度值将写入深度缓冲区。 Then when the more distant quads are drawn, their depth value are greater than the depth in the buffer and thus those pixels are discarded.然后当绘制更远的四边形时,它们的深度值大于缓冲区中的深度,因此这些像素被丢弃。 In other viewing angles it just so happens that distant quads are drawn first and then the closer quads, so no pixels are discarded due to depth testing.在其他视角中,恰好先绘制远处的四边形,然后绘制较近的四边形,因此不会因深度测试而丢弃任何像素。

Hopefully its clear now that there are two aspects of depth testing: the comparison of depth values and the writing of depth values to the depth buffer.希望现在很清楚深度测试两个方面:深度值的比较和将深度值写入深度缓冲区。 DepthTest and depthWrite gives you fine control over how to archive the desired effect. DepthTest 和 depthWrite 使您可以很好地控制如何存档所需的效果。

Turning off depth testing all together would be faster than just depth writing.一起关闭深度测试将比仅深度写入更快。 However, sometimes you just want to prevent new pixels to write to the depth buffer but still with the depth testing enabled.但是,有时您只想阻止新像素写入深度缓冲区,但仍启用深度测试。 For example, in your demo if you were to draw a totally opaque cube in the center;例如,在您的演示中,如果您要在中心绘制一个完全不透明的立方体; you still want pixels with further depth than the pixels representing the opaque cube to be hidden (the depth testing aspect), but also want to prevent pixels from the transparent circles from blocking each other (the writing aspect).您仍然希望隐藏比表示不透明立方体的像素更深的像素(深度测试方面),但还希望防止透明圆圈中的像素相互阻塞(写入方面)。 A common draw configuration you see is to draw all the opaque object with depth testing on, turn depth write off, then draw the transparent objects in a back to front order.您看到的一种常见绘制配置是在启用深度测试的情况下绘制所有不透明对象,关闭深度写入,然后以从后到前的顺序绘制透明对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM