Skip to content

Commit

Permalink
Merge pull request #17114 from WestLangley/dev_pbr_transparency
Browse files Browse the repository at this point in the history
MeshPhysicalMaterial: added transparency
  • Loading branch information
mrdoob authored Aug 23, 2019
2 parents b7ca8be + f05816d commit d39dabb
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 86 deletions.
245 changes: 160 additions & 85 deletions examples/webgl_materials_transparency.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<body>

<div id="container"></div>
<div id="info"><a href="http://threejs.org" target="_blank" rel="noopener">threejs</a> - Transparency with Premultiplied Alpha (right) and without (left)<br /> using RGBA8 Buffers by <a href="http://clara.io/" target="_blank" rel="noopener">Ben Houston</a>.</div>
<div id="info"><a href="http://threejs.org" target="_blank" rel="noopener">threejs</a> - Transparency with Premultiplied Alpha (right) and without (left)</div>

<script type="module">

Expand All @@ -19,120 +19,195 @@

import { GUI } from './jsm/libs/dat.gui.module.js';
import { OrbitControls } from './jsm/controls/OrbitControls.js';

var params = { opacity: 0.25 };
import { HDRCubeTextureLoader } from './jsm/loaders/HDRCubeTextureLoader.js';
import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js';
import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js';

var params = {
color: 0xffffff,
transparency: 0.90,
envMapIntensity: 1,
lightIntensity: 1,
exposure: 1
};

var container, stats;
var camera, scene, renderer;

init();
animate();
var hdrCubeRenderTarget;
var spotLight1, spotLight2;
var mesh1, mesh2;

var hdrUrls = [ 'px.hdr', 'nx.hdr', 'py.hdr', 'ny.hdr', 'pz.hdr', 'nz.hdr' ];

var hdrCubeMap = new HDRCubeTextureLoader()
.setPath( './textures/cube/pisaHDR/' )
.setDataType( THREE.UnsignedByteType )
.load( hdrUrls, function () {

init();
animate();

} );

function init() {

container = document.createElement( 'div' );
document.body.appendChild( container );

camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 2000 );
camera.position.set( 0.0, 40, 40 * 3.5 );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.shadowMap.enabled = true;
container.appendChild( renderer.domElement );

renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = params.exposure;

renderer.gammaOutput = true;

scene = new THREE.Scene();
scene.background = hdrCubeMap;

camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 2000 );
camera.position.set( 0, 0, 120 );

//

var geometry = new THREE.SphereBufferGeometry( 18, 30, 30 );
var pmremGenerator = new PMREMGenerator( hdrCubeMap );
pmremGenerator.update( renderer );

var material1 = new THREE.MeshStandardMaterial( {
opacity: params.opacity,
transparent: true
} );
var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods );
pmremCubeUVPacker.update( renderer );

var material2 = new THREE.MeshStandardMaterial( {
opacity: params.opacity,
premultipliedAlpha: true,
transparent: true
} );
hdrCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget;

var textureLoader = new THREE.TextureLoader();
textureLoader.load( "textures/hardwood2_diffuse.jpg", function ( map ) {
hdrCubeMap.magFilter = THREE.LinearFilter;
hdrCubeMap.needsUpdate = true;

map.anisotropy = 8;
pmremGenerator.dispose();
pmremCubeUVPacker.dispose();

material1.map = map;
material1.needsUpdate = true;
material2.map = map;
material2.needsUpdate = true;
//

var geometry = new THREE.SphereBufferGeometry( 20, 64, 32 );

var texture = new THREE.CanvasTexture( generateTexture() );
texture.magFilter = THREE.NearestFilter;
texture.wrapT = THREE.RepeatWrapping;
texture.wrapS = THREE.RepeatWrapping;
texture.repeat.set( 1, 3.5 );

var material = new THREE.MeshPhysicalMaterial( {
color: params.color,
metalness: 0,
roughness: 0,
alphaMap: texture,
alphaTest: 0.5,
envMap: hdrCubeRenderTarget.texture,
envMapIntensity: params.envMapIntensity,
depthTest: false,
transparency: params.transparency,
transparent: true
} );

var textureLoader = new THREE.TextureLoader();
textureLoader.load( "textures/hardwood2_roughness.jpg", function ( map ) {
var material1 = new THREE.MeshPhysicalMaterial().copy( material );

map.anisotropy = 8;
var material1b = new THREE.MeshPhysicalMaterial().copy( material );
material1b.side = THREE.BackSide;

material1.roughnessMap = map;
material1.needsUpdate = true;
material2.roughnessMap = map;
material2.needsUpdate = true;
var material2 = new THREE.MeshPhysicalMaterial().copy( material );
material2.premultipliedAlpha = true;

} );
var material2b = new THREE.MeshPhysicalMaterial().copy( material );
material2b.premultipliedAlpha = true;
material2b.side = THREE.BackSide;

var mesh = new THREE.Mesh( geometry, material1 );
mesh.position.x = - 25.0;
scene.add( mesh );
mesh1 = new THREE.Mesh( geometry, material1 );
mesh1.position.x = - 30.0;
scene.add( mesh1 );

var mesh = new THREE.Mesh( geometry, material2 );
mesh.position.x = 25.0;
scene.add( mesh );
var mesh = new THREE.Mesh( geometry, material1b );
mesh.renderOrder = - 1;
mesh1.add( mesh );

//
mesh2 = new THREE.Mesh( geometry, material2 );
mesh2.position.x = 30.0;
scene.add( mesh2 );

var geometry = new THREE.PlaneBufferGeometry( 800, 800 );
var material = new THREE.MeshStandardMaterial( { color: 0x333333 } );
var mesh = new THREE.Mesh( geometry, material );
mesh.position.y = - 50;
mesh.rotation.x = - Math.PI * 0.5;
scene.add( mesh );
var mesh = new THREE.Mesh( geometry, material2b );
mesh.renderOrder = - 1;
mesh2.add( mesh );

// Lights
//

var spotLight = new THREE.SpotLight( 0xff8888 );
spotLight.position.set( 100, 200, 100 );
spotLight.angle = Math.PI / 6;
spotLight.penumbra = 0.9;
scene.add( spotLight );
spotLight1 = new THREE.SpotLight( 0xffffff, params.lightIntensity );
spotLight1.position.set( 100, 200, 100 );
spotLight1.angle = Math.PI / 6;
scene.add( spotLight1 );

var spotLight = new THREE.SpotLight( 0x8888ff );
spotLight.position.set( - 100, - 200, - 100 );
spotLight.angle = Math.PI / 6;
spotLight.penumbra = 0.9;
scene.add( spotLight );
spotLight2 = new THREE.SpotLight( 0xffffff, params.lightIntensity );
spotLight2.position.set( - 100, - 200, - 100 );
spotLight2.angle = Math.PI / 6;
scene.add( spotLight2 );

//

renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.shadowMap.enabled = true;
container.appendChild( renderer.domElement );

renderer.gammaInput = true;
renderer.gammaOutput = true;

stats = new Stats();
container.appendChild( stats.dom );

var controls = new OrbitControls( camera, renderer.domElement );
controls.minDistance = 10;
controls.maxDistance = 150;

window.addEventListener( 'resize', onWindowResize, false );

//

var gui = new GUI();
gui.add( params, 'opacity', 0, 1 ).onChange( function () {

material1.opacity = params.opacity;
material2.opacity = params.opacity;
gui.addColor( params, 'color' )
.onChange( function () {

material1.color.set( params.color );
material2.color.set( params.color );
material1b.color.set( params.color );
material2b.color.set( params.color );

} );

gui.add( params, 'transparency', 0, 1 )
.onChange( function () {

material1.transparency = material2.transparency = params.transparency;
material1b.transparency = material2b.transparency = params.transparency;

} );

gui.add( params, 'envMapIntensity', 0, 1 )
.name( 'envMap intensity' )
.onChange( function () {

material1.envMapIntensity = material2.envMapIntensity = params.envMapIntensity;
material1b.envMapIntensity = material2b.envMapIntensity = params.envMapIntensity;

} );

gui.add( params, 'lightIntensity', 0, 1 )
.name( 'light intensity' )
.onChange( function () {

spotLight1.intensity = spotLight2.intensity = params.lightIntensity;

} );

gui.add( params, 'exposure', 0, 1 )
.onChange( function () {

renderer.toneMappingExposure = params.exposure;

} );

} );
gui.open();

}
Expand All @@ -151,32 +226,32 @@

//

function animate() {
function generateTexture() {

requestAnimationFrame( animate );
var canvas = document.createElement( 'canvas' );
canvas.width = 2;
canvas.height = 2;

stats.begin();
render();
stats.end();
var context = canvas.getContext( '2d' );
context.fillStyle = 'white';
context.fillRect( 0, 1, 2, 1 );

}
return canvas;

function render() {

for ( var i = 0, l = scene.children.length; i < l; i ++ ) {

var object = scene.children[ i ];
}

if ( object.geometry instanceof THREE.SphereBufferGeometry ) {
function animate() {

object.rotation.x = performance.now() * 0.0002;
object.rotation.y = - performance.now() * 0.0002;
requestAnimationFrame( animate );

}
var t = performance.now();

}
mesh1.rotation.x = mesh2.rotation.x = t * 0.0002;
mesh1.rotation.z = mesh2.rotation.z = - t * 0.0002;

stats.begin();
renderer.render( scene, camera );
stats.end();

}

Expand Down
5 changes: 4 additions & 1 deletion src/materials/MeshPhysicalMaterial.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ function MeshPhysicalMaterial( parameters ) {
this.clearcoatNormalScale = new Vector2( 1, 1 );
this.clearcoatNormalMap = null;

this.transparency = 0.0;

this.setValues( parameters );

}
Expand Down Expand Up @@ -71,9 +73,10 @@ MeshPhysicalMaterial.prototype.copy = function ( source ) {
this.clearcoatNormalMap = source.clearcoatNormalMap;
this.clearcoatNormalScale.copy( source.clearcoatNormalScale );

this.transparency = source.transparency;

return this;

};


export { MeshPhysicalMaterial };
2 changes: 2 additions & 0 deletions src/renderers/WebGLRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2286,6 +2286,8 @@ function WebGLRenderer( parameters ) {

}

uniforms.transparency.value = material.transparency;

}

function refreshUniformsMatcap( uniforms, material ) {
Expand Down
1 change: 1 addition & 0 deletions src/renderers/shaders/ShaderLib.js
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ ShaderLib.physical = {
uniforms: mergeUniforms( [
ShaderLib.standard.uniforms,
{
transparency: { value: 0 },
clearcoat: { value: 0 },
clearcoatRoughness: { value: 0 },
sheen: { value: new Color( 0x000000 ) },
Expand Down
12 changes: 12 additions & 0 deletions src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default /* glsl */`
#ifdef PHYSICAL
#define REFLECTIVITY
#define CLEARCOAT
#define TRANSPARENCY
#endif
uniform vec3 diffuse;
Expand All @@ -12,13 +13,19 @@ uniform float roughness;
uniform float metalness;
uniform float opacity;
#ifdef TRANSPARENCY
uniform float transparency;
#endif
#ifdef REFLECTIVITY
uniform float reflectivity;
#endif
#ifdef CLEARCOAT
uniform float clearcoat;
uniform float clearcoatRoughness;
#endif
#ifdef USE_SHEEN
uniform vec3 sheen;
#endif
Expand Down Expand Up @@ -97,6 +104,11 @@ void main() {
vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;
// this is a stub for the transparency model
#ifdef TRANSPARENCY
diffuseColor.a *= saturate( 1. - transparency + linearToRelativeLuminance( reflectedLight.directSpecular + reflectedLight.indirectSpecular ) );
#endif
gl_FragColor = vec4( outgoingLight, diffuseColor.a );
#include <tonemapping_fragment>
Expand Down

0 comments on commit d39dabb

Please sign in to comment.