ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

javascript – Three.js – depthWrite vs depthTest for THREE.Points上的透明画布纹理贴图

2019-10-04 15:37:21  阅读:332  来源: 互联网

标签:javascript webgl three-js


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>

解决方法:

深度测试意味着一起关闭深度测试. (阅读/测试和写作)

深度写入意味着防止深度缓冲区被写入.

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

好吧,如果你试图在没有深度测试的情况下做到这一点,你只会在一半的时间内获得所需的效果:如果远处的物体是在较近的物体之前绘制的,没有问题,与现实生活相同;但如果在距离物体之前画出更近的物体,哦 – 哦,远处的物体应该是可见的.有问题的.

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

这就解释了为什么有时会在演示中看到黑色四边形.首先绘制这些四边形时,将它们的深度值写入深度缓冲区.然后,当绘制更远的四边形时,它们的深度值大于缓冲区中的深度,因此丢弃那些像素.在其他视角中,恰好会先绘制远距离四边形,然后绘制更接近的四边形,因此不会因深度测试而丢弃像素.

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

一起关闭深度测试将比仅深度编写更快.但是,有时您只想阻止新像素写入深度缓冲区,但仍然启用了深度测试.例如,在您的演示中,如果您要在中心绘制一个完全不透明的立方体;你仍然希望像素的深度远远超过隐藏不透明立方体的像素(深度测试方面),但也希望防止透明圆圈中的像素相互阻挡(写入方面).您看到的常见绘图配置是通过深度测试绘制所有不透明对象,转动深度注释,然后按照从前到后的顺序绘制透明对象.

标签:javascript,webgl,three-js
来源: https://codeday.me/bug/20191004/1853298.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有