Three.js - 用于 THREE.Points 上透明画布纹理贴图的 depthWrite 与 depthTest [英] Three.js - depthWrite vs depthTest for transparent canvas texture map on THREE.Points

查看:83
本文介绍了Three.js - 用于 THREE.Points 上透明画布纹理贴图的 depthWrite 与 depthTest的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

depthWrite: falsedepthTest: false 之间有显着区别吗?使用 depthTest 是否提供性能优势?选择一个或另一个在功能上有任何牺牲吗?

Is there a significant difference between depthWrite: false and depthTest: false? Does using depthTest offer a performance advantage? Is there any sacrifice in functionality choosing one or the other?

我想渲染一个 THREE.Points 对象,每个点都带有半透明圆圈.我使用了从 canvas 元素加载的 THREE.Texture 并将其传递给 THREE.PointsMaterial 上的 map 属性>.

I wanted to render a THREE.Points object with translucent circles as each point. I used a THREE.Texture loaded from a canvas element and passed it to the map property on the THREE.PointsMaterial.

透明度没有完全起作用,一些圆圈重叠得很好,但其他的表现得好像它们是实心的.

The transparency did not completely work, some circles overlapped fine but others behaved as if they were solid.

我在了解 THREE.PointsMaterial 上的 depthWrite: falsedepthTest: false 后修复了它.

I fixed it after learning about depthWrite: false and depthTest: false on the THREE.PointsMaterial.

我有一个代码示例(嵌入在底部)显示重叠点错误,可以使用 depthTestdepthWrite 修复它:

I have a code example (embedded at bottom) that shows the overlapping points error, and can use depthTest or depthWrite to fix it:

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

我是这一切的新手,但我尝试阅读该主题,并且据我所知(如果我错了请纠正我)深度缓冲区用于确定哪些片段被遮挡并且不需要渲染.关闭 depthWritedepthTest 将使对象免于此过程.它们的不同之处在于:

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. They differ in that:

  • depthWrite: false 仍然计算深度,但不考虑渲染整个对象

  • depthWrite: false still calculates depth, but renders the entire object regardless

depthTest: false 甚至不计算深度

所以听起来我会通过关闭 depthTest 而不是 depthWrite 失去一些对象质量,但可能通过完全跳过计算来提高性能?但是,我会失去哪些品质?实际上是否存在性能差异?我的无知在这里闪耀.

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? 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 表示将深度测试全部关闭.(阅读/测试和写作)

Depth test off means to turn off depth testing all together. (reading/testing and writing)

Depth write off 是指防止深度缓冲区被写入.

Depth write off means to prevent the depth buffer from being written.

那么首先,什么是深度测试?假设您要直接在您面前绘制 2 个相同的形状,但与您的距离不同.在现实生活中,您希望只看到离您更近的形状,对吗?

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. 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.

深度测试是一种内置于当今 GPU 中的工具,它允许获得所需的绘制输出无论绘制对象的顺序如何.这通常非常有用,但它有一个严重的弱点:深度和混合(透明度)不能一起工作.为什么会这样?那么深度测试的作用是对于绘制的每个像素,将该像素到相机的距离(深度)与存储在该像素中的深度值进行比较.如果距离小于存储的深度值,则绘制该像素,否则丢弃该像素.

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. 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.

希望现在很清楚,深度测试有两个方面:深度值的比较和将深度值写入深度缓冲区. DepthTest 和 depthWrite 使您可以很好地控制如何存档想要的效果.

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.

同时关闭深度测试比仅仅关闭深度写入要快.但是,有时您只想阻止新像素写入深度缓冲区,但仍启用深度测试.例如,在您的演示中,如果您要在中心绘制一个完全不透明的立方体;您仍然希望隐藏比表示不透明立方体的像素更深的像素(深度测试方面),但还希望防止透明圆圈中的像素相互阻塞(写入方面).您看到的常见绘制配置是绘制所有不透明对象并启用深度测试,关闭深度写入,然后以从后到前的顺序绘制透明对象.

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.

这篇关于Three.js - 用于 THREE.Points 上透明画布纹理贴图的 depthWrite 与 depthTest的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