Browse Source

Logical separation of clearcoat normal from geometry normal

Added the option to use a clearcoat normal independent from the (maybe) perturbed geometry normal.
arobertson0 6 years ago
parent
commit
ae375034f7

File diff suppressed because it is too large
+ 0 - 0
build/three.js


File diff suppressed because it is too large
+ 0 - 0
build/three.module.js


+ 271 - 0
examples/_.html

@@ -0,0 +1,271 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+	<title>three.js webgl - materials - normal map [Lee Perry-Smith]</title>
+	<meta charset="utf-8">
+	<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+	<link type="text/css" rel="stylesheet" href="main.css">
+	<style>
+		#vt {
+			display: none
+		}
+
+		#vt,
+		#vt a {
+			color: orange;
+		}
+	</style>
+</head>
+
+<body>
+	<div id="info">
+		<a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - webgl clearcoat geometry normal demo.<br />
+	</div>
+
+	<script type="module">
+
+		import * as THREE from '../build/three.module.js';
+
+		import Stats from './jsm/libs/stats.module.js';
+
+		import { GUI } from './jsm/libs/dat.gui.module.js';
+
+		import { OrbitControls } from './jsm/controls/OrbitControls.js';
+		import { HDRCubeTextureLoader } from './jsm/loaders/HDRCubeTextureLoader.js';
+		import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js';
+		import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js';
+
+		var container, stats, loader;
+
+		var camera, scene, renderer;
+
+		var color = {
+			hue: 0.0,
+		}
+
+		var params = {
+
+			metalness: 0.0,
+			roughness: 0.8,
+			clearCoat: 1.0,
+			clearCoatRoughness: 0.0,
+			reflectivity: 0.0,
+		};
+
+		var particleLight;
+		var meshes = [];
+		var mats = [];
+
+		var windowHalfX = window.innerWidth / 2;
+		var windowHalfY = window.innerHeight / 2;
+
+	new THREE.FontLoader()
+		.load('fonts/gentilis_regular.typeface.json', function (font) {
+
+			init(font);
+			animate();
+
+		});
+
+
+		function init(font) {
+
+			container = document.createElement('div');
+			document.body.appendChild(container);
+
+			camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 10000);
+			camera.position.z = 1200;
+
+			var genCubeUrls = function ( prefix, postfix ) {
+
+				return [
+					prefix + 'px' + postfix, prefix + 'nx' + postfix,
+					prefix + 'py' + postfix, prefix + 'ny' + postfix,
+					prefix + 'pz' + postfix, prefix + 'nz' + postfix
+				];
+
+			};
+
+			scene = new THREE.Scene();
+
+			var hdrUrls = genCubeUrls( './textures/cube/pisaHDR/', '.hdr' );
+
+			new HDRCubeTextureLoader()
+				.setType(THREE.UnsignedByteType)
+				.load(hdrUrls, function (hdrCubeMap) {
+
+					var pmremGenerator = new PMREMGenerator(hdrCubeMap);
+					pmremGenerator.update(renderer);
+
+					var pmremCubeUVPacker = new PMREMCubeUVPacker(pmremGenerator.cubeLods);
+					pmremCubeUVPacker.update(renderer);
+
+					var hdrCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget;
+
+					var geometry = new THREE.SphereBufferGeometry(80, 64, 32);
+
+					var normalMap = new THREE.TextureLoader()
+						.load("models/gltf/LeePerrySmith/Infinite-Level_02_Tangent_SmoothUV.jpg");
+
+					var mat = {
+						envMap: hdrCubeRenderTarget.texture,
+						normalMap: normalMap,
+						normalScale: new THREE.Vector2(0.8, 0.8)
+					};
+
+					for(var i = 0;i<2;i++){
+						mats[i] = new THREE.MeshPhysicalMaterial(mat);
+						meshes[i] = new THREE.Mesh(geometry, mats[i]);
+						meshes[i].position.x  = -100.0+ i*200;
+						scene.add(meshes[i]);
+					}
+
+					mats[0].clearCoat = 1.0;
+
+					mats[1].clearCoat = 1.0;
+					mats[1].clearCoatGeometryNormals = true;
+
+					hdrCubeMap.magFilter = THREE.LinearFilter;
+					hdrCubeMap.needsUpdate = true;
+					scene.background = hdrCubeMap;
+
+					pmremGenerator.dispose();
+					pmremCubeUVPacker.dispose();
+				});
+
+			function addLabel(name, location, fontSize) {
+				fontSize = fontSize | 20;
+				var textGeo = new THREE.TextBufferGeometry(name, {
+
+					font: font,
+					size: fontSize,
+					height: 1,
+					curveSegments: 1
+
+				});
+
+				var textMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff });
+				var textMesh = new THREE.Mesh(textGeo, textMaterial);
+
+				textGeo.computeBoundingBox();
+				var bb = textGeo.boundingBox.clone();
+				//var diag = bb.max.sub(bb.min);
+				var displace = bb.max.sub(bb.min).divide( new THREE.Vector3(2,2,2));
+
+
+
+
+				textMesh.position.copy(location.sub(displace));
+				scene.add(textMesh);
+
+			}
+
+			addLabel("false", new THREE.Vector3(- 100, 110, 0));
+			addLabel("true", new THREE.Vector3(100, 110, 0));
+			addLabel("Use geometry normals", new THREE.Vector3(0, 180, 0),30);
+
+			// LIGHTS
+
+			particleLight = new THREE.Mesh( new THREE.SphereBufferGeometry( 4, 8, 8 ), new THREE.MeshBasicMaterial( { color: 0xffffff } ) );
+			scene.add( particleLight );
+
+			{
+				var ambientLight = new THREE.AmbientLight(0x444444);
+				scene.add(ambientLight);
+			}
+			{
+				var pointLight = new THREE.PointLight(0xffffff, 1.25, 1000);
+				particleLight.add(pointLight);
+			}
+			{
+				var directionalLight = new THREE.DirectionalLight(0xffffff);
+				directionalLight.position.set(1, - 0.5, - 1);
+				scene.add(directionalLight);
+			}
+
+
+			renderer = new THREE.WebGLRenderer();
+			renderer.setSize(window.innerWidth, window.innerHeight);
+			container.appendChild(renderer.domElement);
+
+			//
+
+			renderer.gammaInput = true;
+			renderer.gammaOutput = true;
+
+			//
+
+			stats = new Stats();
+			container.appendChild(stats.dom);
+
+			// EVENTS
+
+			var controls = new OrbitControls( camera, renderer.domElement );
+
+			window.addEventListener('resize', onWindowResize, false);
+
+			var gui = new GUI();
+
+			gui.add( color, 'hue', 0, 1 );
+			gui.add( params, 'metalness', 0, 1 );
+			gui.add( params, 'roughness', 0, 1 );
+			gui.add( params, 'reflectivity', 0, 1 );
+			gui.add( params, 'clearCoat', 0, 1 );
+			gui.add( params, 'clearCoatRoughness', 0, 1 );
+
+			gui.open();
+		}
+
+		//
+
+		function onWindowResize() {
+			var width = window.innerWidth;
+			var height = window.innerHeight;
+
+			camera.aspect = width / height;
+			camera.updateProjectionMatrix();
+
+			renderer.setSize(width, height);
+		}
+
+		//
+
+		function animate() {
+
+			requestAnimationFrame(animate);
+
+			render();
+
+			stats.update();
+
+		}
+
+		function render() {
+
+			var matColor = new THREE.Color().setHSL( color.hue, 0.5, 0.25 );
+			for (var mat of mats) {
+				mat.color = matColor;
+				for (var param in params) {
+					mat[param] = params[param];
+				}
+			}
+
+			var timer = Date.now() * 0.00025;
+			particleLight.position.x = Math.sin( timer * 7 ) * 300;
+			particleLight.position.y = Math.cos( timer * 5 ) * 400;
+			particleLight.position.z = Math.cos( timer * 3 ) * 300;
+
+			for(var mesh of meshes){
+				mesh.rotation.y += 0.005;
+			}
+
+			renderer.render( scene, camera );
+
+		}
+
+	</script>
+
+</body>
+
+</html>

