问题
depthWrite: false
与depthTest: false
之间是否存在显著差异?使用depthTest
是否提供性能优势?在选择其中一种时,是否会有任何功能上的牺牲?
原始问题
我想渲染一个THREE.Points
对象,每个点都是具有半透明圆形的粒子。我使用从canvas
元素加载的 THREE.Texture
,并将其传递给THREE.PointsMaterial
上的map
属性。
透明度并没有完全生效,有些圆圈重叠得很好,但其他圆圈的行为就像它们是实心的。
后来我了解到在THREE.PointsMaterial
上使用depthWrite: false
和depthTest: false
可以解决这个问题。
目前情况
我有一个代码示例(嵌入在下面),展示了重叠点错误的情况,并可以使用depthTest
或depthWrite
进行修复:
var points = new THREE.Points(
new THREE.Geometry(),
new THREE.PointsMaterial({
//depthTest: false,
//depthWrite: false,
map: circleTexture,
size: circleDiameter,
transparent: true
})
);
我对这一切都很新,但我试着阅读了相关主题,从我所了解的来看(如果我错了,请纠正我),深度缓冲区用于确定哪些片段被遮挡并且不需要渲染。关闭depthWrite
或depthTest
中的任何一个将使对象免于此过程。它们的区别在于:
depthWrite:false
仍然计算深度,但无论如何都渲染整个对象depthTest:false
甚至不会计算深度
这听起来像是关闭depthTest
而不是depthWrite
将导致我失去一些对象特性,但通过完全跳过计算可能会获得性能提升?但是,我会失去哪些质量呢?实际上是否存在性能差异?这里显露出我的无知。
// 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>
,当圆形在固体几何体后面时,它们将无法正确遮挡。但是如果我使用
depthWrite: false`,它们将被正确地阻挡。 - aburner