ShaderMaterial透明度

时间:2014-12-17 21:37:22

标签: three.js

我在我的应用程序中使用自定义着色器材质。它是THREE.ShaderLib['phong']的扩展(并重命名)副本,除了透明度之外,它的效果很好。有时透明对象后面的对象是可见的,但通常会被剔除。为了确保我没有破坏某些东西,我创造了下面的小提琴。

当场景初始化时,一切看起来都应该是 - 三个透明平面,所有透明度都正常工作。即使移动场景,乍一看似乎也能正常工作。但突然间你可能会注意到一些爆裂声。减慢旋转表明,在某些角度,平面相对于彼此简单地停止透明。 (我已经添加了一个方便的" BREAK IT"按钮,将相机移动到一个这样的位置。)

那是怎么回事?我还在/实际上是在破坏什么吗?我已尝试单独初始化材料,但克隆似乎也在克隆材料。或者这只是这个材料如何运作的问题,我必须找到另一种方法来处理它?<​​/ p>

小提琴: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 个答案:

答案 0 :(得分:2)

您看到的透明度工件与您的特定着色器无关。 MeshBasicMaterial会出现同样的问题。

三个.js中透明对象的Alpha混合是依赖于顺序的

three.js根据物体与相机的距离对物体进行分类,并按照从最远到最近的顺序渲染透明物体。请参阅this related answer

因此,您可能会在移动相机时看到瑕疵,并且排序顺序会发生变化。

有一些特定于用例的解决方法可能会有所帮助,例如通过设置renderer.sortObjects = false或更改材料属性来控制渲染顺序。你必须尝试看看哪些对你有用。

three.js r.69