+ 2 - 0
src/materials/MeshPhysicalMaterial.d.ts

@@ -8,6 +8,7 @@ export interface MeshPhysicalMaterialParameters
 	reflectivity?: number;
 	reflectivity?: number;
 	clearCoat?: number;
 	clearCoat?: number;
 	clearCoatRoughness?: number;
 	clearCoatRoughness?: number;
+	clearCoatGeometryNormals?: boolean;
 }
 }
 
 
 export class MeshPhysicalMaterial extends MeshStandardMaterial {
 export class MeshPhysicalMaterial extends MeshStandardMaterial {
@@ -18,5 +19,6 @@ export class MeshPhysicalMaterial extends MeshStandardMaterial {
 	reflectivity: number;
 	reflectivity: number;
 	clearCoat: number;
 	clearCoat: number;
 	clearCoatRoughness: number;
 	clearCoatRoughness: number;
+	clearCoatGeometryNormals?: boolean;
 
 
 }
 }

+ 4 - 0
src/materials/MeshPhysicalMaterial.js

@@ -7,6 +7,7 @@ import { MeshStandardMaterial } from './MeshStandardMaterial.js';
  *  reflectivity: <float>
  *  reflectivity: <float>
  *  clearCoat: <float>
  *  clearCoat: <float>
  *  clearCoatRoughness: <float>
  *  clearCoatRoughness: <float>
+ *  clearCoatGeometryNormals: <boolean>
  * }
  * }
  */
  */
 
 
