着色器材质透明度
Posted
技术标签:
【中文标题】着色器材质透明度【英文标题】:ShaderMaterial transparency 【发布时间】:2015-02-16 13:44:24 【问题描述】:我在我的应用程序中使用了自定义着色器材质。它是THREE.ShaderLib['phong']
的扩展(并重命名)副本,效果很好,除了透明度,这是命中或错过。有时透明对象后面的对象是可见的,但通常会被剔除。为了确保我没有破坏某些东西,我在下面创建了小提琴。
当场景初始化时,一切看起来都正常——三个透明平面,所有透明都正常工作。乍一看,即使移动场景似乎也能正常工作。但突然间,你可能会注意到一些爆裂声。放慢旋转速度表明,在某些角度,这些平面只是不再相互透明。 (我添加了一个方便的“BREAK IT”按钮来将相机移动到一个这样的位置。)
那么发生了什么?我还在/实际上在破坏什么吗?我已经尝试单独初始化材料,但克隆似乎也可以完成克隆材料的工作。或者这只是这种材料工作原理的一个陷阱,我必须找到另一种方法来处理它?
小提琴:http://jsfiddle.net/TheJim01/rwt64fgd/
JS:
// BufferGeometry Tester
var hostDiv, scene, renderer, camera, root, controls, light;
var WIDTH = 500;//window.innerWidth,
HEIGHT = 500;//window.innerHeight,
FOV = 35,
NEAR = 1,
FAR = 1000;
function breakIt()
camera.position.set(-25.759449580212017, -17.239852126859287, 39.2331270225625);
camera.lookAt(scene.position);
camera.up.set(0.07701484672816412, 0.8931831414880415, 0.44304919494903006);
function createBufferGeometryMesh()
var geo = new THREE.BufferGeometry();
var tl = new THREE.Vector3(-10., 10., 0.),
tr = new THREE.Vector3(10., 10., 0.),
bl = new THREE.Vector3(-10., -10., 0.),
br = new THREE.Vector3(10., -10., 0.);
var n0 = new THREE.Vector3(0., 0., 1.);
var vertices =
[
tl.x, tl.y, tl.z,
tr.x, tr.y, tr.z,
br.x, br.y, br.z,
bl.x, bl.y, bl.z
],
normals =
[
n0.x, n0.y, n0.z,
n0.x, n0.y, n0.z,
n0.x, n0.y, n0.z,
n0.x, n0.y, n0.z
],
indices = [ 0, 2, 1, 0, 3, 2 ];
geo.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertices ), 3 ) );
geo.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( normals ), 3 ) );
geo.addAttribute( 'index', new THREE.BufferAttribute( new Uint32Array( indices ), 1 ) );
/*/
var mat = new THREE.MeshPhongMaterial(
color: 0xffffff,
ambient: 0xffffff,
specular: 0xffffff,
shininess: 50,
side: THREE.DoubleSide
);
/*/
var shader = THREE.ShaderLib['phong'];
var uniforms = null,
parameters = null;
uniforms = THREE.UniformsUtils.clone(shader.uniforms);
uniforms['diffuse'].value.setHex(0xcccccc);
uniforms['ambient'].value.setHex(0x0);
uniforms['emissive'].value.setHex(0x0);
uniforms['specular'].value.setHex(0xffffff);
uniforms['shininess'].value = 1;
uniforms['opacity'].value = 0.5;
uniforms['ambient'].value.convertGammaToLinear();
parameters =
fragmentShader: shader.fragmentShader,
vertexShader: shader.vertexShader,
uniforms: uniforms,
lights: true,
fog: false,
side: THREE.DoubleSide,
blending: THREE.NormalBlending,
transparent: (uniforms['opacity'].value < 1.0)
;
var mat = new THREE.ShaderMaterial(parameters);
var msh = new THREE.Mesh(geo, mat);
return msh;
function init()
hostDiv = document.createElement('div');
document.body.appendChild(hostDiv);
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer( antialias: true );
renderer.setSize(WIDTH, HEIGHT);
renderer.setClearColor( 0x888888, 1 );
hostDiv.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, NEAR, FAR);
camera.position.z = 50;
camera.lookAt(scene.position);
controls = new THREE.TrackballControls(camera, renderer.domElement);
light = new THREE.PointLight(0xffffff, 1, 1000);
light.position.copy(camera.position);
scene.add(camera);
scene.add(light);
var square = createBufferGeometryMesh();
square.material.uniforms['diffuse'].value.setHex(0xff0000);
square.material.needsUpdate = true;
square.translateY(5);
square.translateX(5);
square.translateZ(5);
scene.add(square);
square = createBufferGeometryMesh();
square.material.uniforms['diffuse'].value.setHex(0x00ff00);
square.material.needsUpdate = true;
square.translateY(-5);
square.translateX(-5);
square.translateZ(-5);
scene.add(square);
square = createBufferGeometryMesh();
square.material.uniforms['diffuse'].value.setHex(0x0000ff);
square.material.needsUpdate = true;
square.scale.set(0.5, 0.5, 0.5);
scene.add(square);
animate();
var button = document.createElement('input');
button.setAttribute('type', 'button');
button.setAttribute('value', 'BREAK IT');
button.addEventListener('click', breakIt);
document.body.appendChild(button);
function render()
renderer.render(scene, camera);
function animate()
light.position.copy(camera.position);
requestAnimationFrame(animate);
render();
controls.update();
init();
【问题讨论】:
1.恭喜你做了小实验来瘦身。这是您真正了解 webgl 和 three.js 的唯一方法。 2.当你使用透明MeshPhongMaterial
代替你的自定义材质时,你看到同样的问题吗?
1.我是一个实干型的学习者,所以它最适合我,并在我需要寻求帮助时帮助说明我的观点。 :) 2. 是的。我的小提琴版本 7 将 ShaderMaterial
替换为类似配置的 MeshPhongMaterial
。
做了更多的挖掘、尝试等。我发现***.com/questions/15994944/…(尽管基于 r57)表明透明度是基于对象位置的。对此进行了一些测试,这是真的。通过一些调整,我将相机放到了一个位置——平面以相同的方式堆叠——蓝色平面是最近的,但红色平面仍然在蓝色平面的前面。奇怪的结果。
1.因此,它不是由您的着色器引起的。简化为MeshBasicMaterial
。看看您是否可以创建一个带有无法解释的结果的简单示例。 2. 你也可以谷歌“订单无关透明度”——这不是three.js 做的,顺便说一句。
MeshBasicMaterial
也是如此。但我预料到——结果并不是那么难以解释。 Alpha 混合是基于对象位置而不是片段位置完成的。这可能会导致奇怪的情况,就像我在示例中看到的那样。但由于three.js 不支持OIT(还......github.com/mrdoob/three.js/issues/4814),我想我现在不走运。这不是一个可怕的问题,我只是希望有一个解决方法。
【参考方案1】:
您看到的透明度伪影与您的特定着色器无关。 MeshBasicMaterial
也会出现同样的问题。
three.js 中透明对象的 Alpha 混合是顺序相关的。
three.js 根据对象与相机的距离对对象进行排序,并按照从最远到最近的顺序渲染透明对象。见this related answer。
因此,您可能会在移动相机时看到伪影,并且排序顺序会发生变化。
有一些特定于用例的变通方法可能会有所帮助,例如通过设置 renderer.sortObjects = false
或更改材质属性来控制渲染顺序。您必须进行试验才能看到适合您的方法。
three.js r.69
【讨论】:
以上是关于着色器材质透明度的主要内容,如果未能解决你的问题,请参考以下文章