Let's say I'm rendering Wonder Woman piloting her Invisible Jet. The jet is made up of multiple meshes, and is mostly transparent. Where the transparent meshes overlap, it becomes more opaque. I'd like to not have that overlap, such that the transparent parts are still shaded, but the material discards transparent fragments that are behind other fragments, as if Wonder Woman is sitting inside a transparent shell.
Perhaps a good way to putting it is that I want to render transparent meshes like opaque meshes, but still allow them to be transparent.
As an example, here is Average Woman driving her Mostly-Visible Car: http://jsfiddle.net/TheJim01/e6ccfo24/
I've done different permutations of depth testing and writing, and tried all the various depth test functions. I've also tried different blending settings (I saw several suggestions for THREE.NoBlending
, but that's not what I want because I lose transparency). If I have to write a custom shader for this, I'll go that route, but I'm not sure where to start.
HTML:
<script>
// INITIALIZE
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight,
FOV = 35,
NEAR = 1,
FAR = 1000;
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(WIDTH, HEIGHT);
document.getElementById('host').appendChild(renderer.domElement);
var stats= new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0';
document.body.appendChild(stats.domElement);
var camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, NEAR, FAR);
camera.position.z = 250;
var trackballControl = new THREE.TrackballControls(camera, renderer.domElement);
trackballControl.rotateSpeed = 5.0; // need to speed it up a little
var scene = new THREE.Scene();
var light = new THREE.PointLight(0xffffff, 1, Infinity);
light.position.copy(camera.position);
scene.add(light);
function draw(){
light.position.copy(camera.position);
renderer.render(scene, camera);
stats.update();
}
trackballControl.addEventListener('change', draw);
function navStartHandler(e) {
renderer.domElement.addEventListener('mousemove', navMoveHandler);
renderer.domElement.addEventListener('mouseup', navEndHandler);
}
function navMoveHandler(e) {
trackballControl.update();
}
function navEndHandler(e) {
renderer.domElement.removeEventListener('mousemove', navMoveHandler);
renderer.domElement.removeEventListener('mouseup', navEndHandler);
}
renderer.domElement.addEventListener('mousedown', navStartHandler);
renderer.domElement.addEventListener('mousewheel', navMoveHandler);
</script>
CSS:
html *{
padding: 0;
margin: 0;
width: 100%;
overflow: hidden;
}
#host {
width: 100%;
height: 100%;
}
JavaScript:
// NOTE: To run this demo, you MUST use the HTTP protocol, not HTTPS!
var msh = new THREE.Mesh(new THREE.SphereGeometry(10, 20, 20), new THREE.MeshLambertMaterial({color: "red"}));
msh.position.set(0, 10, 0);
scene.add(msh);
var mat = new THREE.MeshLambertMaterial({
color: "silver",
transparent: true,
opacity: 0.5
});
msh = new THREE.Mesh(new THREE.CylinderGeometry(15, 15, 75, 20), mat);
msh.rotation.set(0, 0, Math.PI / 2);
msh.position.set(0,10,0);
scene.add(msh);
msh = new THREE.Mesh(new THREE.CylinderGeometry(15, 15, 50, 20), mat);
msh.rotation.set(Math.PI / 2, 0, 0);
msh.position.set(-20,-10,0);
scene.add(msh);
msh = new THREE.Mesh(new THREE.CylinderGeometry(15, 15, 50, 20), mat);
msh.rotation.set(Math.PI / 2, 0, 0);
msh.position.set(20,-10,0);
scene.add(msh);
draw();
If you want to render overlapping transparent faces, but do not want the overlapping regions to be darker, you can implement a trick: render the faces first with
material.colorWrite = false;
and then render them a second time with
material.colorWrite = true;
You can use the Object3D.renderOrder
property to ensure rendering the faces with colorWrite = false
occurs prior to rendering with colorWrite = true
.
three.js r.144
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With