Forráskód Böngészése

Working on CC normal impl

Created a separate variable for cc normal, independent perturb implementations
arobertson0 6 éve
szülő
commit
1778a779ff
28 módosított fájl, 454 hozzáadás és 173 törlés
  1. 0 0
      build/three.js
  2. 0 0
      build/three.module.js
  3. 127 57
      examples/_.html
  4. BIN
      examples/textures/nvidia_tentacle/tentacle_object_space.png
  5. BIN
      examples/textures/nvidia_tentacle/tentacle_tangent_space.png
  6. 1 1
      package-lock.json
  7. 11 0
      src/materials/MeshPhysicalMaterial.d.ts
  8. 13 0
      src/materials/MeshPhysicalMaterial.js
  9. 97 93
      src/renderers/WebGLRenderer.js
  10. 2 0
      src/renderers/shaders/ShaderChunk.d.ts
  11. 4 0
      src/renderers/shaders/ShaderChunk.js
  12. 8 3
      src/renderers/shaders/ShaderChunk/clearcoat_normal_fragment_begin.glsl.js
  13. 79 0
      src/renderers/shaders/ShaderChunk/clearcoat_normal_fragment_maps.glsl.js
  14. 80 0
      src/renderers/shaders/ShaderChunk/clearcoat_normalmap_pars_fragment.glsl.js
  15. 1 1
      src/renderers/shaders/ShaderChunk/envmap_fragment.glsl.js
  16. 2 2
      src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl.js
  17. 1 1
      src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl.js
  18. 1 1
      src/renderers/shaders/ShaderChunk/envmap_vertex.glsl.js
  19. 6 4
      src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js
  20. 2 2
      src/renderers/shaders/ShaderChunk/uv_pars_fragment.glsl.js
  21. 1 1
      src/renderers/shaders/ShaderChunk/uv_pars_vertex.glsl.js
  22. 1 1
      src/renderers/shaders/ShaderChunk/uv_vertex.glsl.js
  23. 3 0
      src/renderers/shaders/ShaderLib.js
  24. 2 0
      src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js
  25. 1 1
      src/renderers/shaders/ShaderLib/normal_frag.glsl.js
  26. 3 3
      src/renderers/shaders/ShaderLib/normal_vert.glsl.js
  27. 5 1
      src/renderers/webgl/WebGLProgram.js
  28. 3 1
      src/renderers/webgl/WebGLPrograms.js

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
build/three.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
build/three.module.js


+ 127 - 57
examples/_.html

@@ -20,7 +20,8 @@
 
 <body>
 	<div id="info">
-		<a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - webgl clearcoat geometry normal demo.<br />
+		<a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - webgl clearcoat geometry normal
+		demo.<br />
 	</div>
 
 	<script type="module">
@@ -40,33 +41,68 @@
 
 		var camera, scene, renderer;
 