@@ -23,6 +24,8 @@ function MeshPhysicalMaterial( parameters ) {
 	this.clearCoat = 0.0;
 	this.clearCoat = 0.0;
 	this.clearCoatRoughness = 0.0;
 	this.clearCoatRoughness = 0.0;
 
 
+	this.clearCoatGeometryNormals = false;
+
 	this.setValues( parameters );
 	this.setValues( parameters );
 
 
 }
 }
@@ -42,6 +45,7 @@ MeshPhysicalMaterial.prototype.copy = function ( source ) {
 
 
 	this.clearCoat = source.clearCoat;
 	this.clearCoat = source.clearCoat;
 	this.clearCoatRoughness = source.clearCoatRoughness;
 	this.clearCoatRoughness = source.clearCoatRoughness;
+	this.clearCoatGeometryNormals = source.clearCoatGeometryNormals;
 
 
 	return this;
 	return this;
 
 

+ 1 - 0
src/renderers/WebGLRenderer.js

@@ -2274,6 +2274,7 @@ function WebGLRenderer( parameters ) {
 
 
 		uniforms.clearCoat.value = material.clearCoat;
 		uniforms.clearCoat.value = material.clearCoat;
 		uniforms.clearCoatRoughness.value = material.clearCoatRoughness;
 		uniforms.clearCoatRoughness.value = material.clearCoatRoughness;
+		uniforms.clearCoatGeometryNormals.value = material.clearCoatGeometryNormals;
 
 
 	}
 	}
 
 

+ 1 - 0
src/renderers/shaders/ShaderChunk.d.ts

