Skip to content

Commit 7a5f069

Browse files
authored
Merge pull request #281 from gkjohnson/thin-film
Thin film
2 parents f3cbfa9 + 952cf76 commit 7a5f069

File tree

7 files changed

+35
-7
lines changed

7 files changed

+35
-7
lines changed

example/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,8 @@ async function updateModel() {
624624

625625
if ( c.material ) {
626626

627+
// set the thickness so we render the material as a volumetric object
628+
c.material.thickness = 1.0;
627629
c.material.side = DoubleSide;
628630

629631
}

example/interior.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,17 @@ async function init() {
116116
.loadAsync( 'https://raw.githubusercontent.com/gkjohnson/3d-demo-data/main/models/pathtracing-bathroom/modernbathroom.glb' )
117117
.then( gltf => {
118118

119+
gltf.scene.traverse( c => {
120+
121+
if ( c.material ) {
122+
123+
// set the thickness so volume rendering is used for transmissive objects.
124+
c.material.thickness = 1.0;
125+
126+
}
127+
128+
} );
129+
119130
const group = new THREE.Group();
120131
group.add( gltf.scene );
121132

example/materialBall.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const params = {
2525
metalness: 0.8,
2626
ior: 1.495,
2727
transmission: 0.0,
28+
thinFilm: false,
2829
attenuationColor: '#ffffff',
2930
attenuationDistance: 0.5,
3031
opacity: 1.0,
@@ -47,6 +48,7 @@ const params = {
4748
roughness: 0.9,
4849
metalness: 0.1,
4950
transmission: 0.0,
51+
thinFilm: false,
5052
attenuationColor: '#ffffff',
5153
attenuationDistance: 0.5,
5254
ior: 1.495,
@@ -433,6 +435,7 @@ async function init() {
433435
matFolder1.add( params.material1, 'metalness', 0, 1 ).onChange( reset );
434436
matFolder1.add( params.material1, 'opacity', 0, 1 ).onChange( reset );
435437
matFolder1.add( params.material1, 'transmission', 0, 1 ).onChange( reset );
438+
matFolder1.add( params.material1, 'thinFilm', 0, 1 ).onChange( reset );
436439
matFolder1.add( params.material1, 'attenuationDistance', 0.05, 2.0 ).onChange( reset );
437440
matFolder1.addColor( params.material1, 'attenuationColor' ).onChange( reset );
438441
matFolder1.add( params.material1, 'ior', 0.9, 3.0 ).onChange( reset );
@@ -457,6 +460,7 @@ async function init() {
457460
matFolder2.add( params.material2, 'metalness', 0, 1 ).onChange( reset );
458461
matFolder2.add( params.material2, 'opacity', 0, 1 ).onChange( reset );
459462
matFolder2.add( params.material2, 'transmission', 0, 1 ).onChange( reset );
463+
matFolder1.add( params.material2, 'thinFilm', 0, 1 ).onChange( reset );
460464
matFolder2.add( params.material2, 'attenuationDistance', 0.05, 2.0 ).onChange( reset );
461465
matFolder2.addColor( params.material2, 'attenuationColor' ).onChange( reset );
462466
matFolder2.add( params.material2, 'ior', 0.9, 3.0 ).onChange( reset );
@@ -578,7 +582,7 @@ function animate() {
578582
m1.metalness = params.material1.metalness;
579583
m1.roughness = params.material1.roughness;
580584
m1.transmission = params.material1.transmission;
581-
m1.attenuationDistance = params.material1.attenuationDistance;
585+
m1.attenuationDistance = params.material1.thinFilm ? Infinity : params.material1.attenuationDistance;
582586
m1.attenuationColor.set( params.material1.attenuationColor );
583587
m1.ior = params.material1.ior;
584588
m1.opacity = params.material1.opacity;
@@ -600,7 +604,7 @@ function animate() {
600604
m2.metalness = params.material2.metalness;
601605
m2.roughness = params.material2.roughness;
602606
m2.transmission = params.material2.transmission;
603-
m2.attenuationDistance = params.material2.attenuationDistance;
607+
m2.attenuationDistance = params.material2.thinFilm ? Infinity : params.material2.attenuationDistance;
604608
m2.attenuationColor.set( params.material2.attenuationColor );
605609
m2.ior = params.material2.ior;
606610
m2.opacity = params.material2.opacity;

src/materials/PhysicalPathTracingMaterial.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -571,10 +571,9 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
571571
// and we're rendering the other then we skip it. Do the opposite on subsequent bounces to get incoming light.
572572
float alphaTest = material.alphaTest;
573573
bool useAlphaTest = alphaTest != 0.0;
574-
bool isFirstHit = i == 0;
575574
if (
576575
// material sidedness
577-
material.side != 0.0 && ( side != material.side ) == isFirstHit
576+
material.side != 0.0 && side != material.side
578577
579578
// alpha test
580579
|| useAlphaTest && albedo.a < alphaTest
@@ -799,7 +798,8 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
799798
// frontFace is used to determine transmissive properties and PDF. If no transmission is used
800799
// then we can just always assume this is a front face.
801800
surfaceRec.frontFace = side == 1.0 || transmission == 0.0;
802-
surfaceRec.iorRatio = surfaceRec.frontFace ? 1.0 / material.ior : material.ior;
801+
surfaceRec.iorRatio = material.thinFilm || surfaceRec.frontFace ? 1.0 / material.ior : material.ior;
802+
surfaceRec.thinFilm = material.thinFilm;
803803
804804
// Compute the filtered roughness value to use during specular reflection computations.
805805
// The accumulated roughness value is scaled by a user setting and a "magic value" of 5.0.

src/shader/shaderMaterialSampling.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ struct SurfaceRec {
1414
vec3 color;
1515
vec3 emission;
1616
float transmission;
17+
bool thinFilm;
1718
float ior;
1819
float iorRatio;
1920
float clearcoat;
@@ -220,14 +221,20 @@ vec3 transmissionDirection( vec3 wo, SurfaceRec surf ) {
220221
vec3 halfVector = normalize( vec3( 0.0, 0.0, 1.0 ) + randDirection() * roughness );
221222
vec3 lightDirection = refract( normalize( - wo ), halfVector, iorRatio );
222223
224+
if ( surf.thinFilm ) {
225+
226+
lightDirection = - refract( normalize( - lightDirection ), - vec3( 0.0, 0.0, 1.0 ), 1.0 / iorRatio );
227+
228+
}
223229
return normalize( lightDirection );
224230
225231
}
226232
227233
vec3 transmissionColor( vec3 wo, vec3 wi, SurfaceRec surf ) {
228234
229235
// only attenuate the color if it's on the way in
230-
return surf.frontFace ? surf.color : vec3( 1.0 );
236+
vec3 col = surf.thinFilm || surf.frontFace ? surf.color : vec3( 1.0 );
237+
return surf.transmission * col;
231238
232239
}
233240

src/shader/shaderStructs.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export const shaderMaterialStructs = /* glsl */ `
6262
6363
float specularIntensity;
6464
int specularIntensityMap;
65+
bool thinFilm;
6566
6667
vec3 attenuationColor;
6768
float attenuationDistance;
@@ -180,6 +181,7 @@ export const shaderMaterialStructs = /* glsl */ `
180181
181182
m.specularIntensity = s11.r;
182183
m.specularIntensityMap = int( round( s11.g ) );
184+
m.thinFilm = bool( s11.b );
183185
184186
m.attenuationColor = s12.rgb;
185187
m.attenuationDistance = s12.a;

src/uniforms/MaterialsTexture.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,9 @@ export class MaterialsTexture extends DataTexture {
335335
// specular intensity
336336
floatArray[ index ++ ] = getField( m, 'specularIntensity', 1.0 );
337337
floatArray[ index ++ ] = getTexture( m, 'specularIntensityMap' );
338-
index ++;
338+
339+
// thickness
340+
floatArray[ index ++ ] = getField( m, 'thickness', 0.0 ) === 0.0 && getField( m, 'attenuationDistance', Infinity ) === Infinity;
339341
index ++;
340342

341343
// sample 12

0 commit comments

Comments
 (0)