-		var color = {
-			hue: 0.0,
-		}
-
-		var params = {
-
+		var guiParams = {
 			metalness: 0.0,
-			roughness: 0.8,
+			roughness: 1.0,
 			clearCoat: 1.0,
 			clearCoatRoughness: 0.0,
 			reflectivity: 0.0,
 		};
 
+		var guiNormalMapNames = [
+			"face",
+			"tentacle"
+		]
+
+		var guiMatParams = {
+			normalMap: "face",
+			normalScale: 1.0,
+			clearCoatNormalMap: "tentacle",
+			clearCoatNormalScale: 1.0,
+		}
+
 		var particleLight;
 		var meshes = [];
 		var mats = [];
+		var normalMaps = {};
 
 		var windowHalfX = window.innerWidth / 2;
 		var windowHalfY = window.innerHeight / 2;
 
-	new THREE.FontLoader()
-		.load('fonts/gentilis_regular.typeface.json', function (font) {
+		const sphereSize = 80;
+		const sphereSpacing = 1.25 * sphereSize * 2;
+
+		const variationsX = [
+			(mat, scale, map) => { },
+			(mat, scale, map) => { mat.clearCoatNormalScale = new THREE.Vector2(scale, scale); },
+			(mat, scale, map) => {
+				mat.clearCoatNormalScale = new THREE.Vector2(scale, scale);
+				if (mat.clearCoatNormalMap !== map) {
+					mat.clearCoatNormalMap = map;
+					mat.needsUpdate = true;
+				}
+			},
+		];
+
+		const variationsY = [
+			(mat, scale, map) => { },
+			(mat, scale, map) => {
+				mat.normalScale = new THREE.Vector2(scale, scale);
+				if (mat.normalMap !== map) {
+					mat.normalMap = map;
+					mat.needsUpdate = true;
+				}
+			},
+		];
 
-			init(font);
-			animate();
+		const maxI = variationsX.length;
+		const maxJ = variationsY.length;
 
-		});
+		new THREE.FontLoader()
+			.load('fonts/gentilis_regular.typeface.json', function (font) {
+				init(font);
+				animate();
+			});
 
 
 		function init(font) {
@@ -75,9 +111,9 @@
 			document.body.appendChild(container);
 
 			camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 10000);
-			camera.position.z = 1200;
+			camera.position.z = 1500;
 
-			var genCubeUrls = function ( prefix, postfix ) {
+			var genCubeUrls = function (prefix, postfix) {
 
 				return [
 					prefix + 'px' + postfix, prefix + 'nx' + postfix,
@@ -89,7 +125,7 @@
 
 			scene = new THREE.Scene();
 
-			var hdrUrls = genCubeUrls( './textures/cube/pisaHDR/', '.hdr' );
+			var hdrUrls = genCubeUrls('./textures/cube/pisaHDR/', '.hdr');
 
 			new HDRCubeTextureLoader()
 				.setType(THREE.UnsignedByteType)
@@ -105,26 +141,39 @@
 
 					var geometry = new THREE.SphereBufferGeometry(80, 64, 32);
 
-					var normalMap = new THREE.TextureLoader()
+					var textureLoader = new THREE.TextureLoader();
+
+					normalMaps.tentacle = textureLoader
+						.load("textures/nvidia_tentacle/tentacle_tangent_space.png");
+
+					normalMaps.face = textureLoader
 						.load("models/gltf/LeePerrySmith/Infinite-Level_02_Tangent_SmoothUV.jpg");
 
-					var mat = {
+					// objectNormalMap = textureLoader
+					// 	.load("textures/nvidia_tentacle/tentacle_object_space.png");
+
+					var matParams = {
 						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;
+					for (var ii = 0; ii < maxI; ii++) {
+						if (!mats[ii]) {
+							mats[ii] = [];
+						}
+						for (var jj = 0; jj < maxJ; jj++) {
+
+							var mat = mats[ii][jj] = new THREE.MeshPhysicalMaterial(matParams);
+
+							variationsX[ii](mat, 1, normalMaps.tentacle);
+							variationsY[jj](mat, 1, normalMaps.face);
+							var mesh = new THREE.Mesh(geometry, mat);
 
-					mats[1].clearCoat = 1.0;
-					mats[1].clearCoatGeometryNormals = true;
+							mesh.position.x = (ii - (maxI - 1) / 2) * sphereSpacing;
+							mesh.position.y = (jj - (maxJ - 1) / 2) * sphereSpacing;
+							scene.add(mesh);
+						}
+					}
 
 					hdrCubeMap.magFilter = THREE.LinearFilter;
 					hdrCubeMap.needsUpdate = true;
@@ -150,25 +199,27 @@
 
 				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));
-
-
-
+				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);
+
+			addLabel("Normal Map", new THREE.Vector3(-450, 0, 0), 30);
+			addLabel("None", new THREE.Vector3(-350, -100, 0));
+			addLabel("Scaling + Map", new THREE.Vector3(-400, 100, 0));
+
+			addLabel("Clearcoat Normal Map", new THREE.Vector3(0, 260, 0), 30);
+			addLabel("None", new THREE.Vector3(- 200, 200, 0));
+			addLabel("Scaling", new THREE.Vector3(0, 200, 0));
+			addLabel("Scaling + Map", new THREE.Vector3(200, 200, 0));
 
 			// LIGHTS
 
-			particleLight = new THREE.Mesh( new THREE.SphereBufferGeometry( 4, 8, 8 ), new THREE.MeshBasicMaterial( { color: 0xffffff } ) );
-			scene.add( particleLight );
+			particleLight = new THREE.Mesh(new THREE.SphereBufferGeometry(4, 8, 8), new THREE.MeshBasicMaterial({ color: 0xffffff }));
+			scene.add(particleLight);
 
 			{
 				var ambientLight = new THREE.AmbientLight(0x444444);
@@ -201,18 +252,23 @@
 
 			// EVENTS
 
-			var controls = new OrbitControls( camera, renderer.domElement );
+			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.add(guiParams, 'metalness', 0, 1, 0.01);
+			gui.add(guiParams, 'roughness', 0, 1, 0.01);
+			gui.add(guiParams, 'reflectivity', 0, 1, 0.01);
+			gui.add(guiParams, 'clearCoat', 0, 1, 0.01);
+			gui.add(guiParams, 'clearCoatRoughness', 0, 1, 0.01);
+
+
+			gui.add(guiMatParams, 'normalMap', guiNormalMapNames);
+			gui.add(guiMatParams, 'normalScale', 0, 10, 0.01);
+			gui.add(guiMatParams, 'clearCoatNormalMap', guiNormalMapNames);
+			gui.add(guiMatParams, 'clearCoatNormalScale', 0, 10, 0.01);
 
 			gui.open();
 		}
@@ -243,24 +299,38 @@
 
 		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 matColor = new THREE.Color().setHSL(0.0, 0.5, 0.25);
+
+			for (var ii = 0; ii < maxI; ii++) {
+				if (mats[ii]) {
+					for (var jj = 0; jj < maxJ; jj++) {
+						var mat = mats[ii][jj];
+						mat.color = matColor;
+						for (var matParam in guiParams) {
+							mat[matParam] = guiParams[matParam];
+						}
+
+						var normalMap = normalMaps[guiMatParams.normalMap];
+						var clearCoatNormalMap = normalMaps[guiMatParams.clearCoatNormalMap];
+
+						variationsX[ii](mat, guiMatParams.clearCoatNormalScale, clearCoatNormalMap);
+						variationsY[jj](mat, guiMatParams.normalScale, normalMap);
+					}
 				}
 			}
 
 			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;
+			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;
+			for (var mesh of meshes) {
+				mesh.rotation.y += 0.01;
 			}
 
-			renderer.render( scene, camera );
+
+			renderer.render(scene, camera);
 
 		}
 

BIN
examples/textures/nvidia_tentacle/tentacle_object_space.png


BIN
examples/textures/nvidia_tentacle/tentacle_tangent_space.png


+ 1 - 1
package-lock.json

@@ -1,6 +1,6 @@
 {
   "name": "three",
-  "version": "0.105.1",
+  "version": "0.106.2",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {

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

@@ -1,3 +1,6 @@
+import { Texture } from './../textures/Texture';
+import { Vector2 } from './../math/Vector2';
+import { NormalMapTypes } from '../constants';
 import {
 	MeshStandardMaterialParameters,
 	MeshStandardMaterial,
@@ -8,7 +11,11 @@ export interface MeshPhysicalMaterialParameters
 	reflectivity?: number;
 	clearCoat?: number;
 	clearCoatRoughness?: number;
+	
 	clearCoatGeometryNormals?: boolean;
+	clearCoatNormalMap?: Texture;
+	clearCoatNormalMapType?: NormalMapTypes;
+	clearCoatNormalScale?: Vector2;
 }
 
 export class MeshPhysicalMaterial extends MeshStandardMaterial {
@@ -19,6 +26,10 @@ export class MeshPhysicalMaterial extends MeshStandardMaterial {
 	reflectivity: number;
 	clearCoat: number;
 	clearCoatRoughness: number;
+
 	clearCoatGeometryNormals?: boolean;
+	clearCoatNormalMap: Texture | null;
+	clearCoatNormalMapType: NormalMapTypes;
+	clearCoatNormalScale: Vector2;
 
 }

+ 13 - 0
src/materials/MeshPhysicalMaterial.js

@@ -1,3 +1,5 @@
+import { TangentSpaceNormalMap } from '../constants.js';
+import { Vector2 } from '../math/Vector2.js';
 import { MeshStandardMaterial } from './MeshStandardMaterial.js';
 
 /**
@@ -7,7 +9,11 @@ import { MeshStandardMaterial } from './MeshStandardMaterial.js';
  *  reflectivity: <float>
  *  clearCoat: <float>
  *  clearCoatRoughness: <float>
+
  *  clearCoatGeometryNormals: <boolean>
+ *  clearCoatNormalMap: new THREE.Texture( <Image> ),
+ *  clearCoatNormalMapType: THREE.TangentSpaceNormalMap,
+ *  clearCoatNormalScale: <Vector2>,
  * }
  */
 
@@ -25,6 +31,9 @@ function MeshPhysicalMaterial( parameters ) {
 	this.clearCoatRoughness = 0.0;
 
 	this.clearCoatGeometryNormals = false;
+	this.clearCoatNormalMap = null;
+	this.clearCoatNormalMapType = TangentSpaceNormalMap;
+	this.clearCoatNormalScale = new Vector2(1, 1);
 
 	this.setValues( parameters );
 
@@ -45,7 +54,11 @@ MeshPhysicalMaterial.prototype.copy = function ( source ) {
 
 	this.clearCoat = source.clearCoat;
 	this.clearCoatRoughness = source.clearCoatRoughness;
+
 	this.clearCoatGeometryNormals = source.clearCoatGeometryNormals;
+	this.clearCoatNormalMap = source.clearCoatNormalMap;
+	this.clearCoatNormalMapType = source.clearCoatNormalMapType;
+	this.clearCoatNormalScale.copy(source.clearCoatNormalScale);
 
 	return this;
 

+ 97 - 93
src/renderers/WebGLRenderer.js

@@ -155,7 +155,7 @@ function WebGLRenderer( parameters ) {
 		_currentScissor = new Vector4(),
 		_currentScissorTest = null,
 
-		//
+	//
 
 		_width = _canvas.width,
 		_height = _canvas.height,
@@ -256,47 +256,47 @@ function WebGLRenderer( parameters ) {
 
 	function initGLContext() {
 
-		extensions = new WebGLExtensions( _gl );
+			extensions = new WebGLExtensions( _gl );
 
-		capabilities = new WebGLCapabilities( _gl, extensions, parameters );
+			capabilities = new WebGLCapabilities( _gl, extensions, parameters );
 
-		if ( ! capabilities.isWebGL2 ) {
+			if ( ! capabilities.isWebGL2 ) {
 
-			extensions.get( 'WEBGL_depth_texture' );
-			extensions.get( 'OES_texture_float' );
-			extensions.get( 'OES_texture_half_float' );
-			extensions.get( 'OES_texture_half_float_linear' );
-			extensions.get( 'OES_standard_derivatives' );
-			extensions.get( 'OES_element_index_uint' );
-			extensions.get( 'ANGLE_instanced_arrays' );
+				extensions.get( 'WEBGL_depth_texture' );
+				extensions.get( 'OES_texture_float' );
+				extensions.get( 'OES_texture_half_float' );
+				extensions.get( 'OES_texture_half_float_linear' );
+				extensions.get( 'OES_standard_derivatives' );
+				extensions.get( 'OES_element_index_uint' );
+				extensions.get( 'ANGLE_instanced_arrays' );
 
-		}
+			}
 
-		extensions.get( 'OES_texture_float_linear' );
+			extensions.get( 'OES_texture_float_linear' );
 
-		utils = new WebGLUtils( _gl, extensions, capabilities );
+			utils = new WebGLUtils( _gl, extensions, capabilities );
 
-		state = new WebGLState( _gl, extensions, utils, capabilities );
-		state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() );
-		state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() );
+			state = new WebGLState( _gl, extensions, utils, capabilities );
+			state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() );
+			state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() );
 
-		info = new WebGLInfo( _gl );
-		properties = new WebGLProperties();
-		textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info );
-		attributes = new WebGLAttributes( _gl );
-		geometries = new WebGLGeometries( _gl, attributes, info );
-		objects = new WebGLObjects( geometries, info );
-		morphtargets = new WebGLMorphtargets( _gl );
-		programCache = new WebGLPrograms( _this, extensions, capabilities );
-		renderLists = new WebGLRenderLists();
-		renderStates = new WebGLRenderStates();
+			info = new WebGLInfo( _gl );
+			properties = new WebGLProperties();
+			textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info );
+			attributes = new WebGLAttributes( _gl );
+			geometries = new WebGLGeometries( _gl, attributes, info );
+			objects = new WebGLObjects( geometries, info );
+			morphtargets = new WebGLMorphtargets( _gl );
+			programCache = new WebGLPrograms( _this, extensions, capabilities );
+			renderLists = new WebGLRenderLists();
+			renderStates = new WebGLRenderStates();
 
-		background = new WebGLBackground( _this, state, objects, _premultipliedAlpha );
+			background = new WebGLBackground( _this, state, objects, _premultipliedAlpha );
 
-		bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities );
-		indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities );
+			bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities );
+			indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities );
 