@@ -83,6 +83,7 @@ export let ShaderChunk: {
 	normal_fragment_maps: string;
 	normal_fragment_maps: string;
 	normal_vert: string;
 	normal_vert: string;
 	normalmap_pars_fragment: string;
 	normalmap_pars_fragment: string;
+	clearcoat_normal_fragment_begin: string;
 	packing: string;
 	packing: string;
 	points_frag: string;
 	points_frag: string;
 	points_vert: string;
 	points_vert: string;

+ 2 - 0
src/renderers/shaders/ShaderChunk.js

@@ -61,6 +61,7 @@ import morphtarget_vertex from './ShaderChunk/morphtarget_vertex.glsl.js';
 import normal_fragment_begin from './ShaderChunk/normal_fragment_begin.glsl.js';
 import normal_fragment_begin from './ShaderChunk/normal_fragment_begin.glsl.js';
 import normal_fragment_maps from './ShaderChunk/normal_fragment_maps.glsl.js';
 import normal_fragment_maps from './ShaderChunk/normal_fragment_maps.glsl.js';
 import normalmap_pars_fragment from './ShaderChunk/normalmap_pars_fragment.glsl.js';
 import normalmap_pars_fragment from './ShaderChunk/normalmap_pars_fragment.glsl.js';
+import clearcoat_normal_fragment_begin from './ShaderChunk/clearcoat_normal_fragment_begin.glsl.js';
 import packing from './ShaderChunk/packing.glsl.js';
 import packing from './ShaderChunk/packing.glsl.js';
 import premultiplied_alpha_fragment from './ShaderChunk/premultiplied_alpha_fragment.glsl.js';
 import premultiplied_alpha_fragment from './ShaderChunk/premultiplied_alpha_fragment.glsl.js';
 import project_vertex from './ShaderChunk/project_vertex.glsl.js';
 import project_vertex from './ShaderChunk/project_vertex.glsl.js';
@@ -183,6 +184,7 @@ export var ShaderChunk = {
 	normal_fragment_begin: normal_fragment_begin,
 	normal_fragment_begin: normal_fragment_begin,
 	normal_fragment_maps: normal_fragment_maps,
 	normal_fragment_maps: normal_fragment_maps,
 	normalmap_pars_fragment: normalmap_pars_fragment,
 	normalmap_pars_fragment: normalmap_pars_fragment,
+	clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin,
 	packing: packing,
 	packing: packing,
 	premultiplied_alpha_fragment: premultiplied_alpha_fragment,
 	premultiplied_alpha_fragment: premultiplied_alpha_fragment,
 	project_vertex: project_vertex,
 	project_vertex: project_vertex,

+ 35 - 1
src/renderers/shaders/ShaderChunk/bsdfs.glsl.js

@@ -1,4 +1,4 @@
-export default /* glsl */`
+export default /* glsl */ `
 
 
 // Analytical approximation of the DFG LUT, one half of the
 // Analytical approximation of the DFG LUT, one half of the
 // split-sum approximation used in indirect specular lighting.
 // split-sum approximation used in indirect specular lighting.
@@ -146,6 +146,29 @@ vec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in Geometric
 
 
 } // validated
 } // validated
 
 
+#ifndef STANDARD
+vec3 BRDF_ClearCoat_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {
+
+	float alpha = pow2( roughness ); // UE4's roughness
+
+	vec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );
+
+	float dotNL = saturate( dot( geometry.clearCoatNormal, incidentLight.direction ) );
+	float dotNV = saturate( dot( geometry.clearCoatNormal, geometry.viewDir ) );
+	float dotNH = saturate( dot( geometry.clearCoatNormal, halfDir ) );
+	float dotLH = saturate( dot( incidentLight.direction, halfDir ) );
+
+	vec3 F = F_Schlick( specularColor, dotLH );
+
+	float G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );
+
+	float D = D_GGX( alpha, dotNH );
+
+	return F * ( G * D );
+
+}
+#endif
+
 // Rect Area Light
 // Rect Area Light
 
 
 // Real-Time Polygonal-Light Shading with Linearly Transformed Cosines
 // Real-Time Polygonal-Light Shading with Linearly Transformed Cosines
@@ -274,6 +297,17 @@ vec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in
 
 
 } // validated
 } // validated
 
 
+#ifndef STANDARD
+vec3 BRDF_ClearCoat_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {
+
+	float dotNV = saturate( dot( geometry.clearCoatNormal, geometry.viewDir ) );
+
+	vec2 brdf = integrateSpecularBRDF( dotNV, roughness );
+
+	return specularColor * brdf.x + brdf.y;
+}
+#endif
+
 // Fdez-Agüera's "Multiple-Scattering Microfacet Model for Real-Time Image Based Lighting"
 // Fdez-Agüera's "Multiple-Scattering Microfacet Model for Real-Time Image Based Lighting"
 // Approximates multiscattering in order to preserve energy.
 // Approximates multiscattering in order to preserve energy.
 // http://www.jcgt.org/published/0008/01/03/
 // http://www.jcgt.org/published/0008/01/03/

+ 10 - 0
src/renderers/shaders/ShaderChunk/clearcoat_normal_fragment_begin.glsl.js

@@ -0,0 +1,10 @@
+export default /* glsl */ `
+
+#ifndef STANDARD
+
+vec3 clearCoatNormal = clearCoatGeometryNormals ?
+  geometryNormal: // use the unperturbed normal of the geometry
+  normal; // Use the (maybe) perturbed normal
+
+#endif
+`;

