浏览代码

wip: proof of concept sheen IBL, needs cleanup (at least)

Daniel Sturk 6 年之前
父节点
当前提交
52ef062102

二进制
examples/textures/dfg.png


+ 68 - 20
examples/webgl_materials_sheen.html

@@ -27,13 +27,23 @@
 
 			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 params = {
-				sheen: .5,
+				sheen: .8,
 				hue: 265,
-				roughness: .9
+				roughness: .9,
+				exposure: 2,
+				envMap: true,
+				directionalLight: false,
+				ambientLight: false
 			};
 
 			// model
@@ -53,9 +63,17 @@
 				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(
+					new THREE.SphereBufferGeometry( 1, 100, 100 ),
+					mesh.material
+				);
+				scene.add(sphere);
+
 				camera.position.set( - 12, 7, 4 );
 
 				var container = document.getElementById( 'container' );
@@ -65,31 +83,51 @@
 				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();
 
-				var ambientLight = new THREE.AmbientLight( 0x404040 );
+				ambientLight = new THREE.AmbientLight( 0x404040 );
 				scene.add( ambientLight );
 
-				var light = new THREE.DirectionalLight( 0xffffff, 1.5 );
-				light.position.set( - 7, 30, 15 );
-				light.castShadow = true;
-
-				var d = 10;
-				light.shadow.camera.left = - d;
-				light.shadow.camera.right = d;
-				light.shadow.camera.top = d;
-				light.shadow.camera.bottom = - d;
+				directionalLight = new THREE.DirectionalLight( 0xffffff, 1.5 );
+				directionalLight.position.set( 0, 10, 0 );
+				directionalLight.castShadow = true;
+				directionalLight.add(
+					new THREE.Mesh(
+						new THREE.SphereBufferGeometry( .5 ),
+						new THREE.MeshBasicMaterial( { color: 0xffffff } )
+					)
+				);
 
-				light.shadow.camera.near = 2;
-				light.shadow.camera.far = 50;
-
-				light.shadow.mapSize.x = 1024;
-				light.shadow.mapSize.y = 1024;
-
-				light.shadow.bias = - 0.003;
-				scene.add( light );
+				scene.add( directionalLight );
 
 				stats = new Stats();
 				stats.domElement.style.position = 'absolute';
@@ -103,6 +141,10 @@
 				gui.add( params, 'sheen', 0, 1 );
 				gui.add( params, 'hue', 0, 360 );
 				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();
@@ -132,6 +174,12 @@
 				mesh.material.sheen = params.sheen;
 				mesh.material.color = new THREE.Color().setHSL(params.hue / 360, 1, .5);
 				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;
+
 				renderer.render( scene, camera );
 
 			}

+ 1 - 0
src/renderers/WebGLRenderer.js

@@ -2273,6 +2273,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.clearCoatNormalMap ) {
 

+ 6 - 4
src/renderers/shaders/ShaderChunk/bsdfs.glsl.js

@@ -352,18 +352,20 @@ float V_Neubelt(float NoV, float NoL) {
 	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 BRDF_Specular_Sheen( const in float roughness, const in vec3 L, const in GeometricContext geometry, vec3 specularColor ) {
 
 	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 specularColor * D_Charlie( roughness, dotNH ) * V_Neubelt( dot(N, V), dot(N, L) );
 
-	return D_Charlie( sheen, dot(N, H) ) * V_Neubelt( dot(N, V), dot(N, L) );
+}
 
+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;
 }
 `;

+ 30 - 29
src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js

@@ -99,31 +99,20 @@ void RE_Direct_Physical( const in IncidentLight directLight, const in GeometricC
 
 	#endif
 
-	reflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness );
-
-	float sheenMix;
-
-	#ifndef STANDARD
-
-		float sheenFactor = material.sheen;
-		if( sheenFactor == 0. ) sheenMix = 0.;
-		else sheenMix = 1. - pow( 1. - sheenFactor, 5. );
-
-	#else
-
-		sheenMix = 0.;
-
-	#endif
-
-	reflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * (1. - sheenMix) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );
-
-	#ifndef STANDARD
-
-		// avoid expensive calculation
-		if(sheenMix > 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

+ 1 - 0
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 },
 		}

+ 1 - 0
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;