-		info.programs = programCache.programs;
+			info.programs = programCache.programs;
 
 		_this.capabilities = capabilities;
 		_this.extensions = extensions;
@@ -305,124 +305,124 @@ function WebGLRenderer( parameters ) {
 		_this.state = state;
 		_this.info = info;
 
-	}
+		}
 
-	initGLContext();
+		initGLContext();
 
-	// vr
+		// vr
 
 	var vr = ( typeof navigator !== 'undefined' && 'xr' in navigator && 'supportsSession' in navigator.xr ) ? new WebXRManager( _this, _gl ) : new WebVRManager( _this );
 
-	this.vr = vr;
+		this.vr = vr;
 
-	// shadow map
+		// shadow map
 
-	var shadowMap = new WebGLShadowMap( _this, objects, capabilities.maxTextureSize );
+		var shadowMap = new WebGLShadowMap( _this, objects, capabilities.maxTextureSize );
 
-	this.shadowMap = shadowMap;
+		this.shadowMap = shadowMap;
 
-	// API
+		// API
 
-	this.getContext = function () {
+		this.getContext = function () {
 
-		return _gl;
+			return _gl;
 
-	};
+		};
 
-	this.getContextAttributes = function () {
+		this.getContextAttributes = function () {
 
-		return _gl.getContextAttributes();
+			return _gl.getContextAttributes();
 
-	};
+		};
 