+ 5 - 1
src/renderers/shaders/ShaderChunk/common.glsl.js

@@ -1,4 +1,4 @@
-export default /* glsl */`
+export default /* glsl */ `
 #define PI 3.14159265359
 #define PI 3.14159265359
 #define PI2 6.28318530718
 #define PI2 6.28318530718
 #define PI_HALF 1.5707963267949
 #define PI_HALF 1.5707963267949
@@ -39,6 +39,10 @@ struct GeometricContext {
 	vec3 position;
 	vec3 position;
 	vec3 normal;
 	vec3 normal;
 	vec3 viewDir;
 	vec3 viewDir;
+
+  #ifndef STANDARD
+	vec3 clearCoatNormal;
+  #endif
 };
 };
 
 
 vec3 transformDirection( in vec3 dir, in mat4 matrix ) {
 vec3 transformDirection( in vec3 dir, in mat4 matrix ) {

+ 4 - 4
src/renderers/shaders/ShaderChunk/envmap_physical_pars_fragment.glsl.js

@@ -1,4 +1,4 @@
-export default /* glsl */`
+export default /* glsl */ `
 #if defined( USE_ENVMAP ) && defined( PHYSICAL )
 #if defined( USE_ENVMAP ) && defined( PHYSICAL )
 
 
 	vec3 getLightProbeIndirectIrradiance( /*const in SpecularLightProbe specularLightProbe,*/ const in GeometricContext geometry, const in int maxMIPLevel ) {
 	vec3 getLightProbeIndirectIrradiance( /*const in SpecularLightProbe specularLightProbe,*/ const in GeometricContext geometry, const in int maxMIPLevel ) {
@@ -54,15 +54,15 @@ export default /* glsl */`
 
 
 	}
 	}
 
 
-	vec3 getLightProbeIndirectRadiance( /*const in SpecularLightProbe specularLightProbe,*/ const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {
+	vec3 getLightProbeIndirectRadiance( /*const in SpecularLightProbe specularLightProbe,*/ const in vec3 viewDir, const in vec3 normal, const in float blinnShininessExponent, const in int maxMIPLevel ) {
 
 
 		#ifdef ENVMAP_MODE_REFLECTION
 		#ifdef ENVMAP_MODE_REFLECTION
 
 
-			vec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );
+		  vec3 reflectVec = reflect( -viewDir, normal );
 
 
 		#else
 		#else
 
 
-			vec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );
+		  vec3 reflectVec = refract( -viewDir, normal, refractionRatio );
 
 
 		#endif
 		#endif
 
 

+ 4 - 1
src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js

@@ -1,4 +1,4 @@
-export default /* glsl */`
+export default /* glsl */ `
 /**
 /**
  * This is a template that can be used to light a material, it uses pluggable
  * This is a template that can be used to light a material, it uses pluggable
  * RenderEquations (RE)for specific lighting scenarios.
  * RenderEquations (RE)for specific lighting scenarios.
@@ -20,6 +20,9 @@ geometry.position = - vViewPosition;
 geometry.normal = normal;
 geometry.normal = normal;
 geometry.viewDir = normalize( vViewPosition );
 geometry.viewDir = normalize( vViewPosition );
 
 
+#ifndef STANDARD
+geometry.clearCoatNormal = clearCoatNormal;
+#endif
 IncidentLight directLight;
 IncidentLight directLight;
 
 
 #if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )
 #if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )

+ 3 - 3
src/renderers/shaders/ShaderChunk/lights_fragment_maps.glsl.js

@@ -1,4 +1,4 @@
-export default /* glsl */`
+export default /* glsl */ `
 #if defined( RE_IndirectDiffuse )
 #if defined( RE_IndirectDiffuse )
 
 
 	#ifdef USE_LIGHTMAP
 	#ifdef USE_LIGHTMAP
@@ -25,10 +25,10 @@ export default /* glsl */`
 
 
 #if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )
 #if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )
 
 
-	radiance += getLightProbeIndirectRadiance( /*specularLightProbe,*/ geometry, Material_BlinnShininessExponent( material ), maxMipLevel );
+  radiance += getLightProbeIndirectRadiance( /*specularLightProbe,*/ geometry.viewDir, geometry.normal, Material_BlinnShininessExponent( material ), maxMipLevel );
 
 
 	#ifndef STANDARD
 	#ifndef STANDARD
-		clearCoatRadiance += getLightProbeIndirectRadiance( /*specularLightProbe,*/ geometry, Material_ClearCoat_BlinnShininessExponent( material ), maxMipLevel );
+	  clearCoatRadiance += getLightProbeIndirectRadiance( /*specularLightProbe,*/ geometry.viewDir, geometry.clearCoatNormal,Material_ClearCoat_BlinnShininessExponent( material ), maxMipLevel );
 	#endif
 	#endif
 
 
 #endif
 #endif

+ 3 - 3
src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js

@@ -1,4 +1,4 @@
-export default /* glsl */`
+export default /* glsl */ `
 struct PhysicalMaterial {
 struct PhysicalMaterial {
 
 
 	vec3	diffuseColor;
 	vec3	diffuseColor;
@@ -88,7 +88,7 @@ void RE_Direct_Physical( const in IncidentLight directLight, const in GeometricC
 
 
 	#ifndef STANDARD
 	#ifndef STANDARD
 
 
-		reflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );
+		reflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_ClearCoat_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );
 
 
 	#endif
 	#endif
 
 
@@ -142,7 +142,7 @@ void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradia
 
 
 	#ifndef STANDARD
 	#ifndef STANDARD
 
 
-		reflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );
+	reflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_ClearCoat_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );
 
 
 	#endif
 	#endif
 }
 }

+ 4 - 1
src/renderers/shaders/ShaderChunk/normal_fragment_begin.glsl.js

@@ -1,4 +1,4 @@
-export default /* glsl */`
+export default /* glsl */ `
 #ifdef FLAT_SHADED
 #ifdef FLAT_SHADED
 
 
 	// Workaround for Adreno/Nexus5 not able able to do dFdx( vViewPosition ) ...
 	// Workaround for Adreno/Nexus5 not able able to do dFdx( vViewPosition ) ...
@@ -32,4 +32,7 @@ export default /* glsl */`
 	#endif
 	#endif
 
 
 #endif
 #endif
+#ifndef STANDARD
+	vec3 geometryNormal = normal;
+#endif
 `;
 `;

+ 2 - 1
src/renderers/shaders/ShaderLib.js

@@ -273,7 +273,8 @@ ShaderLib.physical = {
 		ShaderLib.standard.uniforms,
 		ShaderLib.standard.uniforms,
 		{
 		{
 			clearCoat: { value: 0 },
 			clearCoat: { value: 0 },
-			clearCoatRoughness: { value: 0 }
+			clearCoatRoughness: { value: 0 },
+			clearCoatGeometryNormals: { value: false },
 		}
 		}
 	] ),
 	] ),
 
 

+ 3 - 1
src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js

@@ -1,4 +1,4 @@
-export default /* glsl */`
+export default /* glsl */ `
 #define PHYSICAL
 #define PHYSICAL
 
 
 uniform vec3 diffuse;
 uniform vec3 diffuse;
@@ -10,6 +10,7 @@ uniform float opacity;
 #ifndef STANDARD
 #ifndef STANDARD
 	uniform float clearCoat;
 	uniform float clearCoat;
 	uniform float clearCoatRoughness;
 	uniform float clearCoatRoughness;
+	uniform bool clearCoatGeometryNormals;
 #endif
 #endif
 
 
 varying vec3 vViewPosition;
 varying vec3 vViewPosition;
@@ -70,6 +71,7 @@ void main() {
 	#include <metalnessmap_fragment>
 	#include <metalnessmap_fragment>
 	#include <normal_fragment_begin>
 	#include <normal_fragment_begin>
 	#include <normal_fragment_maps>
 	#include <normal_fragment_maps>
+	#include <clearcoat_normal_fragment_begin>
 	#include <emissivemap_fragment>
 	#include <emissivemap_fragment>
 
 
 	// accumulation
 	// accumulation

Some files were not shown because too many files changed in this diff