I'm using a custom shader material in my application. It's an extended (and renamed) copy of THREE.ShaderLib['phong']
, and it works great, except for transparency, which is hit-or-miss. Sometimes objects behind a transparent object are visible, but often get culled. To ensure I didn't break something, I created the fiddle below.
When the scene initializes, everything looks as it should--three transparent planes, all transparency working correctly. Even moving the scene around appears to work correctly at first glance. But suddenly you might notice some popping. Slowing down the rotation shows that at certain angles the planes simply cease being transparent with respect to each other. (I've added a convenient "BREAK IT" button to move the camera into one such position.)
So what's going on? Am I still/actually breaking something? I've tried initializing the materials individually, but the clone seems to do the job of cloning the materials as well. Or is this just a gotcha in how this material works, and I have to find another way to approach it?
Fiddle: 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();