-	this.forceContextLoss = function () {
+		this.forceContextLoss = function () {
 
-		var extension = extensions.get( 'WEBGL_lose_context' );
-		if ( extension ) extension.loseContext();
+			var extension = extensions.get( 'WEBGL_lose_context' );
+			if ( extension ) extension.loseContext();
 
-	};
+		};
 
-	this.forceContextRestore = function () {
+		this.forceContextRestore = function () {
 
-		var extension = extensions.get( 'WEBGL_lose_context' );
-		if ( extension ) extension.restoreContext();
+			var extension = extensions.get( 'WEBGL_lose_context' );
+			if ( extension ) extension.restoreContext();
 
-	};
+		};
 
-	this.getPixelRatio = function () {
+		this.getPixelRatio = function () {
 
-		return _pixelRatio;
+			return _pixelRatio;
 
-	};
+		};
 
-	this.setPixelRatio = function ( value ) {
+		this.setPixelRatio = function ( value ) {
 
-		if ( value === undefined ) return;
+			if ( value === undefined ) return;
 
-		_pixelRatio = value;
+			_pixelRatio = value;
 
-		this.setSize( _width, _height, false );
+			this.setSize( _width, _height, false );
 
-	};
+		};
 
-	this.getSize = function ( target ) {
+		this.getSize = function ( target ) {
 
-		if ( target === undefined ) {
+			if ( target === undefined ) {
 
-			console.warn( 'WebGLRenderer: .getsize() now requires a Vector2 as an argument' );
+				console.warn( 'WebGLRenderer: .getsize() now requires a Vector2 as an argument' );
 
-			target = new Vector2();
+				target = new Vector2();
 
-		}
+			}
 
-		return target.set( _width, _height );
+			return target.set( _width, _height );
 
-	};
+		};
 
