Skip to content

Commit 5c74583

Browse files
authored
Merge pull request #272 from gkjohnson/volume-transmission
Volume transmission
2 parents 6b569e6 + e276469 commit 5c74583

File tree

7 files changed

+118
-63
lines changed

7 files changed

+118
-63
lines changed

example/materialBall.js

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ const params = {
2525
metalness: 0.8,
2626
ior: 1.495,
2727
transmission: 0.0,
28+
attenuationColor: '#ffffff',
29+
attenuationDistance: 0.5,
2830
opacity: 1.0,
2931
clearcoat: 0.0,
3032
clearcoatRoughness: 0.0,
@@ -45,6 +47,8 @@ const params = {
4547
roughness: 0.9,
4648
metalness: 0.1,
4749
transmission: 0.0,
50+
attenuationColor: '#ffffff',
51+
attenuationDistance: 0.5,
4852
ior: 1.495,
4953
opacity: 1.0,
5054
clearcoat: 0.0,
@@ -63,17 +67,7 @@ const params = {
6367
color: '#000000',
6468
roughness: 0.1,
6569
metalness: 0.05,
66-
clearcoat: 0.0,
67-
clearcoatRoughness: 0.0,
68-
sheenColor: '#000000',
69-
sheenRoughness: 0.0,
70-
iridescence: 0.0,
71-
iridescenceIOR: 1.5,
72-
iridescenceThickness: 400,
73-
specularColor: '#ffffff',
74-
specularIntensity: 1.0,
7570
matte: false,
76-
castShadow: true,
7771
},
7872

7973
multipleImportanceSampling: true,
@@ -104,7 +98,9 @@ if ( window.location.hash.includes( 'transmission' ) ) {
10498
params.material1.roughness = 0.23;
10599
params.material1.transmission = 1.0;
106100
params.material1.color = '#ffffff';
101+
107102
params.bounces = 10;
103+
params.tiles = 2;
108104

109105
} else if ( window.location.hash.includes( 'iridescent' ) ) {
110106

@@ -113,6 +109,26 @@ if ( window.location.hash.includes( 'transmission' ) ) {
113109
params.material1.metalness = 1.0;
114110
params.material1.iridescence = 1.0;
115111

112+
} else if ( window.location.hash.includes( 'acrylic' ) ) {
113+
114+
params.material1.color = '#ffffff';
115+
params.material1.roughness = 0;
116+
params.material1.metalness = 0;
117+
params.material1.transmission = 1.0;
118+
params.material1.attenuationDistance = 0.75;
119+
params.material1.attenuationColor = '#2a6dc6';
120+
121+
params.material2.color = '#ffffff';
122+
params.material2.roughness = 0.0;
123+
params.material2.metalness = 0.975;
124+
125+
params.material3.color = '#999999';
126+
params.material3.roughness = 0.2;
127+
params.material3.metalness = 0.0;
128+
129+
params.bounces = 20;
130+
params.tiles = 3;
131+
116132
}
117133

118134
// adjust performance parameters for mobile
@@ -336,6 +352,8 @@ async function init() {
336352
denoiseFolder.add( params, 'denoiseSigma', 0.01, 12.0 );
337353
denoiseFolder.add( params, 'denoiseThreshold', 0.01, 1.0 );
338354
denoiseFolder.add( params, 'denoiseKSigma', 0.0, 12.0 );
355+
denoiseFolder.close();
356+
339357

340358
const envFolder = gui.addFolder( 'Environment' );
341359
envFolder.add( params, 'environmentIntensity', 0, 10 ).onChange( () => {
@@ -377,6 +395,7 @@ async function init() {
377395
}
378396

379397
} );
398+
envFolder.close();
380399

381400
const cameraFolder = gui.addFolder( 'Camera' );
382401
cameraFolder.add( params, 'cameraProjection', [ 'Perspective', 'Orthographic', 'Equirectangular' ] ).onChange( v => {
@@ -402,6 +421,7 @@ async function init() {
402421
reset();
403422

404423
} ).listen();
424+
cameraFolder.close();
405425

406426
const matFolder1 = gui.addFolder( 'Shell Material' );
407427
matFolder1.addColor( params.material1, 'color' ).onChange( reset );
@@ -411,6 +431,8 @@ async function init() {
411431
matFolder1.add( params.material1, 'metalness', 0, 1 ).onChange( reset );
412432
matFolder1.add( params.material1, 'opacity', 0, 1 ).onChange( reset );
413433
matFolder1.add( params.material1, 'transmission', 0, 1 ).onChange( reset );
434+
matFolder1.add( params.material1, 'attenuationDistance', 0.05, 2.0 ).onChange( reset );
435+
matFolder1.addColor( params.material1, 'attenuationColor' ).onChange( reset );
414436
matFolder1.add( params.material1, 'ior', 0.9, 3.0 ).onChange( reset );
415437
matFolder1.add( params.material1, 'clearcoat', 0, 1 ).onChange( reset );
416438
matFolder1.add( params.material1, 'clearcoatRoughness', 0, 1 ).onChange( reset );
@@ -433,6 +455,8 @@ async function init() {
433455
matFolder2.add( params.material2, 'metalness', 0, 1 ).onChange( reset );
434456
matFolder2.add( params.material2, 'opacity', 0, 1 ).onChange( reset );
435457
matFolder2.add( params.material2, 'transmission', 0, 1 ).onChange( reset );
458+
matFolder2.add( params.material2, 'attenuationDistance', 0.05, 2.0 ).onChange( reset );
459+
matFolder2.addColor( params.material2, 'attenuationColor' ).onChange( reset );
436460
matFolder2.add( params.material2, 'ior', 0.9, 3.0 ).onChange( reset );
437461
matFolder2.add( params.material2, 'clearcoat', 0, 1 ).onChange( reset );
438462
matFolder2.add( params.material2, 'clearcoatRoughness', 0, 1 ).onChange( reset );
@@ -451,17 +475,7 @@ async function init() {
451475
matFolder3.addColor( params.material3, 'color' ).onChange( reset );
452476
matFolder3.add( params.material3, 'roughness', 0, 1 ).onChange( reset );
453477
matFolder3.add( params.material3, 'metalness', 0, 1 ).onChange( reset );
454-
matFolder3.add( params.material3, 'clearcoat', 0, 1 ).onChange( reset );
455-
matFolder3.add( params.material3, 'clearcoatRoughness', 0, 1 ).onChange( reset );
456-
matFolder3.addColor( params.material3, 'sheenColor' ).onChange( reset );
457-
matFolder3.add( params.material3, 'sheenRoughness', 0, 1 ).onChange( reset );
458478
matFolder3.add( params.material3, 'matte' ).onChange( reset );
459-
matFolder3.add( params.material3, 'castShadow' ).onChange( reset );
460-
matFolder3.add( params.material3, 'iridescence', 0.0, 1.0 ).onChange( reset );
461-
matFolder3.add( params.material3, 'iridescenceIOR', 0.1, 3.0 ).onChange( reset );
462-
matFolder3.add( params.material3, 'iridescenceThickness', 0.0, 1200.0 ).onChange( reset );
463-
matFolder3.addColor( params.material3, 'specularColor' ).onChange( reset );
464-
matFolder3.add( params.material3, 'specularIntensity', 0.0, 1.0 ).onChange( reset );
465479
matFolder3.close();
466480

467481
animate();
@@ -562,6 +576,8 @@ function animate() {
562576
m1.metalness = params.material1.metalness;
563577
m1.roughness = params.material1.roughness;
564578
m1.transmission = params.material1.transmission;
579+
m1.attenuationDistance = params.material1.attenuationDistance;
580+
m1.attenuationColor.set( params.material1.attenuationColor );
565581
m1.ior = params.material1.ior;
566582
m1.opacity = params.material1.opacity;
567583
m1.clearcoat = params.material1.clearcoat;
@@ -581,6 +597,8 @@ function animate() {
581597
m2.metalness = params.material2.metalness;
582598
m2.roughness = params.material2.roughness;
583599
m2.transmission = params.material2.transmission;
600+
m2.attenuationDistance = params.material2.attenuationDistance;
601+
m2.attenuationColor.set( params.material2.attenuationColor );
584602
m2.ior = params.material2.ior;
585603
m2.opacity = params.material2.opacity;
586604
m2.clearcoat = params.material2.clearcoat;
@@ -597,23 +615,13 @@ function animate() {
597615
m3.color.set( params.material3.color ).convertSRGBToLinear();
598616
m3.metalness = params.material3.metalness;
599617
m3.roughness = params.material3.roughness;
600-
m3.clearcoat = params.material3.clearcoat;
601-
m3.clearcoatRoughness = params.material3.clearcoatRoughness;
602-
m3.sheenColor.set( params.material3.sheenColor ).convertSRGBToLinear();
603-
m3.sheenRoughness = params.material3.sheenRoughness;
604-
m3.iridescence = params.material3.iridescence;
605-
m3.iridescenceIOR = params.material3.iridescenceIOR;
606-
m3.iridescenceThicknessRange = [ 0, params.material3.iridescenceThickness ];
607-
m3.specularColor.set( params.material3.specularColor ).convertSRGBToLinear();
608-
m3.specularIntensity = params.material3.specularIntensity;
609618

610619
ptRenderer.material.materials.updateFrom( sceneInfo.materials, sceneInfo.textures );
611620
ptRenderer.material.materials.setMatte( 0, params.material1.matte );
612621
ptRenderer.material.materials.setMatte( 1, params.material2.matte );
613622
ptRenderer.material.materials.setMatte( 2, params.material3.matte );
614623
ptRenderer.material.materials.setCastShadow( 0, params.material1.castShadow );
615624
ptRenderer.material.materials.setCastShadow( 1, params.material2.castShadow );
616-
ptRenderer.material.materials.setCastShadow( 2, params.material3.castShadow );
617625

618626
ptRenderer.material.filterGlossyFactor = params.filterGlossyFactor;
619627
ptRenderer.material.environmentIntensity = params.environmentIntensity;

example/viewerTest.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,6 @@ function animate() {
199199

200200
camera.updateMatrixWorld();
201201

202-
203-
204202
if ( ! params.pause || ptRenderer.samples < 1 ) {
205203

206204
for ( let i = 0, l = params.samplesPerFrame; i < l; i ++ ) {

src/materials/PhysicalPathTracingMaterial.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,11 +281,16 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
281281
282282
}
283283
284-
// only attenuate on the way in
285-
if ( isBelowSurface ) {
284+
if ( side == 1.0 && isBelowSurface ) {
286285
286+
// only attenuate by surface color on the way in
287287
color *= mix( vec3( 1.0 ), albedo.rgb, transmissionFactor );
288288
289+
} else if ( side == - 1.0 ) {
290+
291+
// attenuate by medium once we hit the opposite side of the model
292+
color *= transmissionAttenuation( dist, material.attenuationColor, material.attenuationDistance );
293+
289294
}
290295
291296
} else {
@@ -782,6 +787,8 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
782787
surfaceRec.iridescenceThickness = iridescenceThickness;
783788
surfaceRec.specularColor = specularColor;
784789
surfaceRec.specularIntensity = specularIntensity;
790+
surfaceRec.attenuationColor = material.attenuationColor;
791+
surfaceRec.attenuationDistance = material.attenuationDistance;
785792
786793
// apply perceptual roughness factor from gltf
787794
// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#microfacet-surfaces
@@ -932,6 +939,13 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
932939
933940
throughputColor *= sampleRec.color / sampleRec.pdf;
934941
942+
// attenuate the throughput color by the medium color
943+
if ( side == - 1.0 ) {
944+
945+
throughputColor *= transmissionAttenuation( dist, surfaceRec.attenuationColor, surfaceRec.attenuationDistance );
946+
947+
}
948+
935949
// discard the sample if there are any NaNs
936950
if ( any( isnan( throughputColor ) ) || any( isinf( throughputColor ) ) ) {
937951

src/shader/shaderMaterialSampling.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ struct SurfaceRec {
2626
float iridescenceThickness;
2727
vec3 specularColor;
2828
float specularIntensity;
29+
vec3 attenuationColor;
30+
float attenuationDistance;
2931
};
3032
3133
struct SampleRec {
@@ -224,7 +226,8 @@ vec3 transmissionDirection( vec3 wo, SurfaceRec surf ) {
224226
225227
vec3 transmissionColor( vec3 wo, vec3 wi, SurfaceRec surf ) {
226228
227-
return surf.color;
229+
// only attenuate the color if it's on the way in
230+
return surf.frontFace ? surf.color : vec3( 1.0 );
228231
229232
}
230233

src/shader/shaderStructs.js

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ export const shaderMaterialStructs = /* glsl */ `
6363
float specularIntensity;
6464
int specularIntensityMap;
6565
66+
vec3 attenuationColor;
67+
float attenuationDistance;
68+
6669
int alphaMap;
6770
6871
bool castShadow;
@@ -114,7 +117,7 @@ export const shaderMaterialStructs = /* glsl */ `
114117
115118
Material readMaterialInfo( sampler2D tex, uint index ) {
116119
117-
uint i = index * 44u;
120+
uint i = index * 45u;
118121
119122
vec4 s0 = texelFetch1D( tex, i + 0u );
120123
vec4 s1 = texelFetch1D( tex, i + 1u );
@@ -130,6 +133,7 @@ export const shaderMaterialStructs = /* glsl */ `
130133
vec4 s11 = texelFetch1D( tex, i + 11u );
131134
vec4 s12 = texelFetch1D( tex, i + 12u );
132135
vec4 s13 = texelFetch1D( tex, i + 13u );
136+
vec4 s14 = texelFetch1D( tex, i + 14u );
133137
134138
Material m;
135139
m.color = s0.rgb;
@@ -176,17 +180,20 @@ export const shaderMaterialStructs = /* glsl */ `
176180
m.specularIntensity = s11.r;
177181
m.specularIntensityMap = int( round( s11.g ) );
178182
179-
m.alphaMap = int( round( s12.r ) );
183+
m.attenuationColor = s12.rgb;
184+
m.attenuationDistance = s12.a;
185+
186+
m.alphaMap = int( round( s13.r ) );
180187
181-
m.opacity = s12.g;
182-
m.alphaTest = s12.b;
183-
m.side = s12.a;
188+
m.opacity = s13.g;
189+
m.alphaTest = s13.b;
190+
m.side = s13.a;
184191
185-
m.matte = bool( s13.r );
186-
m.castShadow = ! bool( s13.g );
187-
m.vertexColors = bool( s13.b );
192+
m.matte = bool( s14.r );
193+
m.castShadow = ! bool( s14.g );
194+
m.vertexColors = bool( s14.b );
188195
189-
uint firstTextureTransformIdx = i + 14u;
196+
uint firstTextureTransformIdx = i + 15u;
190197
191198
m.mapTransform = m.map == - 1 ? mat3( 0 ) : readTextureTransform( tex, firstTextureTransformIdx );
192199
m.metalnessMapTransform = m.metalnessMap == - 1 ? mat3( 0 ) : readTextureTransform( tex, firstTextureTransformIdx + 2u );

src/shader/shaderUtils.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
export const shaderUtils = /* glsl */`
22
3+
// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_volume/README.md#attenuation
4+
vec3 transmissionAttenuation( float dist, vec3 attColor, float attDist ) {
5+
6+
vec3 ot = - log( attColor ) / attDist;
7+
return exp( - ot * dist );
8+
9+
}
10+
311
// https://google.github.io/filament/Filament.md.html#materialsystem/diffusebrdf
412
float schlickFresnel( float cosine, float f0 ) {
513

0 commit comments

Comments
 (0)