Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rendering a transparent shell

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();
like image 739
TheJim01 Avatar asked Apr 29 '16 21:04

TheJim01


1 Answers

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

like image 198
WestLangley Avatar answered Nov 08 '22 20:11

WestLangley