-	this.setSize = function ( width, height, updateStyle ) {
+		this.setSize = function ( width, height, updateStyle ) {
 
-		if ( vr.isPresenting() ) {
+			if ( vr.isPresenting() ) {
 
-			console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' );
-			return;
+				console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' );
+				return;
 
-		}
+			}
 
-		_width = width;
-		_height = height;
+			_width = width;
+			_height = height;
 
-		_canvas.width = Math.floor( width * _pixelRatio );
-		_canvas.height = Math.floor( height * _pixelRatio );
+			_canvas.width = Math.floor( width * _pixelRatio );
+			_canvas.height = Math.floor( height * _pixelRatio );
 
-		if ( updateStyle !== false ) {
+			if ( updateStyle !== false ) {
 
-			_canvas.style.width = width + 'px';
-			_canvas.style.height = height + 'px';
+				_canvas.style.width = width + 'px';
+				_canvas.style.height = height + 'px';
 
-		}
+			}
 
-		this.setViewport( 0, 0, width, height );
+			this.setViewport( 0, 0, width, height );
 
-	};
+		};
 
-	this.getDrawingBufferSize = function ( target ) {
+		this.getDrawingBufferSize = function ( target ) {
 
-		if ( target === undefined ) {
+			if ( target === undefined ) {
 
-			console.warn( 'WebGLRenderer: .getdrawingBufferSize() now requires a Vector2 as an argument' );
+				console.warn( 'WebGLRenderer: .getdrawingBufferSize() now requires a Vector2 as an argument' );
 
-			target = new Vector2();
+				target = new Vector2();
 
-		}
+			}
 
-		return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor();
+			return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor();
 
-	};
+		};
 
