Skip to content

Commit d39dabb

Browse files
authored
Merge pull request mrdoob#17114 from WestLangley/dev_pbr_transparency
MeshPhysicalMaterial: added transparency
2 parents b7ca8be + f05816d commit d39dabb

File tree

5 files changed

+179
-86
lines changed

5 files changed

+179
-86
lines changed

examples/webgl_materials_transparency.html

Lines changed: 160 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<body>
1010

1111
<div id="container"></div>
12-
<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>
12+
<div id="info"><a href="http://threejs.org" target="_blank" rel="noopener">threejs</a> - Transparency with Premultiplied Alpha (right) and without (left)</div>
1313

1414
<script type="module">
1515

@@ -19,120 +19,195 @@
1919

2020
import { GUI } from './jsm/libs/dat.gui.module.js';
2121
import { OrbitControls } from './jsm/controls/OrbitControls.js';
22-
23-
var params = { opacity: 0.25 };
22+
import { HDRCubeTextureLoader } from './jsm/loaders/HDRCubeTextureLoader.js';
23+
import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js';
24+
import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js';
25+
26+
var params = {
27+
color: 0xffffff,
28+
transparency: 0.90,
29+
envMapIntensity: 1,
30+
lightIntensity: 1,
31+
exposure: 1
32+
};
2433

2534
var container, stats;
2635
var camera, scene, renderer;
2736

28-
init();
29-
animate();
37+
var hdrCubeRenderTarget;
38+
var spotLight1, spotLight2;
39+
var mesh1, mesh2;
40+
41+
var hdrUrls = [ 'px.hdr', 'nx.hdr', 'py.hdr', 'ny.hdr', 'pz.hdr', 'nz.hdr' ];
42+
43+
var hdrCubeMap = new HDRCubeTextureLoader()
44+
.setPath( './textures/cube/pisaHDR/' )
45+
.setDataType( THREE.UnsignedByteType )
46+
.load( hdrUrls, function () {
47+
48+
init();
49+
animate();
50+
51+
} );
3052

3153
function init() {
3254

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

36-
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 2000 );
37-
camera.position.set( 0.0, 40, 40 * 3.5 );
58+
renderer = new THREE.WebGLRenderer( { antialias: true } );
59+
renderer.setPixelRatio( window.devicePixelRatio );
60+
renderer.setSize( window.innerWidth, window.innerHeight );
61+
renderer.shadowMap.enabled = true;
62+
container.appendChild( renderer.domElement );
63+
64+
renderer.toneMapping = THREE.ACESFilmicToneMapping;
65+
renderer.toneMappingExposure = params.exposure;
66+
67+
renderer.gammaOutput = true;
3868

3969
scene = new THREE.Scene();
70+
scene.background = hdrCubeMap;
71+
72+
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 2000 );
73+
camera.position.set( 0, 0, 120 );
4074

4175
//
4276

43-
var geometry = new THREE.SphereBufferGeometry( 18, 30, 30 );
77+
var pmremGenerator = new PMREMGenerator( hdrCubeMap );
78+
pmremGenerator.update( renderer );
4479

45-
var material1 = new THREE.MeshStandardMaterial( {
46-
opacity: params.opacity,
47-
transparent: true
48-
} );
80+
var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods );
81+
pmremCubeUVPacker.update( renderer );
4982

50-
var material2 = new THREE.MeshStandardMaterial( {
51-
opacity: params.opacity,
52-
premultipliedAlpha: true,
53-
transparent: true
54-
} );
83+
hdrCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget;
5584

56-
var textureLoader = new THREE.TextureLoader();
57-
textureLoader.load( "textures/hardwood2_diffuse.jpg", function ( map ) {
85+
hdrCubeMap.magFilter = THREE.LinearFilter;
86+
hdrCubeMap.needsUpdate = true;
5887

59-
map.anisotropy = 8;
88+
pmremGenerator.dispose();
89+
pmremCubeUVPacker.dispose();
6090

61-
material1.map = map;
62-
material1.needsUpdate = true;
63-
material2.map = map;
64-
material2.needsUpdate = true;
91+
//
6592

93+
var geometry = new THREE.SphereBufferGeometry( 20, 64, 32 );
94+
95+
var texture = new THREE.CanvasTexture( generateTexture() );
96+
texture.magFilter = THREE.NearestFilter;
97+
texture.wrapT = THREE.RepeatWrapping;
98+
texture.wrapS = THREE.RepeatWrapping;
99+
texture.repeat.set( 1, 3.5 );
100+
101+
var material = new THREE.MeshPhysicalMaterial( {
102+
color: params.color,
103+
metalness: 0,
104+
roughness: 0,
105+
alphaMap: texture,
106+
alphaTest: 0.5,
107+
envMap: hdrCubeRenderTarget.texture,
108+
envMapIntensity: params.envMapIntensity,
109+
depthTest: false,
110+
transparency: params.transparency,
111+
transparent: true
66112
} );
67113

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

71-
map.anisotropy = 8;
116+
var material1b = new THREE.MeshPhysicalMaterial().copy( material );
117+
material1b.side = THREE.BackSide;
72118

73-
material1.roughnessMap = map;
74-
material1.needsUpdate = true;
75-
material2.roughnessMap = map;
76-
material2.needsUpdate = true;
119+
var material2 = new THREE.MeshPhysicalMaterial().copy( material );
120+
material2.premultipliedAlpha = true;
77121

78-
} );
122+
var material2b = new THREE.MeshPhysicalMaterial().copy( material );
123+
material2b.premultipliedAlpha = true;
124+
material2b.side = THREE.BackSide;
79125

80-
var mesh = new THREE.Mesh( geometry, material1 );
81-
mesh.position.x = - 25.0;
82-
scene.add( mesh );
126+
mesh1 = new THREE.Mesh( geometry, material1 );
127+
mesh1.position.x = - 30.0;
128+
scene.add( mesh1 );
83129

84-
var mesh = new THREE.Mesh( geometry, material2 );
85-
mesh.position.x = 25.0;
86-
scene.add( mesh );
130+
var mesh = new THREE.Mesh( geometry, material1b );
131+
mesh.renderOrder = - 1;
132+
mesh1.add( mesh );
87133

88-
//
134+
mesh2 = new THREE.Mesh( geometry, material2 );
135+
mesh2.position.x = 30.0;
136+
scene.add( mesh2 );
89137

90-
var geometry = new THREE.PlaneBufferGeometry( 800, 800 );
91-
var material = new THREE.MeshStandardMaterial( { color: 0x333333 } );
92-
var mesh = new THREE.Mesh( geometry, material );
93-
mesh.position.y = - 50;
94-
mesh.rotation.x = - Math.PI * 0.5;
95-
scene.add( mesh );
138+
var mesh = new THREE.Mesh( geometry, material2b );
139+
mesh.renderOrder = - 1;
140+
mesh2.add( mesh );
96141

97-
// Lights
142+
//
98143

99-
var spotLight = new THREE.SpotLight( 0xff8888 );
100-
spotLight.position.set( 100, 200, 100 );
101-
spotLight.angle = Math.PI / 6;
102-
spotLight.penumbra = 0.9;
103-
scene.add( spotLight );
144+
spotLight1 = new THREE.SpotLight( 0xffffff, params.lightIntensity );
145+
spotLight1.position.set( 100, 200, 100 );
146+
spotLight1.angle = Math.PI / 6;
147+
scene.add( spotLight1 );
104148

105-
var spotLight = new THREE.SpotLight( 0x8888ff );
106-
spotLight.position.set( - 100, - 200, - 100 );
107-
spotLight.angle = Math.PI / 6;
108-
spotLight.penumbra = 0.9;
109-
scene.add( spotLight );
149+
spotLight2 = new THREE.SpotLight( 0xffffff, params.lightIntensity );
150+
spotLight2.position.set( - 100, - 200, - 100 );
151+
spotLight2.angle = Math.PI / 6;
152+
scene.add( spotLight2 );
110153

111154
//
112155

113-
renderer = new THREE.WebGLRenderer( { antialias: true } );
114-
renderer.setPixelRatio( window.devicePixelRatio );
115-
renderer.setSize( window.innerWidth, window.innerHeight );
116-
renderer.shadowMap.enabled = true;
117-
container.appendChild( renderer.domElement );
118-
119-
renderer.gammaInput = true;
120-
renderer.gammaOutput = true;
121-
122156
stats = new Stats();
123157
container.appendChild( stats.dom );
124158

125159
var controls = new OrbitControls( camera, renderer.domElement );
160+
controls.minDistance = 10;
161+
controls.maxDistance = 150;
126162

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

165+
//
166+
129167
var gui = new GUI();
130-
gui.add( params, 'opacity', 0, 1 ).onChange( function () {
131168

132-
material1.opacity = params.opacity;
133-
material2.opacity = params.opacity;
169+
gui.addColor( params, 'color' )
170+
.onChange( function () {
171+
172+
material1.color.set( params.color );
173+
material2.color.set( params.color );
174+
material1b.color.set( params.color );
175+
material2b.color.set( params.color );
176+
177+
} );
178+
179+
gui.add( params, 'transparency', 0, 1 )
180+
.onChange( function () {
181+
182+
material1.transparency = material2.transparency = params.transparency;
183+
material1b.transparency = material2b.transparency = params.transparency;
184+
185+
} );
186+
187+
gui.add( params, 'envMapIntensity', 0, 1 )
188+
.name( 'envMap intensity' )
189+
.onChange( function () {
190+
191+
material1.envMapIntensity = material2.envMapIntensity = params.envMapIntensity;
192+
material1b.envMapIntensity = material2b.envMapIntensity = params.envMapIntensity;
193+
194+
} );
195+
196+
gui.add( params, 'lightIntensity', 0, 1 )
197+
.name( 'light intensity' )
198+
.onChange( function () {
199+
200+
spotLight1.intensity = spotLight2.intensity = params.lightIntensity;
201+
202+
} );
203+
204+
gui.add( params, 'exposure', 0, 1 )
205+
.onChange( function () {
206+
207+
renderer.toneMappingExposure = params.exposure;
208+
209+
} );
134210

135-
} );
136211
gui.open();
137212

138213
}
@@ -151,32 +226,32 @@
151226

152227
//
153228

154-
function animate() {
229+
function generateTexture() {
155230

156-
requestAnimationFrame( animate );
231+
var canvas = document.createElement( 'canvas' );
232+
canvas.width = 2;
233+
canvas.height = 2;
157234

158-
stats.begin();
159-
render();
160-
stats.end();
235+
var context = canvas.getContext( '2d' );
236+
context.fillStyle = 'white';
237+
context.fillRect( 0, 1, 2, 1 );
161238

162-
}
239+
return canvas;
163240

164-
function render() {
165-
166-
for ( var i = 0, l = scene.children.length; i < l; i ++ ) {
167-
168-
var object = scene.children[ i ];
241+
}
169242

170-
if ( object.geometry instanceof THREE.SphereBufferGeometry ) {
243+
function animate() {
171244

172-
object.rotation.x = performance.now() * 0.0002;
173-
object.rotation.y = - performance.now() * 0.0002;
245+
requestAnimationFrame( animate );
174246

175-
}
247+
var t = performance.now();
176248

177-
}
249+
mesh1.rotation.x = mesh2.rotation.x = t * 0.0002;
250+
mesh1.rotation.z = mesh2.rotation.z = - t * 0.0002;
178251

252+
stats.begin();
179253
renderer.render( scene, camera );
254+
stats.end();
180255

181256
}
182257

src/materials/MeshPhysicalMaterial.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ function MeshPhysicalMaterial( parameters ) {
4040
this.clearcoatNormalScale = new Vector2( 1, 1 );
4141
this.clearcoatNormalMap = null;
4242

43+
this.transparency = 0.0;
44+
4345
this.setValues( parameters );
4446

4547
}
@@ -71,9 +73,10 @@ MeshPhysicalMaterial.prototype.copy = function ( source ) {
7173
this.clearcoatNormalMap = source.clearcoatNormalMap;
7274
this.clearcoatNormalScale.copy( source.clearcoatNormalScale );
7375

76+
this.transparency = source.transparency;
77+
7478
return this;
7579

7680
};
7781

78-
7982
export { MeshPhysicalMaterial };

src/renderers/WebGLRenderer.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2286,6 +2286,8 @@ function WebGLRenderer( parameters ) {
22862286

22872287
}
22882288

2289+
uniforms.transparency.value = material.transparency;
2290+
22892291
}
22902292

22912293
function refreshUniformsMatcap( uniforms, material ) {

src/renderers/shaders/ShaderLib.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ ShaderLib.physical = {
273273
uniforms: mergeUniforms( [
274274
ShaderLib.standard.uniforms,
275275
{
276+
transparency: { value: 0 },
276277
clearcoat: { value: 0 },
277278
clearcoatRoughness: { value: 0 },
278279
sheen: { value: new Color( 0x000000 ) },

src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export default /* glsl */`
44
#ifdef PHYSICAL
55
#define REFLECTIVITY
66
#define CLEARCOAT
7+
#define TRANSPARENCY
78
#endif
89
910
uniform vec3 diffuse;
@@ -12,13 +13,19 @@ uniform float roughness;
1213
uniform float metalness;
1314
uniform float opacity;
1415
16+
#ifdef TRANSPARENCY
17+
uniform float transparency;
18+
#endif
19+
1520
#ifdef REFLECTIVITY
1621
uniform float reflectivity;
1722
#endif
23+
1824
#ifdef CLEARCOAT
1925
uniform float clearcoat;
2026
uniform float clearcoatRoughness;
2127
#endif
28+
2229
#ifdef USE_SHEEN
2330
uniform vec3 sheen;
2431
#endif
@@ -97,6 +104,11 @@ void main() {
97104
98105
vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;
99106
107+
// this is a stub for the transparency model
108+
#ifdef TRANSPARENCY
109+
diffuseColor.a *= saturate( 1. - transparency + linearToRelativeLuminance( reflectedLight.directSpecular + reflectedLight.indirectSpecular ) );
110+
#endif
111+
100112
gl_FragColor = vec4( outgoingLight, diffuseColor.a );
101113
102114
#include <tonemapping_fragment>

0 commit comments

Comments
 (0)