From d268b80044e2a422c7a4061ef1c8f1e522b709af Mon Sep 17 00:00:00 2001 From: Daniel Sturk Date: Tue, 2 Jul 2019 15:09:49 -0400 Subject: [PATCH 01/22] Added sheen to physical material --- examples/webgl_materials_sheen.html | 378 ++++++++++++++++++ src/materials/MeshPhysicalMaterial.js | 4 + src/renderers/WebGLRenderer.js | 1 + src/renderers/shaders/ShaderChunk.d.ts | 1 + src/renderers/shaders/ShaderChunk.js | 2 + .../shaders/ShaderChunk/bsdfs.glsl.js | 26 ++ .../lights_physical_pars_fragment.glsl.js | 15 +- .../ShaderChunk/sheen_pars_fragment.glsl.js | 5 + src/renderers/shaders/ShaderLib.js | 3 +- .../ShaderLib/meshphysical_frag.glsl.js | 1 + 10 files changed, 434 insertions(+), 2 deletions(-) create mode 100644 examples/webgl_materials_sheen.html create mode 100644 src/renderers/shaders/ShaderChunk/sheen_pars_fragment.glsl.js diff --git a/examples/webgl_materials_sheen.html b/examples/webgl_materials_sheen.html new file mode 100644 index 00000000000000..0a4e3e071323ff --- /dev/null +++ b/examples/webgl_materials_sheen.html @@ -0,0 +1,378 @@ + + + Ammo.js softbody cloth demo + + + + + + +
Sheen demo by DanielSturk
Demo copied from webgl_physics_cloth.html
+
+ + + + + + + + + + + + diff --git a/src/materials/MeshPhysicalMaterial.js b/src/materials/MeshPhysicalMaterial.js index a4ea18c03cddbb..95c2f353128766 100644 --- a/src/materials/MeshPhysicalMaterial.js +++ b/src/materials/MeshPhysicalMaterial.js @@ -23,6 +23,8 @@ function MeshPhysicalMaterial( parameters ) { this.clearCoat = 0.0; this.clearCoatRoughness = 0.0; + this.sheen = 0.0; + this.setValues( parameters ); } @@ -43,6 +45,8 @@ MeshPhysicalMaterial.prototype.copy = function ( source ) { this.clearCoat = source.clearCoat; this.clearCoatRoughness = source.clearCoatRoughness; + this.sheen = source.sheen; + return this; }; diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index 924faf4e6e9ce5..90d61d69cae0de 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -2276,6 +2276,7 @@ function WebGLRenderer( parameters ) { uniforms.clearCoat.value = material.clearCoat; uniforms.clearCoatRoughness.value = material.clearCoatRoughness; + uniforms.sheen.value = material.sheen; } diff --git a/src/renderers/shaders/ShaderChunk.d.ts b/src/renderers/shaders/ShaderChunk.d.ts index c7845ef7a3ce0a..9ca97057911e5d 100644 --- a/src/renderers/shaders/ShaderChunk.d.ts +++ b/src/renderers/shaders/ShaderChunk.d.ts @@ -88,6 +88,7 @@ export let ShaderChunk: { points_vert: string; shadow_frag: string; shadow_vert: string; + sheen_pars_fragment: sheen_pars_fragment; premultiplied_alpha_fragment: string; project_vertex: string; diff --git a/src/renderers/shaders/ShaderChunk.js b/src/renderers/shaders/ShaderChunk.js index 2adf87807dac15..613b84fefbe3c6 100644 --- a/src/renderers/shaders/ShaderChunk.js +++ b/src/renderers/shaders/ShaderChunk.js @@ -87,6 +87,7 @@ import uv2_pars_fragment from './ShaderChunk/uv2_pars_fragment.glsl.js'; import uv2_pars_vertex from './ShaderChunk/uv2_pars_vertex.glsl.js'; import uv2_vertex from './ShaderChunk/uv2_vertex.glsl.js'; import worldpos_vertex from './ShaderChunk/worldpos_vertex.glsl.js'; +import sheen_pars_fragment from './ShaderChunk/sheen_pars_fragment.glsl'; import background_frag from './ShaderLib/background_frag.glsl.js'; import background_vert from './ShaderLib/background_vert.glsl.js'; @@ -209,6 +210,7 @@ export var ShaderChunk = { uv2_pars_vertex: uv2_pars_vertex, uv2_vertex: uv2_vertex, worldpos_vertex: worldpos_vertex, + sheen_pars_fragment: sheen_pars_fragment, background_frag: background_frag, background_vert: background_vert, diff --git a/src/renderers/shaders/ShaderChunk/bsdfs.glsl.js b/src/renderers/shaders/ShaderChunk/bsdfs.glsl.js index 10e69395f30106..8d25ada112a956 100644 --- a/src/renderers/shaders/ShaderChunk/bsdfs.glsl.js +++ b/src/renderers/shaders/ShaderChunk/bsdfs.glsl.js @@ -336,4 +336,30 @@ float GGXRoughnessToBlinnExponent( const in float ggxRoughness ) { float BlinnExponentToGGXRoughness( const in float blinnExponent ) { return sqrt( 2.0 / ( blinnExponent + 2.0 ) ); } + +// inverted Guassian distribution +float D_Inv(float b, float thetaH) { + + float cot2ThetaH = pow2( 1. / tan( thetaH ) ); + + return ( 1. / ( PI * ( 1. + 4. * pow2( b ) ) ) ) * + ( 1. + 4. * exp( -cot2ThetaH / pow2(b) ) / pow( sin( thetaH ), 4. ) ); + +} + +float BDRF_Diffuse_Sheen( const in float sheen, const in IncidentLight incidentLight, const in GeometricContext geometry ) { + + vec3 N = geometry.normal; + vec3 V = geometry.viewDir; + vec3 L = incidentLight.direction; + vec3 H = normalize( V + L ); + float dotNH = saturate( dot( N, H ) ); + + float thetaH = acos( dotNH ); + + return D_Inv( sheen, thetaH ) / ( + 4. * ( dot( N, L ) + dot( N, V ) - dot( N, L ) * dot( N, V ) ) + ); + +} `; diff --git a/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js index ba2bed2623f978..49e067e5a266c8 100644 --- a/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +++ b/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js @@ -84,7 +84,20 @@ void RE_Direct_Physical( const in IncidentLight directLight, const in GeometricC reflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness ); - reflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ); + + float sheenMix; + #ifdef SHEEN + if(sheen == 0.) sheenMix = 0.; + else sheenMix = 1. - pow(1. - sheen, 5.); + #else + sheenMix = 0.; + #endif + + reflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ) * (1. - sheenMix); + #ifdef SHEEN + // avoid expensive calculation + if(sheenMix > 0.) reflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * material.diffuseColor * irradiance * sheenMix * BDRF_Diffuse_Sheen( sheen, directLight, geometry ); + #endif #ifndef STANDARD diff --git a/src/renderers/shaders/ShaderChunk/sheen_pars_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/sheen_pars_fragment.glsl.js new file mode 100644 index 00000000000000..2de621af30bd2f --- /dev/null +++ b/src/renderers/shaders/ShaderChunk/sheen_pars_fragment.glsl.js @@ -0,0 +1,5 @@ +export default /* glsl */` + +#define SHEEN +uniform float sheen; +`; diff --git a/src/renderers/shaders/ShaderLib.js b/src/renderers/shaders/ShaderLib.js index 76f0c50cc50b78..0e1f9ff08aaf39 100644 --- a/src/renderers/shaders/ShaderLib.js +++ b/src/renderers/shaders/ShaderLib.js @@ -273,7 +273,8 @@ ShaderLib.physical = { ShaderLib.standard.uniforms, { clearCoat: { value: 0 }, - clearCoatRoughness: { value: 0 } + clearCoatRoughness: { value: 0 }, + sheen: { value: 0 } } ] ), diff --git a/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js b/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js index d909ad10d82793..35660c8f0831e2 100644 --- a/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js +++ b/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js @@ -33,6 +33,7 @@ varying vec3 vViewPosition; #include #include #include +#include #include #include #include From 9428b70c05cbadb32d05d13c925beb4839d030b1 Mon Sep 17 00:00:00 2001 From: Daniel Sturk Date: Tue, 2 Jul 2019 15:19:35 -0400 Subject: [PATCH 02/22] Moved sheen to PhysicalMaterial struct --- src/renderers/shaders/ShaderChunk.d.ts | 1 - src/renderers/shaders/ShaderChunk.js | 2 -- .../shaders/ShaderChunk/lights_physical_fragment.glsl.js | 1 + .../ShaderChunk/lights_physical_pars_fragment.glsl.js | 7 ++++--- .../shaders/ShaderChunk/sheen_pars_fragment.glsl.js | 5 ----- src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js | 2 +- 6 files changed, 6 insertions(+), 12 deletions(-) delete mode 100644 src/renderers/shaders/ShaderChunk/sheen_pars_fragment.glsl.js diff --git a/src/renderers/shaders/ShaderChunk.d.ts b/src/renderers/shaders/ShaderChunk.d.ts index 9ca97057911e5d..c7845ef7a3ce0a 100644 --- a/src/renderers/shaders/ShaderChunk.d.ts +++ b/src/renderers/shaders/ShaderChunk.d.ts @@ -88,7 +88,6 @@ export let ShaderChunk: { points_vert: string; shadow_frag: string; shadow_vert: string; - sheen_pars_fragment: sheen_pars_fragment; premultiplied_alpha_fragment: string; project_vertex: string; diff --git a/src/renderers/shaders/ShaderChunk.js b/src/renderers/shaders/ShaderChunk.js index 613b84fefbe3c6..2adf87807dac15 100644 --- a/src/renderers/shaders/ShaderChunk.js +++ b/src/renderers/shaders/ShaderChunk.js @@ -87,7 +87,6 @@ import uv2_pars_fragment from './ShaderChunk/uv2_pars_fragment.glsl.js'; import uv2_pars_vertex from './ShaderChunk/uv2_pars_vertex.glsl.js'; import uv2_vertex from './ShaderChunk/uv2_vertex.glsl.js'; import worldpos_vertex from './ShaderChunk/worldpos_vertex.glsl.js'; -import sheen_pars_fragment from './ShaderChunk/sheen_pars_fragment.glsl'; import background_frag from './ShaderLib/background_frag.glsl.js'; import background_vert from './ShaderLib/background_vert.glsl.js'; @@ -210,7 +209,6 @@ export var ShaderChunk = { uv2_pars_vertex: uv2_pars_vertex, uv2_vertex: uv2_vertex, worldpos_vertex: worldpos_vertex, - sheen_pars_fragment: sheen_pars_fragment, background_frag: background_frag, background_vert: background_vert, diff --git a/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js index a9628deed45599..f60b36795fa061 100644 --- a/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js +++ b/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js @@ -8,5 +8,6 @@ material.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 ); material.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor ); material.clearCoat = saturate( clearCoat ); // Burley clearcoat model material.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 ); + material.sheen = sheen; #endif `; diff --git a/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js index 49e067e5a266c8..840a869679601b 100644 --- a/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +++ b/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js @@ -8,6 +8,7 @@ struct PhysicalMaterial { #ifndef STANDARD float clearCoat; float clearCoatRoughness; + float sheen; #endif }; @@ -86,15 +87,15 @@ void RE_Direct_Physical( const in IncidentLight directLight, const in GeometricC float sheenMix; - #ifdef SHEEN + #ifndef STANDARD if(sheen == 0.) sheenMix = 0.; - else sheenMix = 1. - pow(1. - sheen, 5.); + else sheenMix = 1. - pow(1. - material.sheen, 5.); #else sheenMix = 0.; #endif reflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ) * (1. - sheenMix); - #ifdef SHEEN + #ifndef STANDARD // avoid expensive calculation if(sheenMix > 0.) reflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * material.diffuseColor * irradiance * sheenMix * BDRF_Diffuse_Sheen( sheen, directLight, geometry ); #endif diff --git a/src/renderers/shaders/ShaderChunk/sheen_pars_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/sheen_pars_fragment.glsl.js deleted file mode 100644 index 2de621af30bd2f..00000000000000 --- a/src/renderers/shaders/ShaderChunk/sheen_pars_fragment.glsl.js +++ /dev/null @@ -1,5 +0,0 @@ -export default /* glsl */` - -#define SHEEN -uniform float sheen; -`; diff --git a/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js b/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js index 35660c8f0831e2..6df315f2543ac6 100644 --- a/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js +++ b/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js @@ -6,6 +6,7 @@ uniform vec3 emissive; uniform float roughness; uniform float metalness; uniform float opacity; +uniform float sheen; #ifndef STANDARD uniform float clearCoat; @@ -33,7 +34,6 @@ varying vec3 vViewPosition; #include #include #include -#include #include #include #include From fcd8fdad4e0cb6931531c4e07785d385d2b2b3ee Mon Sep 17 00:00:00 2001 From: Daniel Sturk Date: Tue, 2 Jul 2019 15:44:02 -0400 Subject: [PATCH 03/22] Fixed renaming mistake --- .../ShaderChunk/lights_physical_pars_fragment.glsl.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js index 840a869679601b..971f0d74d019c1 100644 --- a/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +++ b/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js @@ -88,8 +88,9 @@ void RE_Direct_Physical( const in IncidentLight directLight, const in GeometricC float sheenMix; #ifndef STANDARD - if(sheen == 0.) sheenMix = 0.; - else sheenMix = 1. - pow(1. - material.sheen, 5.); + float sheenFactor = material.sheen; + if(sheenFactor == 0.) sheenMix = 0.; + else sheenMix = 1. - pow(1. - sheenFactor, 5.); #else sheenMix = 0.; #endif @@ -97,7 +98,7 @@ void RE_Direct_Physical( const in IncidentLight directLight, const in GeometricC reflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ) * (1. - sheenMix); #ifndef STANDARD // avoid expensive calculation - if(sheenMix > 0.) reflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * material.diffuseColor * irradiance * sheenMix * BDRF_Diffuse_Sheen( sheen, directLight, geometry ); + if(sheenMix > 0.) reflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * material.diffuseColor * irradiance * sheenMix * BDRF_Diffuse_Sheen( sheenFactor, directLight, geometry ); #endif #ifndef STANDARD From 1ae0a6568f91efbeaca6af421ec264e6102a54b9 Mon Sep 17 00:00:00 2001 From: Daniel Sturk Date: Wed, 3 Jul 2019 15:23:24 -0400 Subject: [PATCH 04/22] Added sheen to StandardNodeMaterial # Conflicts: # examples/jsm/nodes/materials/nodes/StandardNode.js # examples/webgl_materials_nodes.html --- examples/jsm/nodes/materials/StandardNodeMaterial.js | 3 ++- examples/jsm/nodes/materials/nodes/StandardNode.js | 4 +++- examples/webgl_materials_nodes.html | 12 +++++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/examples/jsm/nodes/materials/StandardNodeMaterial.js b/examples/jsm/nodes/materials/StandardNodeMaterial.js index bcc220473bc904..f574ff39015b57 100644 --- a/examples/jsm/nodes/materials/StandardNodeMaterial.js +++ b/examples/jsm/nodes/materials/StandardNodeMaterial.js @@ -35,7 +35,8 @@ NodeUtils.addShortcuts( StandardNodeMaterial.prototype, 'fragment', [ 'ao', 'environment', 'mask', - 'position' + 'position', + 'sheen' ] ); export { StandardNodeMaterial }; diff --git a/examples/jsm/nodes/materials/nodes/StandardNode.js b/examples/jsm/nodes/materials/nodes/StandardNode.js index a84e4b27e4c4c8..424641feb515c8 100644 --- a/examples/jsm/nodes/materials/nodes/StandardNode.js +++ b/examples/jsm/nodes/materials/nodes/StandardNode.js @@ -30,7 +30,7 @@ StandardNode.prototype.build = function ( builder ) { var code; - builder.define( this.clearCoat || this.clearCoatRoughness ? 'PHYSICAL' : 'STANDARD' ); + builder.define( this.clearCoat || this.clearCoatRoughness || this.sheen ? 'PHYSICAL' : 'STANDARD' ); builder.requires.lights = true; @@ -183,6 +183,8 @@ StandardNode.prototype.build = function ( builder ) { var clearCoatEnv = useClearCoat && environment ? this.environment.flow( builder, 'c', { cache: 'clearCoat', context: contextEnvironment, slot: 'environment' } ) : undefined; + var sheen = ! builder.isDefined( 'STANDARD' ) && this.sheen ? this.sheen.buildCode( builder, 'f' ) : undefined; + builder.requires.transparent = alpha !== undefined; builder.addParsCode( [ diff --git a/examples/webgl_materials_nodes.html b/examples/webgl_materials_nodes.html index 7bb5577e6bc957..50d35185e5f4c6 100644 --- a/examples/webgl_materials_nodes.html +++ b/examples/webgl_materials_nodes.html @@ -559,7 +559,9 @@ Nodes.OperatorNode.MUL ); - mtl.color = new Nodes.ColorNode( 0xEEEEEE ); + var sheen = new THREE.FloatNode(.5); + + mtl.color = new THREE.ColorNode( 0xEEEEEE ); mtl.roughness = roughness; mtl.metalness = metalness; mtl.reflectivity = reflectivity; @@ -569,6 +571,8 @@ mtl.normal = new Nodes.NormalMapNode( new Nodes.TextureNode( getTexture( "grassNormal" ) ) ); mtl.normal.scale = normalMask; + mtl.sheen = sheen; + // GUI addGui( 'color', mtl.color.value.getHex(), function ( val ) { @@ -625,6 +629,12 @@ }, false, 0, 1 ); + addGui( 'sheen', sheen.value, function ( val ) { + + sheen.value = val; + + }, false, 0, 1 ); + break; case 'wave': From b728371ce9c11d364e650bc617a55c9fd4e72d96 Mon Sep 17 00:00:00 2001 From: Daniel Sturk Date: Wed, 3 Jul 2019 15:12:32 -0400 Subject: [PATCH 05/22] Fixed node material crashing, added more options to sheen demo --- examples/jsm/nodes/materials/nodes/StandardNode.js | 4 ++++ examples/webgl_materials_sheen.html | 14 ++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/examples/jsm/nodes/materials/nodes/StandardNode.js b/examples/jsm/nodes/materials/nodes/StandardNode.js index 424641feb515c8..1e800a0c63dd53 100644 --- a/examples/jsm/nodes/materials/nodes/StandardNode.js +++ b/examples/jsm/nodes/materials/nodes/StandardNode.js @@ -293,6 +293,10 @@ StandardNode.prototype.build = function ( builder ) { output.push( 'material.clearCoatRoughness = 0.0;' ); + } else { + + output.push( 'float sheen = 0.;' ); + } if ( reflectivity ) { diff --git a/examples/webgl_materials_sheen.html b/examples/webgl_materials_sheen.html index 0a4e3e071323ff..172ecb7bf1b31e 100644 --- a/examples/webgl_materials_sheen.html +++ b/examples/webgl_materials_sheen.html @@ -49,7 +49,9 @@ var clothMaterial; var params = { - sheen: .5 + sheen: .5, + hue: 0, + roughness: 1 }; Ammo().then( function( AmmoLib ) { @@ -98,7 +100,7 @@ var ambientLight = new THREE.AmbientLight( 0x404040 ); scene.add( ambientLight ); - var light = new THREE.DirectionalLight( 0xffffff, 1 ); + var light = new THREE.DirectionalLight( 0xffffff, 2 ); light.position.set( - 7, 10, 15 ); light.castShadow = true; var d = 10; @@ -126,6 +128,8 @@ var gui = new dat.GUI(); gui.add( params, 'sheen', 0, 1 ); + gui.add( params, 'hue', 0, 360 ); + gui.add( params, 'roughness', 0, 1 ); gui.open(); } @@ -165,7 +169,7 @@ clothGeometry.rotateY( Math.PI * 0.5 ); clothGeometry.translate( clothPos.x, clothPos.y + clothHeight * 0.5, clothPos.z - clothWidth * 0.5 ); clothMaterial = new THREE.MeshPhysicalMaterial( { - color: 0xFFFFFF, + color: 0x8000FF, side: THREE.DoubleSide, roughness: 1, sheen: .9 @@ -179,7 +183,7 @@ texture.wrapS = THREE.RepeatWrapping; texture.wrapT = THREE.RepeatWrapping; texture.repeat.set( clothNumSegmentsZ, clothNumSegmentsY ); - cloth.material.map = texture; + // cloth.material.map = texture; cloth.material.needsUpdate = true; } ); @@ -322,6 +326,8 @@ updatePhysics( deltaTime ); clothMaterial.sheen = params.sheen; + clothMaterial.color = new THREE.Color().setHSL(params.hue / 360, 1, .5); + clothMaterial.roughness = params.roughness; renderer.render( scene, camera ); From ef38e812fca4af1871cd2a1ab1757e89f6f671dd Mon Sep 17 00:00:00 2001 From: Daniel Sturk Date: Wed, 3 Jul 2019 15:12:32 -0400 Subject: [PATCH 06/22] Fixed node material crashing, added more options to sheen demo --- examples/jsm/nodes/materials/nodes/StandardNode.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/jsm/nodes/materials/nodes/StandardNode.js b/examples/jsm/nodes/materials/nodes/StandardNode.js index 1e800a0c63dd53..3227923e4abe46 100644 --- a/examples/jsm/nodes/materials/nodes/StandardNode.js +++ b/examples/jsm/nodes/materials/nodes/StandardNode.js @@ -297,6 +297,10 @@ StandardNode.prototype.build = function ( builder ) { output.push( 'float sheen = 0.;' ); + } else { + + output.push( 'float sheen = 0.;' ); + } if ( reflectivity ) { From 8597102f4d6445f27e8b947b7ad9d5cacdbe917a Mon Sep 17 00:00:00 2001 From: Daniel Sturk Date: Wed, 3 Jul 2019 15:14:04 -0400 Subject: [PATCH 07/22] Switched to Google's Filament sheen BDRF --- .../shaders/ShaderChunk/bsdfs.glsl.js | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/renderers/shaders/ShaderChunk/bsdfs.glsl.js b/src/renderers/shaders/ShaderChunk/bsdfs.glsl.js index 8d25ada112a956..c53bca9dbaa018 100644 --- a/src/renderers/shaders/ShaderChunk/bsdfs.glsl.js +++ b/src/renderers/shaders/ShaderChunk/bsdfs.glsl.js @@ -347,19 +347,33 @@ float D_Inv(float b, float thetaH) { } +// https://github.com/google/filament/blob/master/shaders/src/brdf.fs#L94 +float D_Charlie(float roughness, float NoH) { + // Estevez and Kulla 2017, "Production Friendly Microfacet Sheen BRDF" + float invAlpha = 1.0 / roughness; + float cos2h = NoH * NoH; + float sin2h = max(1.0 - cos2h, 0.0078125); // 2^(-14/2), so sin2h^2 > 0 in fp16 + return (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI); +} + +// https://github.com/google/filament/blob/master/shaders/src/brdf.fs#L136 +float V_Neubelt(float NoV, float NoL) { + // Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886" + return saturate(1.0 / (4.0 * (NoL + NoV - NoL * NoV))); +} + float BDRF_Diffuse_Sheen( const in float sheen, const in IncidentLight incidentLight, const in GeometricContext geometry ) { vec3 N = geometry.normal; vec3 V = geometry.viewDir; vec3 L = incidentLight.direction; + vec3 H = normalize( V + L ); float dotNH = saturate( dot( N, H ) ); float thetaH = acos( dotNH ); - return D_Inv( sheen, thetaH ) / ( - 4. * ( dot( N, L ) + dot( N, V ) - dot( N, L ) * dot( N, V ) ) - ); + return D_Charlie( sheen, dot(N, H) ) * V_Neubelt( dot(N, V), dot(N, L) ); } `; From 79cd845ab12188f848cd3b80ce4921268333f853 Mon Sep 17 00:00:00 2001 From: Daniel Sturk Date: Wed, 3 Jul 2019 15:41:13 -0400 Subject: [PATCH 08/22] Fixed errors due to discrepancies between mainline and private three.js repos --- .../jsm/nodes/materials/nodes/StandardNode.js | 10 ++++----- examples/webgl_materials_nodes.html | 4 ++-- examples/webgl_materials_sheen.html | 22 +++++++------------ 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/examples/jsm/nodes/materials/nodes/StandardNode.js b/examples/jsm/nodes/materials/nodes/StandardNode.js index 3227923e4abe46..079328f6be08a1 100644 --- a/examples/jsm/nodes/materials/nodes/StandardNode.js +++ b/examples/jsm/nodes/materials/nodes/StandardNode.js @@ -183,7 +183,7 @@ StandardNode.prototype.build = function ( builder ) { var clearCoatEnv = useClearCoat && environment ? this.environment.flow( builder, 'c', { cache: 'clearCoat', context: contextEnvironment, slot: 'environment' } ) : undefined; - var sheen = ! builder.isDefined( 'STANDARD' ) && this.sheen ? this.sheen.buildCode( builder, 'f' ) : undefined; + var sheen = ! builder.isDefined( 'STANDARD' ) && this.sheen ? this.sheen.flow( builder, 'f' ) : undefined; builder.requires.transparent = alpha !== undefined; @@ -293,13 +293,11 @@ StandardNode.prototype.build = function ( builder ) { output.push( 'material.clearCoatRoughness = 0.0;' ); - } else { - - output.push( 'float sheen = 0.;' ); + } - } else { + if ( sheen ) { - output.push( 'float sheen = 0.;' ); + output.push( 'material.sheen = ' + sheen.result + ';' ); } diff --git a/examples/webgl_materials_nodes.html b/examples/webgl_materials_nodes.html index 50d35185e5f4c6..13842c7973d495 100644 --- a/examples/webgl_materials_nodes.html +++ b/examples/webgl_materials_nodes.html @@ -559,9 +559,9 @@ Nodes.OperatorNode.MUL ); - var sheen = new THREE.FloatNode(.5); + var sheen = new Nodes.FloatNode(.5); - mtl.color = new THREE.ColorNode( 0xEEEEEE ); + mtl.color = new Nodes.ColorNode( 0xEEEEEE ); mtl.roughness = roughness; mtl.metalness = metalness; mtl.reflectivity = reflectivity; diff --git a/examples/webgl_materials_sheen.html b/examples/webgl_materials_sheen.html index 172ecb7bf1b31e..102d4b3adba1d9 100644 --- a/examples/webgl_materials_sheen.html +++ b/examples/webgl_materials_sheen.html @@ -14,22 +14,16 @@
Sheen demo by DanielSturk
Demo copied from webgl_physics_cloth.html
- - - - - - From 2c575709ccbfd0dc3dc15e9ee2fdbc2d80b9b395 Mon Sep 17 00:00:00 2001 From: Daniel Sturk Date: Thu, 25 Jul 2019 10:38:42 -0400 Subject: [PATCH 13/22] forgot to commit fbx --- examples/models/fbx/cloth.fbx | Bin 0 -> 133536 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/models/fbx/cloth.fbx diff --git a/examples/models/fbx/cloth.fbx b/examples/models/fbx/cloth.fbx new file mode 100644 index 0000000000000000000000000000000000000000..91b5858c2184915cf91e7780b65a74ea28506e03 GIT binary patch literal 133536 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

LHpBpQ>{hcbm?^q)iRE|mb>*F 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


A|?y3Mek6uTs)(QA1y1^Xz>~Pu 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 Date: Thu, 25 Jul 2019 10:43:10 -0400 Subject: [PATCH 14/22] Changed title of demo --- examples/webgl_materials_sheen.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/webgl_materials_sheen.html b/examples/webgl_materials_sheen.html index db716a49c9058d..9ebc7d4bbb930f 100644 --- a/examples/webgl_materials_sheen.html +++ b/examples/webgl_materials_sheen.html @@ -1,6 +1,6 @@ - Ammo.js softbody cloth demo + Sheen demo (material property) @@ -11,7 +11,7 @@ -
Sheen demo by DanielSturk
Demo copied from webgl_physics_cloth.html
+
Sheen demo by DanielSturk
From 7f5e885671da139cdd6c946796d1d7deee15472e Mon Sep 17 00:00:00 2001 From: Daniel Sturk Date: Thu, 1 Aug 2019 09:47:41 -0400 Subject: [PATCH 15/22] added typescript declaration --- src/materials/MeshPhysicalMaterial.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/materials/MeshPhysicalMaterial.d.ts b/src/materials/MeshPhysicalMaterial.d.ts index 96c7f15247b6d3..d702186086e5ab 100644 --- a/src/materials/MeshPhysicalMaterial.d.ts +++ b/src/materials/MeshPhysicalMaterial.d.ts @@ -8,6 +8,7 @@ export interface MeshPhysicalMaterialParameters reflectivity?: number; clearCoat?: number; clearCoatRoughness?: number; + sheen?: number; } export class MeshPhysicalMaterial extends MeshStandardMaterial { @@ -18,5 +19,6 @@ export class MeshPhysicalMaterial extends MeshStandardMaterial { reflectivity: number; clearCoat: number; clearCoatRoughness: number; + sheen: number; } From c42ccfbf0cab1a4f53b0a616d201332843e4a8f4 Mon Sep 17 00:00:00 2001 From: Daniel Sturk Date: Thu, 8 Aug 2019 10:11:04 -0400 Subject: [PATCH 16/22] fixed formatting --- src/materials/MeshPhysicalMaterial.d.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/materials/MeshPhysicalMaterial.d.ts b/src/materials/MeshPhysicalMaterial.d.ts index 7c24b0b66313db..0b9afc20dd7295 100644 --- a/src/materials/MeshPhysicalMaterial.d.ts +++ b/src/materials/MeshPhysicalMaterial.d.ts @@ -17,7 +17,8 @@ export interface MeshPhysicalMaterialParameters } export class MeshPhysicalMaterial extends MeshStandardMaterial { - constructor(parameters: MeshPhysicalMaterialParameters); + + constructor( parameters: MeshPhysicalMaterialParameters ); defines: any; reflectivity: number; @@ -27,4 +28,5 @@ export class MeshPhysicalMaterial extends MeshStandardMaterial { clearCoatNormalScale: Vector2; clearCoatNormalMap: Texture | null; + } From 52ef06210205b00105577e56a9001ce52e439e09 Mon Sep 17 00:00:00 2001 From: Daniel Sturk Date: Wed, 14 Aug 2019 14:02:18 -0400 Subject: [PATCH 17/22] wip: proof of concept sheen IBL, needs cleanup (at least) --- examples/textures/dfg.png | Bin 0 -> 7471 bytes examples/webgl_materials_sheen.html | 88 ++++++++++++++---- src/renderers/WebGLRenderer.js | 1 + .../shaders/ShaderChunk/bsdfs.glsl.js | 10 +- .../lights_physical_pars_fragment.glsl.js | 59 ++++++------ src/renderers/shaders/ShaderLib.js | 1 + .../ShaderLib/meshphysical_frag.glsl.js | 1 + 7 files changed, 107 insertions(+), 53 deletions(-) create mode 100644 examples/textures/dfg.png diff --git a/examples/textures/dfg.png b/examples/textures/dfg.png new file mode 100644 index 0000000000000000000000000000000000000000..ec8f2cc702c78fff46adea9e823ee38c29c58527 GIT binary patch literal 7471 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 gG8XZzZ=D26WQQ 0.) reflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * sheenMix * material.diffuseColor * irradiance * BDRF_Diffuse_Sheen( sheenFactor, directLight, geometry ); - - #endif - + reflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * (sheen > 0. ? + BRDF_Specular_Sheen( + material.specularRoughness, + directLight.direction, + geometry, + mix( + material.specularColor, + material.diffuseColor, + sheen + ) + ) + : BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness) + ); + reflectedLight.directDiffuse += ( 1. - sheen ) * ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ); } void RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { @@ -149,6 +138,8 @@ void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradia #endif float clearCoatInv = 1.0 - clearCoatDHR; + float sheen = material.sheen; + float sheenInv = 1. - sheen; // Both indirect specular and diffuse light accumulate here // if energy preservation enabled, and PMREM provided. @@ -159,18 +150,28 @@ void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradia BRDF_Specular_Multiscattering_Environment( geometry, material.specularColor, material.specularRoughness, singleScattering, multiScattering ); - vec3 diffuse = material.diffuseColor * ( 1.0 - ( singleScattering + multiScattering ) ); + vec3 diffuse = material.diffuseColor * mix( + ( 1.0 - ( singleScattering + multiScattering ) ), + vec3(0), + sheen + ); - reflectedLight.indirectSpecular += clearCoatInv * radiance * singleScattering; - reflectedLight.indirectDiffuse += multiScattering * cosineWeightedIrradiance; + reflectedLight.indirectSpecular += sheenInv * clearCoatInv * radiance * singleScattering; + reflectedLight.indirectDiffuse += sheenInv * multiScattering * cosineWeightedIrradiance; reflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance; #ifndef STANDARD - reflectedLight.indirectSpecular += clearCoatInv * radiance * BRDF_Specular_GGX_Environment( geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness ); + reflectedLight.indirectSpecular += sheenInv * clearCoatInv * radiance * BRDF_Specular_GGX_Environment( geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness ); #endif + reflectedLight.indirectSpecular += sheen * cosineWeightedIrradiance * BRDF_Specular_Sheen_Environment( + geometry, + material.diffuseColor, + material.specularRoughness + ); + } #define RE_Direct RE_Direct_Physical diff --git a/src/renderers/shaders/ShaderLib.js b/src/renderers/shaders/ShaderLib.js index 69e23ea6e8116a..c425aa148443bf 100644 --- a/src/renderers/shaders/ShaderLib.js +++ b/src/renderers/shaders/ShaderLib.js @@ -276,6 +276,7 @@ ShaderLib.physical = { clearCoat: { value: 0 }, clearCoatRoughness: { value: 0 }, sheen: { value: 0 }, + dfgLut: { value: null }, clearCoatNormalScale: { value: new Vector2( 1, 1 ) }, clearCoatNormalMap: { value: null }, } diff --git a/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js b/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js index 5b56808ecf1106..1a63ceb9b5a96e 100644 --- a/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js +++ b/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js @@ -7,6 +7,7 @@ uniform float roughness; uniform float metalness; uniform float opacity; uniform float sheen; +uniform sampler2D dfgLut; #ifndef STANDARD uniform float clearCoat; From 74e5482d3765ad84b2f16401a47fef94c421e830 Mon Sep 17 00:00:00 2001 From: Daniel Sturk Date: Tue, 20 Aug 2019 14:08:11 -0400 Subject: [PATCH 18/22] replaced sheen with sheenColor, and removed IBL sheen (for now) --- examples/webgl_materials_sheen.html | 67 ++++--------------- src/materials/MeshPhysicalMaterial.d.ts | 7 +- src/materials/MeshPhysicalMaterial.js | 10 ++- src/renderers/WebGLRenderer.js | 3 +- .../shaders/ShaderChunk/bsdfs.glsl.js | 7 +- .../lights_physical_fragment.glsl.js | 4 +- .../lights_physical_pars_fragment.glsl.js | 51 +++++--------- src/renderers/shaders/ShaderLib.js | 2 +- .../ShaderLib/meshphysical_frag.glsl.js | 6 +- src/renderers/webgl/WebGLProgram.js | 2 + src/renderers/webgl/WebGLPrograms.js | 5 +- 11 files changed, 62 insertions(+), 102 deletions(-) diff --git a/examples/webgl_materials_sheen.html b/examples/webgl_materials_sheen.html index 449bcdbe0b0264..5b275f48f4b1bd 100644 --- a/examples/webgl_materials_sheen.html +++ b/examples/webgl_materials_sheen.html @@ -27,23 +27,16 @@ import { FBXLoader } from './jsm/loaders/FBXLoader.js'; - import { RGBELoader } from './jsm/loaders/RGBELoader.js'; - import { EquirectangularToCubeGenerator } from './jsm/loaders/EquirectangularToCubeGenerator.js'; - import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js'; - import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js'; - // Graphics variables var camera, controls, scene, renderer, mesh, stats; - var envMap, directionalLight, ambientLight; + var directionalLight; var params = { - sheen: .8, - hue: 265, + color: new THREE.Color( 255, 0, 127 ), + sheenBRDF: true, + sheenColor: new THREE.Color( 10, 10, 10 ), // corresponds to .04 reflectance roughness: .9, exposure: 2, - envMap: true, - directionalLight: false, - ambientLight: false }; // model @@ -83,41 +76,11 @@ renderer.shadowMap.enabled = true; container.appendChild( renderer.domElement ); - renderer.dfgLut = new THREE.TextureLoader().load( 'textures/dfg.png' ); - renderer.dfgLut.generateMipmaps = false; - renderer.dfgLut.magFilter = THREE.LinearFilter; - renderer.dfgLut.minFilter = THREE.LinearFilter; - - var hdrUrls = [ 'px.hdr', 'nx.hdr', 'py.hdr', 'ny.hdr', 'pz.hdr', 'nz.hdr' ]; - - new THREE.CubeTextureLoader() - .setPath( 'textures/cube/Park3Med/' ) - .load( [ 'px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg' ], function ( ldrCubeMap ) { - - envMap = ldrCubeMap; - - var pmremGenerator = new PMREMGenerator( envMap, 128 ); - pmremGenerator.update( renderer ); - - var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); - pmremCubeUVPacker.update( renderer ); - - mesh.material.envMap = pmremCubeUVPacker.CubeUVRenderTarget.texture; - mesh.material.needsUpdate = true; - - pmremGenerator.dispose(); - pmremCubeUVPacker.dispose(); - - } ); - controls = new OrbitControls( camera, renderer.domElement ); controls.target.set( 0, 2, 0 ); controls.update(); - ambientLight = new THREE.AmbientLight( 0x404040 ); - scene.add( ambientLight ); - - directionalLight = new THREE.DirectionalLight( 0xffffff, 1.5 ); + directionalLight = new THREE.DirectionalLight( 0xffffff, .5 ); directionalLight.position.set( 0, 10, 0 ); directionalLight.castShadow = true; directionalLight.add( @@ -138,13 +101,11 @@ var gui = new GUI(); - gui.add( params, 'sheen', 0, 1 ); - gui.add( params, 'hue', 0, 360 ); + gui.addColor( params, 'color' ); + gui.add( params, 'sheenBRDF' ); + gui.addColor( params, 'sheenColor' ); gui.add( params, 'roughness', 0, 1 ); gui.add( params, 'exposure', 0, 3 ); - gui.add( params, 'envMap' ); - gui.add( params, 'directionalLight' ); - gui.add( params, 'ambientLight' ); gui.open(); animate(); @@ -171,14 +132,14 @@ function render() { - mesh.material.sheen = params.sheen; - mesh.material.color = new THREE.Color().setHSL(params.hue / 360, 1, .5); + mesh.material.sheenColor = params.sheenBRDF + ? new THREE.Color().copy( params.sheenColor ).multiplyScalar( 1 / 255 ) + : null; + + mesh.material.color.copy(params.color).multiplyScalar( 1 / 255 ); mesh.material.roughness = params.roughness; renderer.toneMappingExposure = params.exposure; - scene.background = params.envMap && envMap || null; - mesh.material.envMapIntensity = params.envMap ? 1 : 0; - directionalLight.visible = params.directionalLight; - ambientLight.visible = params.ambientLight; + mesh.material.needsUpdate = true; renderer.render( scene, camera ); diff --git a/src/materials/MeshPhysicalMaterial.d.ts b/src/materials/MeshPhysicalMaterial.d.ts index 0b9afc20dd7295..fdec848b9c5c1d 100644 --- a/src/materials/MeshPhysicalMaterial.d.ts +++ b/src/materials/MeshPhysicalMaterial.d.ts @@ -4,13 +4,15 @@ import { MeshStandardMaterialParameters, MeshStandardMaterial, } from './MeshStandardMaterial'; +import { Color } from './../math/Color'; export interface MeshPhysicalMaterialParameters extends MeshStandardMaterialParameters { reflectivity?: number; clearCoat?: number; clearCoatRoughness?: number; - sheen?: number; + + sheenColor?: Color; clearCoatNormalScale?: Vector2; clearCoatNormalMap?: Texture; @@ -24,7 +26,8 @@ export class MeshPhysicalMaterial extends MeshStandardMaterial { reflectivity: number; clearCoat: number; clearCoatRoughness: number; - sheen: number; + + sheenColor: Color | null; clearCoatNormalScale: Vector2; clearCoatNormalMap: Texture | null; diff --git a/src/materials/MeshPhysicalMaterial.js b/src/materials/MeshPhysicalMaterial.js index f7028e5098a1b8..55f3a34caed0d9 100644 --- a/src/materials/MeshPhysicalMaterial.js +++ b/src/materials/MeshPhysicalMaterial.js @@ -1,5 +1,6 @@ import { Vector2 } from '../math/Vector2.js'; import { MeshStandardMaterial } from './MeshStandardMaterial.js'; +import { Color } from '../math/Color.js'; /** * @author WestLangley / http://github.com/WestLangley @@ -9,6 +10,8 @@ import { MeshStandardMaterial } from './MeshStandardMaterial.js'; * clearCoat: * clearCoatRoughness: * + * sheen: + * * clearCoatNormalScale: , * clearCoatNormalMap: new THREE.Texture( ), * } @@ -27,7 +30,8 @@ function MeshPhysicalMaterial( parameters ) { this.clearCoat = 0.0; this.clearCoatRoughness = 0.0; - this.sheen = 0.0; + this.sheenColor = null; // null will disable sheen bsdf + this.clearCoatNormalScale = new Vector2( 1, 1 ); this.clearCoatNormalMap = null; @@ -51,7 +55,9 @@ MeshPhysicalMaterial.prototype.copy = function ( source ) { this.clearCoat = source.clearCoat; this.clearCoatRoughness = source.clearCoatRoughness; - this.sheen = source.sheen; + if( source.sheenColor ) this.sheenColor = ( this.sheenColor || new Color() ).copy( source.sheenColor ); + else this.sheenColor = null; + this.clearCoatNormalMap = source.clearCoatNormalMap; this.clearCoatNormalScale.copy( source.clearCoatNormalScale ); diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index d90e50cf7cd7d4..15f3aec61b2226 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -2272,8 +2272,7 @@ function WebGLRenderer( parameters ) { uniforms.clearCoat.value = material.clearCoat; uniforms.clearCoatRoughness.value = material.clearCoatRoughness; - uniforms.sheen.value = material.sheen; - uniforms.dfgLut.value = _this.dfgLut || null; + if( material.sheenColor ) uniforms.sheenColor.value.copy( material.sheenColor ); if ( material.clearCoatNormalMap ) { diff --git a/src/renderers/shaders/ShaderChunk/bsdfs.glsl.js b/src/renderers/shaders/ShaderChunk/bsdfs.glsl.js index d38d3f87a63573..9e479c6c614aea 100644 --- a/src/renderers/shaders/ShaderChunk/bsdfs.glsl.js +++ b/src/renderers/shaders/ShaderChunk/bsdfs.glsl.js @@ -337,6 +337,8 @@ float BlinnExponentToGGXRoughness( const in float blinnExponent ) { return sqrt( 2.0 / ( blinnExponent + 2.0 ) ); } +#if defined( USE_SHEEN ) + // https://github.com/google/filament/blob/master/shaders/src/brdf.fs#L94 float D_Charlie(float roughness, float NoH) { // Estevez and Kulla 2017, "Production Friendly Microfacet Sheen BRDF" @@ -364,8 +366,5 @@ vec3 BRDF_Specular_Sheen( const in float roughness, const in vec3 L, const in Ge } -vec3 BRDF_Specular_Sheen_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) { - float dotNV = saturate( dot( geometry.normal, geometry.viewDir ) ); - return specularColor * texture2D(dfgLut, vec2(dotNV, roughness)).b; -} +#endif `; diff --git a/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js index f60b36795fa061..87b8e08bfa711b 100644 --- a/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js +++ b/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js @@ -8,6 +8,8 @@ material.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 ); material.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor ); material.clearCoat = saturate( clearCoat ); // Burley clearcoat model material.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 ); - material.sheen = sheen; +#endif +#ifdef USE_SHEEN + material.sheenColor = sheenColor; #endif `; diff --git a/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js index 521d16f6a9138b..5a4421eafedf46 100644 --- a/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +++ b/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js @@ -8,7 +8,10 @@ struct PhysicalMaterial { #ifndef STANDARD float clearCoat; float clearCoatRoughness; - float sheen; + #endif + + #ifdef USE_SHEEN + vec3 sheenColor; #endif }; @@ -99,20 +102,18 @@ void RE_Direct_Physical( const in IncidentLight directLight, const in GeometricC #endif - reflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * (sheen > 0. ? - BRDF_Specular_Sheen( + #ifdef USE_SHEEN + reflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_Sheen( material.specularRoughness, directLight.direction, geometry, - mix( - material.specularColor, - material.diffuseColor, - sheen - ) - ) - : BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness) - ); - reflectedLight.directDiffuse += ( 1. - sheen ) * ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ); + sheenColor + ); + #else + reflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness); + #endif + + reflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ); } void RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { @@ -122,7 +123,7 @@ void RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricCo void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) { - #ifndef STANDARD + #ifdef PHYSICAL float ccDotNV = saturate( dot( geometry.clearCoatNormal, geometry.viewDir ) ); @@ -138,8 +139,6 @@ void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradia #endif float clearCoatInv = 1.0 - clearCoatDHR; - float sheen = material.sheen; - float sheenInv = 1. - sheen; // Both indirect specular and diffuse light accumulate here // if energy preservation enabled, and PMREM provided. @@ -150,28 +149,12 @@ void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradia BRDF_Specular_Multiscattering_Environment( geometry, material.specularColor, material.specularRoughness, singleScattering, multiScattering ); - vec3 diffuse = material.diffuseColor * mix( - ( 1.0 - ( singleScattering + multiScattering ) ), - vec3(0), - sheen - ); + vec3 diffuse = material.diffuseColor * ( 1.0 - ( singleScattering + multiScattering ) ); - reflectedLight.indirectSpecular += sheenInv * clearCoatInv * radiance * singleScattering; - reflectedLight.indirectDiffuse += sheenInv * multiScattering * cosineWeightedIrradiance; + reflectedLight.indirectSpecular += clearCoatInv * radiance * singleScattering; + reflectedLight.indirectDiffuse += multiScattering * cosineWeightedIrradiance; reflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance; - #ifndef STANDARD - - reflectedLight.indirectSpecular += sheenInv * clearCoatInv * radiance * BRDF_Specular_GGX_Environment( geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness ); - - #endif - - reflectedLight.indirectSpecular += sheen * cosineWeightedIrradiance * BRDF_Specular_Sheen_Environment( - geometry, - material.diffuseColor, - material.specularRoughness - ); - } #define RE_Direct RE_Direct_Physical diff --git a/src/renderers/shaders/ShaderLib.js b/src/renderers/shaders/ShaderLib.js index c425aa148443bf..217e5bc9b2b123 100644 --- a/src/renderers/shaders/ShaderLib.js +++ b/src/renderers/shaders/ShaderLib.js @@ -275,7 +275,7 @@ ShaderLib.physical = { { clearCoat: { value: 0 }, clearCoatRoughness: { value: 0 }, - sheen: { value: 0 }, + sheenColor: { value: new Color( 0x000000 ) }, dfgLut: { value: null }, clearCoatNormalScale: { value: new Vector2( 1, 1 ) }, clearCoatNormalMap: { value: null }, diff --git a/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js b/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js index 1a63ceb9b5a96e..73b49fdaef6dae 100644 --- a/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js +++ b/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js @@ -6,14 +6,16 @@ uniform vec3 emissive; uniform float roughness; uniform float metalness; uniform float opacity; -uniform float sheen; -uniform sampler2D dfgLut; #ifndef STANDARD uniform float clearCoat; uniform float clearCoatRoughness; #endif +#ifdef USE_SHEEN + uniform vec3 sheenColor; +#endif + varying vec3 vViewPosition; #ifndef FLAT_SHADED diff --git a/src/renderers/webgl/WebGLProgram.js b/src/renderers/webgl/WebGLProgram.js index a05bf4a15b9ab0..e981a381c220f8 100644 --- a/src/renderers/webgl/WebGLProgram.js +++ b/src/renderers/webgl/WebGLProgram.js @@ -514,6 +514,8 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters, parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', parameters.alphaMap ? '#define USE_ALPHAMAP' : '', + parameters.sheen ? '#define USE_SHEEN' : '', + parameters.vertexTangents ? '#define USE_TANGENT' : '', parameters.vertexColors ? '#define USE_COLOR' : '', diff --git a/src/renderers/webgl/WebGLPrograms.js b/src/renderers/webgl/WebGLPrograms.js index f3ac364f18c6aa..934e8f531587e0 100644 --- a/src/renderers/webgl/WebGLPrograms.js +++ b/src/renderers/webgl/WebGLPrograms.js @@ -37,7 +37,8 @@ function WebGLPrograms( renderer, extensions, capabilities ) { "maxMorphTargets", "maxMorphNormals", "premultipliedAlpha", "numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights", "shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights', - "alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering" + "alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering", + "sheen" ]; @@ -162,6 +163,8 @@ function WebGLPrograms( renderer, extensions, capabilities ) { gradientMap: !! material.gradientMap, + sheen: !!material.sheenColor, + combine: material.combine, vertexTangents: ( material.normalMap && material.vertexTangents ), From 22fce3b128f62344b11834b165ad4da53e21bb67 Mon Sep 17 00:00:00 2001 From: Daniel Sturk Date: Tue, 20 Aug 2019 14:36:09 -0400 Subject: [PATCH 19/22] fixed StandardNodeMaterial's sheen --- .../nodes/materials/StandardNodeMaterial.js | 2 +- .../jsm/nodes/materials/nodes/StandardNode.js | 18 +++--- examples/webgl_materials_nodes.html | 10 --- examples/webgl_materials_sheen.html | 61 +++++++++++++++---- .../lights_physical_pars_fragment.glsl.js | 2 +- 5 files changed, 61 insertions(+), 32 deletions(-) diff --git a/examples/jsm/nodes/materials/StandardNodeMaterial.js b/examples/jsm/nodes/materials/StandardNodeMaterial.js index f574ff39015b57..fae44b8ac7e552 100644 --- a/examples/jsm/nodes/materials/StandardNodeMaterial.js +++ b/examples/jsm/nodes/materials/StandardNodeMaterial.js @@ -36,7 +36,7 @@ NodeUtils.addShortcuts( StandardNodeMaterial.prototype, 'fragment', [ 'environment', 'mask', 'position', - 'sheen' + 'sheenColor' ] ); export { StandardNodeMaterial }; diff --git a/examples/jsm/nodes/materials/nodes/StandardNode.js b/examples/jsm/nodes/materials/nodes/StandardNode.js index ae78868c042d7b..880f22ca107c28 100644 --- a/examples/jsm/nodes/materials/nodes/StandardNode.js +++ b/examples/jsm/nodes/materials/nodes/StandardNode.js @@ -32,7 +32,7 @@ StandardNode.prototype.build = function ( builder ) { var code; - builder.define( this.clearCoat || this.clearCoatRoughness || this.sheen ? 'PHYSICAL' : 'STANDARD' ); + builder.define( this.clearCoat || this.clearCoatRoughness ? 'PHYSICAL' : 'STANDARD' ); if ( this.energyPreservation ) builder.define( 'ENERGY_PRESERVATION' ); @@ -162,17 +162,17 @@ StandardNode.prototype.build = function ( builder ) { // isolate environment from others inputs ( see TextureNode, CubeTextureNode ) // environment.analyze will detect if there is a need of calculate irradiance - this.environment.analyze( builder, { cache: 'radiance', context: contextEnvironment, slot: 'radiance' } ); + this.environment.analyze( builder, { cache: 'radiance', context: contextEnvironment, slot: 'radiance' } ); if ( builder.requires.irradiance ) { - this.environment.analyze( builder, { cache: 'irradiance', context: contextEnvironment, slot: 'irradiance' } ); + this.environment.analyze( builder, { cache: 'irradiance', context: contextEnvironment, slot: 'irradiance' } ); } } - if ( this.sheen ) this.sheen.analyze( builder ); + if ( this.sheenColor ) this.sheenColor.analyze( builder ); // build code @@ -216,7 +216,7 @@ StandardNode.prototype.build = function ( builder ) { var clearCoatEnv = useClearCoat && environment ? this.environment.flow( builder, 'c', { cache: 'clearCoat', context: contextEnvironment, slot: 'environment' } ) : undefined; - var sheen = ! builder.isDefined( 'STANDARD' ) && this.sheen ? this.sheen.flow( builder, 'f' ) : undefined; + var sheenColor = this.sheenColor ? this.sheenColor.flow( builder, 'c' ) : undefined; builder.requires.transparent = alpha !== undefined; @@ -328,9 +328,9 @@ StandardNode.prototype.build = function ( builder ) { } - if ( sheen ) { + if ( sheenColor ) { - output.push( 'material.sheen = ' + sheen.result + ';' ); + output.push( 'material.sheenColor = ' + sheenColor.result + ';' ); } @@ -506,7 +506,7 @@ StandardNode.prototype.copy = function ( source ) { if ( source.environment ) this.environment = source.environment; - if ( source.sheen ) this.sheen = source.sheen; + if ( source.sheenColor ) this.sheenColor = source.sheenColor; return this; @@ -551,7 +551,7 @@ StandardNode.prototype.toJSON = function ( meta ) { if ( this.environment ) data.environment = this.environment.toJSON( meta ).uuid; - if ( this.sheen ) data.sheen = this.sheen.toJSON( meta ).uuid; + if ( this.sheenColor ) data.sheenColor = this.sheenColor.toJSON( meta ).uuid; } diff --git a/examples/webgl_materials_nodes.html b/examples/webgl_materials_nodes.html index d003fd3b2099e9..26bd064d10bfb8 100644 --- a/examples/webgl_materials_nodes.html +++ b/examples/webgl_materials_nodes.html @@ -800,8 +800,6 @@ Nodes.OperatorNode.MUL ); - var sheen = new Nodes.FloatNode(.5); - mtl.color = new Nodes.ColorNode( 0xEEEEEE ); mtl.roughness = roughness; mtl.metalness = metalness; @@ -812,8 +810,6 @@ mtl.normal = new Nodes.NormalMapNode( new Nodes.TextureNode( getTexture( "grassNormal" ) ) ); mtl.normal.scale = normalMask; - mtl.sheen = sheen; - // GUI addGui( 'color', mtl.color.value.getHex(), function ( val ) { @@ -870,12 +866,6 @@ }, false, 0, 1 ); - addGui( 'sheen', sheen.value, function ( val ) { - - sheen.value = val; - - }, false, 0, 1 ); - break; case 'wave': diff --git a/examples/webgl_materials_sheen.html b/examples/webgl_materials_sheen.html index 5b275f48f4b1bd..5c93df8d7a8251 100644 --- a/examples/webgl_materials_sheen.html +++ b/examples/webgl_materials_sheen.html @@ -20,6 +20,8 @@ import * as THREE from '../build/three.module.js'; + import * as Nodes from './jsm/nodes/Nodes.js'; + import Stats from './jsm/libs/stats.module.js'; import { GUI } from './jsm/libs/dat.gui.module.js'; @@ -28,10 +30,12 @@ import { FBXLoader } from './jsm/loaders/FBXLoader.js'; // Graphics variables - var camera, controls, scene, renderer, mesh, stats; + var camera, controls, scene, renderer, stats; var directionalLight; + var mesh, sphere, material, nodeMaterial; var params = { + nodeMaterial: true, color: new THREE.Color( 255, 0, 127 ), sheenBRDF: true, sheenColor: new THREE.Color( 10, 10, 10 ), // corresponds to .04 reflectance @@ -55,15 +59,28 @@ scene = new THREE.Scene(); scene.background = new THREE.Color( 0xbfd1e5 ); - mesh.material = new THREE.MeshPhysicalMaterial(); - mesh.material.side = THREE.DoubleSide; - mesh.material.metalness = 0; mesh.scale.multiplyScalar( .5 ); scene.add( mesh ); - var sphere = new THREE.Mesh( + // + + material = new THREE.MeshPhysicalMaterial(); + material.side = THREE.DoubleSide; + material.metalness = 0; + + // + + nodeMaterial = new Nodes.StandardNodeMaterial(); + nodeMaterial.side = THREE.DoubleSide; + nodeMaterial.metalness = new Nodes.FloatNode( 0 ); + nodeMaterial.roughness = new Nodes.FloatNode(); + nodeMaterial.color = new Nodes.ColorNode( params.color.clone() ); + + // + + sphere = new THREE.Mesh( new THREE.SphereBufferGeometry( 1, 100, 100 ), - mesh.material + material ); scene.add(sphere); @@ -101,6 +118,7 @@ var gui = new GUI(); + gui.add( params, 'nodeMaterial' ); gui.addColor( params, 'color' ); gui.add( params, 'sheenBRDF' ); gui.addColor( params, 'sheenColor' ); @@ -132,15 +150,36 @@ function render() { - mesh.material.sheenColor = params.sheenBRDF + mesh.material = sphere.material = params.nodeMaterial + ? nodeMaterial + : material; + + // + + material.sheenColor = params.sheenBRDF ? new THREE.Color().copy( params.sheenColor ).multiplyScalar( 1 / 255 ) : null; - mesh.material.color.copy(params.color).multiplyScalar( 1 / 255 ); - mesh.material.roughness = params.roughness; - renderer.toneMappingExposure = params.exposure; - mesh.material.needsUpdate = true; + material.color.copy( params.color ).multiplyScalar( 1 / 255 ); + material.roughness = params.roughness; + material.needsUpdate = true; + + // + + nodeMaterial.sheenColor = params.sheenBRDF + ? new Nodes.ColorNode( material.sheenColor ) + : undefined; + + nodeMaterial.color.value.copy( material.color ); + + nodeMaterial.roughness.value = params.roughness; + + nodeMaterial.needsCompile = true; + + // + + renderer.toneMappingExposure = params.exposure; renderer.render( scene, camera ); } diff --git a/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js index 5a4421eafedf46..5dbb78621d6f0d 100644 --- a/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +++ b/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js @@ -107,7 +107,7 @@ void RE_Direct_Physical( const in IncidentLight directLight, const in GeometricC material.specularRoughness, directLight.direction, geometry, - sheenColor + material.sheenColor ); #else reflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness); From 796c5b3f91a85d6c18d41547416ba14057930ce7 Mon Sep 17 00:00:00 2001 From: Daniel Sturk Date: Tue, 20 Aug 2019 14:38:27 -0400 Subject: [PATCH 20/22] removed DFG LUT for IBL sheen --- examples/textures/dfg.png | Bin 7471 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 examples/textures/dfg.png diff --git a/examples/textures/dfg.png b/examples/textures/dfg.png deleted file mode 100644 index ec8f2cc702c78fff46adea9e823ee38c29c58527..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7471 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 gG8XZzZ=D26WQQ Date: Tue, 20 Aug 2019 14:43:22 -0400 Subject: [PATCH 21/22] Removed Sheen IBL DFG LUT from ShaderLib --- src/renderers/shaders/ShaderLib.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/renderers/shaders/ShaderLib.js b/src/renderers/shaders/ShaderLib.js index 217e5bc9b2b123..a6137bb97aef61 100644 --- a/src/renderers/shaders/ShaderLib.js +++ b/src/renderers/shaders/ShaderLib.js @@ -276,7 +276,6 @@ ShaderLib.physical = { clearCoat: { value: 0 }, clearCoatRoughness: { value: 0 }, sheenColor: { value: new Color( 0x000000 ) }, - dfgLut: { value: null }, clearCoatNormalScale: { value: new Vector2( 1, 1 ) }, clearCoatNormalMap: { value: null }, } From 7b14d5cbb2d1e956757febeae84e29e555cb1236 Mon Sep 17 00:00:00 2001 From: Daniel Sturk Date: Tue, 20 Aug 2019 14:50:30 -0400 Subject: [PATCH 22/22] fixed formatting --- src/materials/MeshPhysicalMaterial.js | 2 +- src/renderers/WebGLRenderer.js | 2 +- src/renderers/webgl/WebGLPrograms.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/materials/MeshPhysicalMaterial.js b/src/materials/MeshPhysicalMaterial.js index 55f3a34caed0d9..d6c0e22e772e6a 100644 --- a/src/materials/MeshPhysicalMaterial.js +++ b/src/materials/MeshPhysicalMaterial.js @@ -55,7 +55,7 @@ MeshPhysicalMaterial.prototype.copy = function ( source ) { this.clearCoat = source.clearCoat; this.clearCoatRoughness = source.clearCoatRoughness; - if( source.sheenColor ) this.sheenColor = ( this.sheenColor || new Color() ).copy( source.sheenColor ); + if ( source.sheenColor ) this.sheenColor = ( this.sheenColor || new Color() ).copy( source.sheenColor ); else this.sheenColor = null; this.clearCoatNormalMap = source.clearCoatNormalMap; diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index 4810dd21cfe6f5..205ed91502a322 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -2271,7 +2271,7 @@ function WebGLRenderer( parameters ) { uniforms.clearCoat.value = material.clearCoat; uniforms.clearCoatRoughness.value = material.clearCoatRoughness; - if( material.sheenColor ) uniforms.sheenColor.value.copy( material.sheenColor ); + if ( material.sheenColor ) uniforms.sheenColor.value.copy( material.sheenColor ); if ( material.clearCoatNormalMap ) { diff --git a/src/renderers/webgl/WebGLPrograms.js b/src/renderers/webgl/WebGLPrograms.js index a87b89f5d4b73f..ddf9c9f0b621bf 100644 --- a/src/renderers/webgl/WebGLPrograms.js +++ b/src/renderers/webgl/WebGLPrograms.js @@ -163,7 +163,7 @@ function WebGLPrograms( renderer, extensions, capabilities ) { gradientMap: !! material.gradientMap, - sheen: !!material.sheenColor, + sheen: !! material.sheenColor, combine: material.combine,