-	this.setDrawingBufferSize = function ( width, height, pixelRatio ) {
+		this.setDrawingBufferSize = function ( width, height, pixelRatio ) {
 
-		_width = width;
-		_height = height;
+			_width = width;
+			_height = height;
 
 		_pixelRatio = pixelRatio;
 
@@ -2274,6 +2274,10 @@ function WebGLRenderer( parameters ) {
 
 		uniforms.clearCoat.value = material.clearCoat;
 		uniforms.clearCoatRoughness.value = material.clearCoatRoughness;
+
+		uniforms.clearCoatGeometryNormals.value = material.clearCoatGeometryNormals;
+		uniforms.clearCoatNormalMap.value = material.clearCoatNormalMap;
+		uniforms.clearCoatNormalScale.value = material.clearCoatNormalScale;
 		uniforms.clearCoatGeometryNormals.value = material.clearCoatGeometryNormals;
 
 	}

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

@@ -84,6 +84,8 @@ export let ShaderChunk: {
 	normal_vert: string;
 	normalmap_pars_fragment: string;
 	clearcoat_normal_fragment_begin: string;
+	clearcoat_normal_fragment_maps: string;
+	clearcoat_normalmap_pars_fragment: string;
 	packing: string;
 	points_frag: string;
 	points_vert: string;

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

@@ -62,6 +62,8 @@ import normal_fragment_begin from './ShaderChunk/normal_fragment_begin.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 clearcoat_normal_fragment_begin from './ShaderChunk/clearcoat_normal_fragment_begin.glsl.js';
+import clearcoat_normal_fragment_maps from './ShaderChunk/clearcoat_normal_fragment_maps.glsl.js';
+import clearcoat_normalmap_pars_fragment from './ShaderChunk/clearcoat_normalmap_pars_fragment.glsl.js';
 import packing from './ShaderChunk/packing.glsl.js';
 import premultiplied_alpha_fragment from './ShaderChunk/premultiplied_alpha_fragment.glsl.js';
 import project_vertex from './ShaderChunk/project_vertex.glsl.js';
@@ -185,6 +187,8 @@ export var ShaderChunk = {
 	normal_fragment_maps: normal_fragment_maps,
 	normalmap_pars_fragment: normalmap_pars_fragment,
 	clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin,
+	clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps,
+	clearcoat_normalmap_pars_fragment: clearcoat_normalmap_pars_fragment,
 	packing: packing,
 	premultiplied_alpha_fragment: premultiplied_alpha_fragment,
 	project_vertex: project_vertex,

+ 8 - 3
src/renderers/shaders/ShaderChunk/clearcoat_normal_fragment_begin.glsl.js

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

+ 79 - 0
src/renderers/shaders/ShaderChunk/clearcoat_normal_fragment_maps.glsl.js

@@ -0,0 +1,79 @@
+export default /* glsl */ `
+#if defined( USE_NORMALMAP )
+
+	#ifdef USE_TANGENT
+
+		mat3 vTBN = mat3( tangent, bitangent, clearCoatNormal );
+		vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;
+		mapN.xy = normalScale * mapN.xy;
+		clearCoatNormal = normalize( vTBN * mapN );
+
+	#else
+
+	  clearCoatNormal = perturbClearCoatNormal2Arb( -vViewPosition, clearCoatNormal );
+
+	#endif
+#endif
+
+`;
+/*
+#if defined( USE_NORMALMAP )
+
+	#ifdef USE_TANGENT
+
+		mat3 vTBN = mat3( tangent, bitangent, normal );
+		vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;
+		mapN.xy = clearCoatnormalScale * mapN.xy;
+		clearCoatNormal = normalize( vTBN * mapN );
+
+	#else
+
+	  clearCoatNormal = perturbClearCoatNormal2Arb( -vViewPosition, clearCoatNormal );
+
+	#endif
+#endif
+*/
+/*
+#if defined( USE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP )
+
+	//#ifdef OBJECTSPACE_NORMALMAP
+
+		normal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0; // overrides both flatShading and attribute normals
+
+		#ifdef FLIP_SIDED
+
+			normal = - normal;
+
+		#endif
+
+		#ifdef DOUBLE_SIDED
+
+			normal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );
+
+		#endif
+
+		normal = normalize( normalMatrix * normal );
+
+	//#else // tangent-space normal map
+
+		#ifdef USE_TANGENT
+
+			mat3 vTBN = mat3( tangent, bitangent, normal );
+			vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;
+			mapN.xy = normalScale * mapN.xy;
+			normal = normalize( vTBN * mapN );
+
+		#else
+
+			normal = perturbNormal2Arb( -vViewPosition, normal );
+
+		#endif
+
+	//#endif
+
+#elif defined( USE_BUMPMAP )
+
+	normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );
+
+#endif
+*/

+ 80 - 0
src/renderers/shaders/ShaderChunk/clearcoat_normalmap_pars_fragment.glsl.js

@@ -0,0 +1,80 @@
+export default /* glsl */ `
+#ifdef USE_NORMALMAP
+
+	//uniform sampler2D normalMap;
+	//uniform vec2 normalScale;
+
+		// Per-Pixel Tangent Space Normal Mapping
+		// http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html
+
+		vec3 perturbClearCoatNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {
+
+			// Workaround for Adreno 3XX dFd*( vec3 ) bug. See #9988
+
+			vec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );
+			vec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );
+			vec2 st0 = dFdx( vUv.st );
+			vec2 st1 = dFdy( vUv.st );
+
+			float scale = sign( st1.t * st0.s - st0.t * st1.s ); // we do not care about the magnitude
+
+			vec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );
+			vec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );
+			vec3 N = normalize( surf_norm );
+			mat3 tsn = mat3( S, T, N );
+
+			vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;
+
+			mapN.xy *= normalScale;
+			mapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );
+
+			return normalize( tsn * mapN );
+
+		}
+
+#endif
+`;
+/*
+#ifdef USE_NORMALMAP
+
+	uniform sampler2D normalMap;
+	uniform vec2 normalScale;
+
+	#ifdef OBJECTSPACE_NORMALMAP
+
+		uniform mat3 normalMatrix;
+
+	#else
+
+		// Per-Pixel Tangent Space Normal Mapping
+		// http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html
+
+		vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {
+
+			// Workaround for Adreno 3XX dFd*( vec3 ) bug. See #9988
+
+			vec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );
+			vec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );
+			vec2 st0 = dFdx( vUv.st );
+			vec2 st1 = dFdy( vUv.st );
+
+			float scale = sign( st1.t * st0.s - st0.t * st1.s ); // we do not care about the magnitude
+
+			vec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );
+			vec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );
+			vec3 N = normalize( surf_norm );
+			mat3 tsn = mat3( S, T, N );
+
+			vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;
+
+			mapN.xy *= normalScale;
+			mapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );
+
+			return normalize( tsn * mapN );
+
+		}
+
+	#endif
+
+#endif
+*/

+ 1 - 1
src/renderers/shaders/ShaderChunk/envmap_fragment.glsl.js

@@ -1,7 +1,7 @@
 export default /* glsl */`
 #ifdef USE_ENVMAP
 
-	#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )
+	#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( PHONG )
 
 		vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );
 

+ 2 - 2
src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl.js

@@ -6,7 +6,7 @@ export default /* glsl */`
 
 #ifdef USE_ENVMAP
 
-	#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )
+	#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( PHONG ) )
 		varying vec3 vWorldPosition;
 	#endif
 
@@ -18,7 +18,7 @@ export default /* glsl */`
 	uniform float flipEnvMap;
 	uniform int maxMipLevel;
 
-	#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )
+	#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )
 		uniform float refractionRatio;
 	#else
 		varying vec3 vReflect;

+ 1 - 1
src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl.js

@@ -1,7 +1,7 @@
 export default /* glsl */`
 #ifdef USE_ENVMAP
 
-	#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )
+	#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( PHONG )
 		varying vec3 vWorldPosition;
 
 	#else

+ 1 - 1
src/renderers/shaders/ShaderChunk/envmap_vertex.glsl.js

@@ -1,7 +1,7 @@
 export default /* glsl */`
 #ifdef USE_ENVMAP
 
-	#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )
+	#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( PHONG )
 
 		vWorldPosition = worldPosition.xyz;
 

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

@@ -77,7 +77,9 @@ void RE_Direct_Physical( const in IncidentLight directLight, const in GeometricC
 	#endif
 
 	#ifndef STANDARD
-		float clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );
+		float ccDotNV = saturate( dot( geometry.clearCoatNormal, geometry.viewDir ) );
+		float ccDotNL = ccDotNV;
+		float clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, ccDotNL );
 	#else
 		float clearCoatDHR = 0.0;
 	#endif
@@ -109,9 +111,9 @@ 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
-		float dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );
-		float dotNL = dotNV;
-		float clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );
+		float ccDotNV = saturate( dot( geometry.clearCoatNormal, geometry.viewDir ) );
+		float ccDotNL = ccDotNV;
+		float clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, ccDotNL );
 	#else
 		float clearCoatDHR = 0.0;
 	#endif

+ 2 - 2
src/renderers/shaders/ShaderChunk/uv_pars_fragment.glsl.js

@@ -1,5 +1,5 @@
-export default /* glsl */`
-#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )
+export default /* glsl */ `
+#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )
 
 	varying vec2 vUv;
 

+ 1 - 1
src/renderers/shaders/ShaderChunk/uv_pars_vertex.glsl.js

@@ -1,5 +1,5 @@
 export default /* glsl */`
-#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )
+#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )
 
 	varying vec2 vUv;
 	uniform mat3 uvTransform;

+ 1 - 1
src/renderers/shaders/ShaderChunk/uv_vertex.glsl.js

@@ -1,5 +1,5 @@
 export default /* glsl */`
-#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )
+#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP )  || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )
 
 	vUv = ( uvTransform * vec3( uv, 1 ) ).xy;
 

+ 3 - 0
src/renderers/shaders/ShaderLib.js

@@ -1,5 +1,6 @@
 import { ShaderChunk } from './ShaderChunk.js';
 import { mergeUniforms } from './UniformsUtils.js';
+import { Vector2 } from '../../math/Vector2.js';
 import { Vector3 } from '../../math/Vector3.js';
 import { UniformsLib } from './UniformsLib.js';
 import { Color } from '../../math/Color.js';
@@ -275,6 +276,8 @@ ShaderLib.physical = {
 			clearCoat: { value: 0 },
 			clearCoatRoughness: { value: 0 },
 			clearCoatGeometryNormals: { value: false },
+			clearCoatNormalMap: { value: null },
+			clearCoatNormalScale: { value: new Vector2( 1, 1 ) }
 		}
 	] ),
 

+ 2 - 0
src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js

@@ -49,6 +49,7 @@ varying vec3 vViewPosition;
 #include <shadowmap_pars_fragment>
 #include <bumpmap_pars_fragment>
 #include <normalmap_pars_fragment>
+#include <clearcoat_normalmap_pars_fragment>
 #include <roughnessmap_pars_fragment>
 #include <metalnessmap_pars_fragment>
 #include <logdepthbuf_pars_fragment>
@@ -72,6 +73,7 @@ void main() {
 	#include <normal_fragment_begin>
 	#include <normal_fragment_maps>
 	#include <clearcoat_normal_fragment_begin>
+	#include <clearcoat_normal_fragment_maps>
 	#include <emissivemap_fragment>
 
 	// accumulation

+ 1 - 1
src/renderers/shaders/ShaderLib/normal_frag.glsl.js

@@ -3,7 +3,7 @@ export default /* glsl */`
 
 uniform float opacity;
 
-#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || ( defined( USE_NORMALMAP ) && ! defined( OBJECTSPACE_NORMALMAP ) )
+#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || ( defined( USE_NORMALMAP ) && ! defined( OBJECTSPACE_NORMALMAP ) ) || ( defined( USE_CLEARCOAT_NORMALMAP ) && ! defined( OBJECTSPACE_CLEARCOAT_NORMALMAP ) )
 
 	varying vec3 vViewPosition;
 

+ 3 - 3
src/renderers/shaders/ShaderLib/normal_vert.glsl.js

@@ -1,7 +1,7 @@
-export default /* glsl */`
+export default /* glsl */ `
 #define NORMAL
 
-#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || ( defined( USE_NORMALMAP ) && ! defined( OBJECTSPACE_NORMALMAP ) )
+#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || ( defined( USE_NORMALMAP ) && ! defined( OBJECTSPACE_NORMALMAP ) ) || ( defined( USE_CLEARCOAT_NORMALMAP ) && ! defined( OBJECTSPACE_CLEARCOAT_NORMALMAP ) )
 
 	varying vec3 vViewPosition;
 
@@ -58,7 +58,7 @@ void main() {
 	#include <logdepthbuf_vertex>
 	#include <clipping_planes_vertex>
 
-#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || ( defined( USE_NORMALMAP ) && ! defined( OBJECTSPACE_NORMALMAP ) )
+#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || ( defined( USE_NORMALMAP ) && ! defined( OBJECTSPACE_NORMALMAP ) ) || ( defined( USE_CLEARCOAT_NORMALMAP ) && ! defined( OBJECTSPACE_CLEARCOAT_NORMALMAP ) )
 
 	vViewPosition = - mvPosition.xyz;
 

+ 5 - 1
src/renderers/webgl/WebGLProgram.js

@@ -118,7 +118,7 @@ function generateExtensions( extensions, parameters, rendererExtensions ) {
 	extensions = extensions || {};
 
 	var chunks = [
-		( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || ( parameters.normalMap && ! parameters.objectSpaceNormalMap ) || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '',
+		( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || ( parameters.normalMap && ! parameters.objectSpaceNormalMap ) || ( parameters.clearCoatNormalMap && ! parameters.objectSpaceclearCoatNormalMap ) || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '',
 		( extensions.fragDepth || parameters.logarithmicDepthBuffer ) && rendererExtensions.get( 'EXT_frag_depth' ) ? '#extension GL_EXT_frag_depth : enable' : '',
 		( extensions.drawBuffers ) && rendererExtensions.get( 'WEBGL_draw_buffers' ) ? '#extension GL_EXT_draw_buffers : require' : '',
 		( extensions.shaderTextureLOD || parameters.envMap ) && rendererExtensions.get( 'EXT_shader_texture_lod' ) ? '#extension GL_EXT_shader_texture_lod : enable' : ''
@@ -384,6 +384,8 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters,
 			parameters.bumpMap ? '#define USE_BUMPMAP' : '',
 			parameters.normalMap ? '#define USE_NORMALMAP' : '',
 			( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '',
+			parameters.clearCoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
+			( parameters.clearCoatNormalMap && parameters.objectSpaceClearCoatNormalMap ) ? '#define OBJECTSPACE_CLEARCOAT_NORMALMAP' : '',
 			parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '',
 			parameters.specularMap ? '#define USE_SPECULARMAP' : '',
 			parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
@@ -500,6 +502,8 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters,
 			parameters.bumpMap ? '#define USE_BUMPMAP' : '',
 			parameters.normalMap ? '#define USE_NORMALMAP' : '',
 			( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '',
+			parameters.clearCoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
+			( parameters.clearCoatNormalMap && parameters.objectSpaceClearCoatNormalMap ) ? '#define OBJECTSPACE_CLEARCOAT_NORMALMAP' : '',
 			parameters.specularMap ? '#define USE_SPECULARMAP' : '',
 			parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
 			parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',

+ 3 - 1
src/renderers/webgl/WebGLPrograms.js

@@ -29,7 +29,7 @@ function WebGLPrograms( renderer, extensions, capabilities ) {
 
 	var parameterNames = [
 		"precision", "supportsVertexTextures", "map", "mapEncoding", "matcap", "matcapEncoding", "envMap", "envMapMode", "envMapEncoding",
-		"lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "objectSpaceNormalMap", "displacementMap", "specularMap",
+		"lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "objectSpaceNormalMap", "clearCoatNormalMap", "objectSpaceClearCoatNormalMap",, "displacementMap", "specularMap",
 		"roughnessMap", "metalnessMap", "gradientMap",
 		"alphaMap", "combine", "vertexColors", "vertexTangents", "fog", "useFog", "fogExp",
 		"flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning",
@@ -153,6 +153,8 @@ function WebGLPrograms( renderer, extensions, capabilities ) {
 			bumpMap: !! material.bumpMap,
 			normalMap: !! material.normalMap,
 			objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap,
+			clearCoatNormalMap: !! material.clearCoatNormalMap,
+			objectSpaceClearCoatNormalMap: material.clearCoatNormalMapType === ObjectSpaceNormalMap,
 			displacementMap: !! material.displacementMap,
 			roughnessMap: !! material.roughnessMap,
 			metalnessMap: !! material.metalnessMap,

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott