diff --git a/README.md b/README.md index 7f31eefbf2777a04ce3ba6ac86b3a02bb5ba3723..aa3e34501dde50d4bd6c52193bbf4d8c6e45d3ec 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -three.js +three.js ======== [![NPM package][npm]][npm-url] diff --git a/examples/files.js b/examples/files.js index b8354d858d3f53f62d9a8fb2b545eea5f49899bb..23614b17a1fa6f0b18e6a84e1b70fd4ade87d761 100644 --- a/examples/files.js +++ b/examples/files.js @@ -147,6 +147,7 @@ var files = { "webgl_materials_bumpmap_skin", "webgl_materials_cars", "webgl_materials_channels", + "webgl_materials_clearcoat_normalmap", "webgl_materials_compile", "webgl_materials_cubemap", "webgl_materials_cubemap_balls_reflection", diff --git a/examples/textures/nvidia_tentacle/tentacle_object_space.png b/examples/textures/nvidia_tentacle/tentacle_object_space.png new file mode 100644 index 0000000000000000000000000000000000000000..2ae9fc70bb6436bcd4246d16e08c0bf419122377 Binary files /dev/null and b/examples/textures/nvidia_tentacle/tentacle_object_space.png differ diff --git a/examples/textures/nvidia_tentacle/tentacle_tangent_space.png b/examples/textures/nvidia_tentacle/tentacle_tangent_space.png new file mode 100644 index 0000000000000000000000000000000000000000..498c7dc2376ca17b393169f14a94a6047fd72a6e Binary files /dev/null and b/examples/textures/nvidia_tentacle/tentacle_tangent_space.png differ diff --git a/examples/webgl_materials_clearcoat_normalmap.html b/examples/webgl_materials_clearcoat_normalmap.html new file mode 100644 index 0000000000000000000000000000000000000000..0412189ed3b86cd16b56a600f9c8aec7dd09edda --- /dev/null +++ b/examples/webgl_materials_clearcoat_normalmap.html @@ -0,0 +1,353 @@ + + + + + three.js webgl - materials - clearcoat normal + + + + + + + +
+ three.js - webgl - materials - clearcoat normal + demo.
+
+ + + + + + \ No newline at end of file diff --git a/examples/webgl_materials_envmaps_parallax.html b/examples/webgl_materials_envmaps_parallax.html index d410e7cfaa3ea1ac6667aae42fe1b55514bd04f3..4f8a0aa8380f616c9faa7fee5e1cbf50127daa5d 100644 --- a/examples/webgl_materials_envmaps_parallax.html +++ b/examples/webgl_materials_envmaps_parallax.html @@ -156,15 +156,15 @@ return clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar ); } - vec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) { + vec3 getLightProbeIndirectRadiance( const in vec3 viewDir, const in vec3 normal, const in float blinnShininessExponent, const in int maxMIPLevel ) { #ifdef ENVMAP_MODE_REFLECTION - vec3 reflectVec = reflect( -geometry.viewDir, geometry.normal ); + vec3 reflectVec = reflect( -viewDir, normal ); #else - vec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio ); + vec3 reflectVec = refract( -viewDir, normal, refractionRatio ); #endif diff --git a/src/materials/MeshPhysicalMaterial.d.ts b/src/materials/MeshPhysicalMaterial.d.ts index 96c7f15247b6d37b3f523331aaa27187ac4b4db8..1ec4ddcff75bdf937feee408aab5976a8b49ea8c 100644 --- a/src/materials/MeshPhysicalMaterial.d.ts +++ b/src/materials/MeshPhysicalMaterial.d.ts @@ -1,3 +1,5 @@ +import { Texture } from './../textures/Texture'; +import { Vector2 } from './../math/Vector2'; import { MeshStandardMaterialParameters, MeshStandardMaterial, @@ -8,6 +10,9 @@ export interface MeshPhysicalMaterialParameters reflectivity?: number; clearCoat?: number; clearCoatRoughness?: number; + + clearCoatNormalScale?: Vector2; + clearCoatNormalMap?: Texture; } export class MeshPhysicalMaterial extends MeshStandardMaterial { @@ -19,4 +24,7 @@ export class MeshPhysicalMaterial extends MeshStandardMaterial { clearCoat: number; clearCoatRoughness: number; + clearCoatNormalScale: Vector2; + clearCoatNormalMap: Texture | null; + } diff --git a/src/materials/MeshPhysicalMaterial.js b/src/materials/MeshPhysicalMaterial.js index a4ea18c03cddbb97e0f9fdc6505c47083afdb4f0..3c77314ffa735e94cc9ebca7bec5324a2645ff15 100644 --- a/src/materials/MeshPhysicalMaterial.js +++ b/src/materials/MeshPhysicalMaterial.js @@ -1,3 +1,4 @@ +import { Vector2 } from '../math/Vector2.js'; import { MeshStandardMaterial } from './MeshStandardMaterial.js'; /** @@ -7,6 +8,9 @@ import { MeshStandardMaterial } from './MeshStandardMaterial.js'; * reflectivity: * clearCoat: * clearCoatRoughness: + * + * clearCoatNormalScale: , + * clearCoatNormalMap: new THREE.Texture( ), * } */ @@ -23,6 +27,9 @@ function MeshPhysicalMaterial( parameters ) { this.clearCoat = 0.0; this.clearCoatRoughness = 0.0; + this.clearCoatNormalScale = new Vector2( 1, 1 ); + this.clearCoatNormalMap = null; + this.setValues( parameters ); } @@ -43,6 +50,9 @@ MeshPhysicalMaterial.prototype.copy = function ( source ) { this.clearCoat = source.clearCoat; this.clearCoatRoughness = source.clearCoatRoughness; + this.clearCoatNormalMap = source.clearCoatNormalMap; + this.clearCoatNormalScale.copy( source.clearCoatNormalScale ); + return this; }; diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index 3d9d1936b9cc3aec32ee4eed6f62ccfcd3458e00..10fbf69a5ecd6aa29d4c96ed8c8ec9e3354e31e0 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -2275,6 +2275,19 @@ function WebGLRenderer( parameters ) { uniforms.clearCoat.value = material.clearCoat; uniforms.clearCoatRoughness.value = material.clearCoatRoughness; + if ( material.clearCoatNormalMap ) { + + uniforms.clearCoatNormalScale.value.copy( material.clearCoatNormalScale ); + uniforms.clearCoatNormalMap.value = material.clearCoatNormalMap; + + if ( material.side === BackSide ) { + + uniforms.clearCoatNormalScale.value.negate(); + + } + + } + } function refreshUniformsMatcap( uniforms, material ) { diff --git a/src/renderers/shaders/ShaderChunk.d.ts b/src/renderers/shaders/ShaderChunk.d.ts index c7845ef7a3ce0ad4119e28b0b19825192cb9626e..ccf453750b680db63d490a5c8dabfb57bc60ef05 100644 --- a/src/renderers/shaders/ShaderChunk.d.ts +++ b/src/renderers/shaders/ShaderChunk.d.ts @@ -83,6 +83,9 @@ export let ShaderChunk: { normal_fragment_maps: string; 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; diff --git a/src/renderers/shaders/ShaderChunk.js b/src/renderers/shaders/ShaderChunk.js index 2adf87807dac15751e2c3e87e905bc4b27f1c634..2b8e7a74c877929cec221521c1b1bbc6e9292cec 100644 --- a/src/renderers/shaders/ShaderChunk.js +++ b/src/renderers/shaders/ShaderChunk.js @@ -61,6 +61,9 @@ import morphtarget_vertex from './ShaderChunk/morphtarget_vertex.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 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'; @@ -183,6 +186,9 @@ export var ShaderChunk = { normal_fragment_begin: normal_fragment_begin, 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, diff --git a/src/renderers/shaders/ShaderChunk/bsdfs.glsl.js b/src/renderers/shaders/ShaderChunk/bsdfs.glsl.js index 10e69395f3010609a01a2ef77db23736df891f69..7c2d85a056bc33310573dbe6ed92aee4c033576f 100644 --- a/src/renderers/shaders/ShaderChunk/bsdfs.glsl.js +++ b/src/renderers/shaders/ShaderChunk/bsdfs.glsl.js @@ -125,15 +125,15 @@ float D_GGX( const in float alpha, const in float dotNH ) { } // GGX Distribution, Schlick Fresnel, GGX-Smith Visibility -vec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) { +vec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) { float alpha = pow2( roughness ); // UE4's roughness - vec3 halfDir = normalize( incidentLight.direction + geometry.viewDir ); + vec3 halfDir = normalize( incidentLight.direction + viewDir ); - float dotNL = saturate( dot( geometry.normal, incidentLight.direction ) ); - float dotNV = saturate( dot( geometry.normal, geometry.viewDir ) ); - float dotNH = saturate( dot( geometry.normal, halfDir ) ); + float dotNL = saturate( dot( normal, incidentLight.direction ) ); + float dotNV = saturate( dot( normal, viewDir ) ); + float dotNH = saturate( dot( normal, halfDir ) ); float dotLH = saturate( dot( incidentLight.direction, halfDir ) ); vec3 F = F_Schlick( specularColor, dotLH ); @@ -264,9 +264,9 @@ vec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in m // End Rect Area Light // ref: https://www.unrealengine.com/blog/physically-based-shading-on-mobile - environmentBRDF for GGX on mobile -vec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) { +vec3 BRDF_Specular_GGX_Environment( const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) { - float dotNV = saturate( dot( geometry.normal, geometry.viewDir ) ); + float dotNV = saturate( dot( normal, viewDir ) ); vec2 brdf = integrateSpecularBRDF( dotNV, roughness ); diff --git a/src/renderers/shaders/ShaderChunk/clearcoat_normal_fragment_begin.glsl.js b/src/renderers/shaders/ShaderChunk/clearcoat_normal_fragment_begin.glsl.js new file mode 100644 index 0000000000000000000000000000000000000000..1fa91f16a47ec53671e1bd72af10413d9cef91f4 --- /dev/null +++ b/src/renderers/shaders/ShaderChunk/clearcoat_normal_fragment_begin.glsl.js @@ -0,0 +1,7 @@ +export default /* glsl */` +#ifndef STANDARD + #ifdef USE_CLEARCOAT_NORMALMAP + vec3 clearCoatNormal = geometryNormal; + #endif +#endif +`; diff --git a/src/renderers/shaders/ShaderChunk/clearcoat_normal_fragment_maps.glsl.js b/src/renderers/shaders/ShaderChunk/clearcoat_normal_fragment_maps.glsl.js new file mode 100644 index 0000000000000000000000000000000000000000..3f1584d4c6df60078ab737f54a7ac68755f29b12 --- /dev/null +++ b/src/renderers/shaders/ShaderChunk/clearcoat_normal_fragment_maps.glsl.js @@ -0,0 +1,19 @@ +export default /* glsl */` +#ifndef STANDARD + #ifdef USE_CLEARCOAT_NORMALMAP + + #ifdef USE_TANGENT + + mat3 vTBN = mat3( tangent, bitangent, clearCoatNormal ); + vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0; + mapN.xy = clearCoatNormalScale * mapN.xy; + clearCoatNormal = normalize( vTBN * mapN ); + + #else + + clearCoatNormal = perturbNormal2Arb( -vViewPosition, clearCoatNormal, clearCoatNormalScale, clearCoatNormalMap ); + + #endif + #endif +#endif +`; diff --git a/src/renderers/shaders/ShaderChunk/clearcoat_normalmap_pars_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/clearcoat_normalmap_pars_fragment.glsl.js new file mode 100644 index 0000000000000000000000000000000000000000..9bfabe6dc10b5682fb420a055a88ab7deb55e626 --- /dev/null +++ b/src/renderers/shaders/ShaderChunk/clearcoat_normalmap_pars_fragment.glsl.js @@ -0,0 +1,10 @@ +export default /* glsl */` +#ifndef STANDARD + #ifdef USE_CLEARCOAT_NORMALMAP + + uniform sampler2D clearCoatNormalMap; + uniform vec2 clearCoatNormalScale; + + #endif +#endif +`; diff --git a/src/renderers/shaders/ShaderChunk/common.glsl.js b/src/renderers/shaders/ShaderChunk/common.glsl.js index 7199b4dfe04d5064663b51075ef87f197f6377c9..c5fc0e13d2efdcee05544385ef7d660bd204d2d7 100644 --- a/src/renderers/shaders/ShaderChunk/common.glsl.js +++ b/src/renderers/shaders/ShaderChunk/common.glsl.js @@ -39,6 +39,14 @@ struct GeometricContext { vec3 position; vec3 normal; vec3 viewDir; + + #ifndef STANDARD + #ifdef USE_CLEARCOAT_NORMALMAP + + vec3 clearCoatNormal; + + #endif + #endif }; vec3 transformDirection( in vec3 dir, in mat4 matrix ) { diff --git a/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl.js index a606115946529d86f5293be73682c9aff5c889a9..716a3ee3c6e6acf109ecba4f52ca708763b5beae 100644 --- a/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl.js +++ b/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 ); diff --git a/src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl.js index ee33c62289d97caa2d544abba5bafa056a639e19..d95c014f6f6a466b0d0cbfa805f7b3db39bf3a28 100644 --- a/src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl.js +++ b/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; diff --git a/src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl.js b/src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl.js index ee79c220ea654e57ac07720a4224ae056b263390..0dfe23530b26ca857af18628f2f43bbedfbe2bfc 100644 --- a/src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl.js +++ b/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 diff --git a/src/renderers/shaders/ShaderChunk/envmap_physical_pars_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/envmap_physical_pars_fragment.glsl.js index d319e9b88dc0c53b9599858218301ca5719add8b..6acbce4af0cd59647cb95a2a31f767c6b07f8e5f 100644 --- a/src/renderers/shaders/ShaderChunk/envmap_physical_pars_fragment.glsl.js +++ b/src/renderers/shaders/ShaderChunk/envmap_physical_pars_fragment.glsl.js @@ -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 - vec3 reflectVec = reflect( -geometry.viewDir, geometry.normal ); + vec3 reflectVec = reflect( -viewDir, normal ); #else - vec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio ); + vec3 reflectVec = refract( -viewDir, normal, refractionRatio ); #endif diff --git a/src/renderers/shaders/ShaderChunk/envmap_vertex.glsl.js b/src/renderers/shaders/ShaderChunk/envmap_vertex.glsl.js index ba94677ceda0e2b9b17b293bb5812e0238130fd6..32fd9bf10b39e4343f7d978377eb37261a993924 100644 --- a/src/renderers/shaders/ShaderChunk/envmap_vertex.glsl.js +++ b/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; diff --git a/src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js b/src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js index 8d979324d520c9fe1ecba3c6c94d962d0c6a2728..081793ab8f135cbaf62a26f98b49e832ef8f042e 100644 --- a/src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js +++ b/src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js @@ -20,6 +20,15 @@ geometry.position = - vViewPosition; geometry.normal = normal; geometry.viewDir = normalize( vViewPosition ); +#ifdef PHYSICAL + #ifndef STANDARD + #ifdef USE_CLEARCOAT_NORMALMAP + + geometry.clearCoatNormal = clearCoatNormal; + + #endif + #endif +#endif IncidentLight directLight; #if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct ) diff --git a/src/renderers/shaders/ShaderChunk/lights_fragment_maps.glsl.js b/src/renderers/shaders/ShaderChunk/lights_fragment_maps.glsl.js index 65e2fb076b7f62335830d31104eb8f7355c80cf5..4e25169766ee26de4974a83ab107ffcbdf189738 100644 --- a/src/renderers/shaders/ShaderChunk/lights_fragment_maps.glsl.js +++ b/src/renderers/shaders/ShaderChunk/lights_fragment_maps.glsl.js @@ -25,11 +25,14 @@ export default /* glsl */` #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 - clearCoatRadiance += getLightProbeIndirectRadiance( /*specularLightProbe,*/ geometry, Material_ClearCoat_BlinnShininessExponent( material ), maxMipLevel ); + #ifdef USE_CLEARCOAT_NORMALMAP + clearCoatRadiance += getLightProbeIndirectRadiance( /*specularLightProbe,*/ geometry.viewDir, geometry.clearCoatNormal, Material_ClearCoat_BlinnShininessExponent( material ), maxMipLevel ); + #else + clearCoatRadiance += getLightProbeIndirectRadiance( /*specularLightProbe,*/ geometry.viewDir, geometry.normal, Material_ClearCoat_BlinnShininessExponent( material ), maxMipLevel ); + #endif #endif - #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 ba2bed2623f9781eed92b58c616f81d963907bed..ccbe7bffdfbf075a5e0d8b9a39c4ef3207938323 100644 --- a/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +++ b/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js @@ -65,9 +65,8 @@ float clearCoatDHRApprox( const in float roughness, const in float dotNL ) { #endif void RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { - + float dotNL = saturate( dot( geometry.normal, directLight.direction ) ); - vec3 irradiance = dotNL * directLight.color; #ifndef PHYSICALLY_CORRECT_LIGHTS @@ -77,19 +76,38 @@ void RE_Direct_Physical( const in IncidentLight directLight, const in GeometricC #endif #ifndef STANDARD - float clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL ); + #ifdef USE_CLEARCOAT_NORMALMAP + float ccDotNL = saturate( dot( geometry.clearCoatNormal, directLight.direction ) ); + vec3 ccIrradiance = ccDotNL * directLight.color; + + #ifndef PHYSICALLY_CORRECT_LIGHTS + + ccIrradiance *= PI; // punctual light + + #endif + #endif + #endif + + #ifndef STANDARD + #ifdef USE_CLEARCOAT_NORMALMAP + float clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, ccDotNL ); + #else + float clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL ); + #endif #else float clearCoatDHR = 0.0; #endif - reflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness ); + reflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness ); reflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ); #ifndef STANDARD - - reflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness ); - + #ifdef USE_CLEARCOAT_NORMALMAP + reflectedLight.directSpecular += ccIrradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.clearCoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness ); + #else + reflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness ); + #endif #endif } @@ -109,9 +127,13 @@ 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 ); + #ifdef USE_CLEARCOAT_NORMALMAP + float ccDotNV = saturate( dot( geometry.clearCoatNormal, geometry.viewDir ) ); + #else + float ccDotNV = saturate( dot( geometry.normal, geometry.viewDir ) ); + #endif + float ccDotNL = ccDotNV; + float clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, ccDotNL ); #else float clearCoatDHR = 0.0; #endif @@ -136,14 +158,16 @@ void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradia #else - reflectedLight.indirectSpecular += clearCoatInv * radiance * BRDF_Specular_GGX_Environment( geometry, material.specularColor, material.specularRoughness ); + reflectedLight.indirectSpecular += clearCoatInv * radiance * BRDF_Specular_GGX_Environment( geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness ); #endif #ifndef STANDARD - - reflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness ); - + #ifdef USE_CLEARCOAT_NORMALMAP + reflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry.viewDir, geometry.clearCoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness ); + #else + reflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry.viewDir, geometry.normal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness ); + #endif #endif } diff --git a/src/renderers/shaders/ShaderChunk/normal_fragment_begin.glsl.js b/src/renderers/shaders/ShaderChunk/normal_fragment_begin.glsl.js index 3d6d128e4338e4ee66d471a87b434c52d5fc4d03..f497cfa4200681eb28f6ef6c0c0c2ec3f1fef0c5 100644 --- a/src/renderers/shaders/ShaderChunk/normal_fragment_begin.glsl.js +++ b/src/renderers/shaders/ShaderChunk/normal_fragment_begin.glsl.js @@ -32,4 +32,7 @@ export default /* glsl */` #endif #endif +#if defined( PHYSICAL ) && !defined( STANDARD ) + vec3 geometryNormal = normal; +#endif `; diff --git a/src/renderers/shaders/ShaderChunk/normal_fragment_maps.glsl.js b/src/renderers/shaders/ShaderChunk/normal_fragment_maps.glsl.js index 9ec57d6327b110164ca67156c18782f4278cc671..b47a936e147d7a1b4d1b515ab35be3b4ee757183 100644 --- a/src/renderers/shaders/ShaderChunk/normal_fragment_maps.glsl.js +++ b/src/renderers/shaders/ShaderChunk/normal_fragment_maps.glsl.js @@ -30,7 +30,7 @@ export default /* glsl */` #else - normal = perturbNormal2Arb( -vViewPosition, normal ); + normal = perturbNormal2Arb( -vViewPosition, normal, normalScale, normalMap ); #endif diff --git a/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl.js index b645306e54f6ffcdc336a0192aa21a39567734bc..9d61e92374b26649541269161e08d49f7612c2e8 100644 --- a/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl.js +++ b/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl.js @@ -8,12 +8,15 @@ export default /* glsl */` uniform mat3 normalMatrix; - #else + #endif +#endif + +#if ( defined ( USE_NORMALMAP ) && !defined ( OBJECTSPACE_NORMALMAP )) || defined ( USE_CLEARCOAT_NORMALMAP ) // 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 ) { + vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec2 normalScale, in sampler2D normalMap ) { // Workaround for Adreno 3XX dFd*( vec3 ) bug. See #9988 @@ -37,8 +40,5 @@ export default /* glsl */` return normalize( tsn * mapN ); } - - #endif - #endif `; diff --git a/src/renderers/shaders/ShaderChunk/uv_pars_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/uv_pars_fragment.glsl.js index 3b8d5d675eff127787614765eaa848dadd8ff6df..ecea9ca95ffc8cd31ebf43cbd5671d6990b9e7d1 100644 --- a/src/renderers/shaders/ShaderChunk/uv_pars_fragment.glsl.js +++ b/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 ) +#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; diff --git a/src/renderers/shaders/ShaderChunk/uv_pars_vertex.glsl.js b/src/renderers/shaders/ShaderChunk/uv_pars_vertex.glsl.js index d1bd641d58a171ccce64b520283da60c09b19196..d22fc8b688e114095296e16e9586c0be93990226 100644 --- a/src/renderers/shaders/ShaderChunk/uv_pars_vertex.glsl.js +++ b/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; diff --git a/src/renderers/shaders/ShaderChunk/uv_vertex.glsl.js b/src/renderers/shaders/ShaderChunk/uv_vertex.glsl.js index 1a923a507eb0473c2ed5412f4c08d9fc60dcde8a..71007abbb60209062492a31f25656ddb71de875e 100644 --- a/src/renderers/shaders/ShaderChunk/uv_vertex.glsl.js +++ b/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; diff --git a/src/renderers/shaders/ShaderLib.js b/src/renderers/shaders/ShaderLib.js index 76f0c50cc50b78cb10f8733b834d51587b1bbb1b..68b5534ec1c1148ef9ee7db995f2c88c3d206768 100644 --- a/src/renderers/shaders/ShaderLib.js +++ b/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'; @@ -273,7 +274,9 @@ ShaderLib.physical = { ShaderLib.standard.uniforms, { clearCoat: { value: 0 }, - clearCoatRoughness: { value: 0 } + clearCoatRoughness: { value: 0 }, + 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 d909ad10d82793e9986ac229f8eb9f3672a74e42..084f1b12de31beed67421a729518ddd8bbdbd0bf 100644 --- a/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js +++ b/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js @@ -48,6 +48,7 @@ varying vec3 vViewPosition; #include #include #include +#include #include #include #include @@ -70,6 +71,8 @@ void main() { #include #include #include + #include + #include #include // accumulation diff --git a/src/renderers/shaders/ShaderLib/normal_frag.glsl.js b/src/renderers/shaders/ShaderLib/normal_frag.glsl.js index d9c640534ec1c686df230cdce28fcd9cb510be08..167b3147815c7345748c0dc9d1a0ffe1cc9f33da 100644 --- a/src/renderers/shaders/ShaderLib/normal_frag.glsl.js +++ b/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 ) varying vec3 vViewPosition; diff --git a/src/renderers/shaders/ShaderLib/normal_vert.glsl.js b/src/renderers/shaders/ShaderLib/normal_vert.glsl.js index 34cfaee75ce519d91fcdca997823c73e7aa71a3c..f07e0ba028b737c3005a5068595f5e435350e884 100644 --- a/src/renderers/shaders/ShaderLib/normal_vert.glsl.js +++ b/src/renderers/shaders/ShaderLib/normal_vert.glsl.js @@ -1,7 +1,7 @@ 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 ) varying vec3 vViewPosition; @@ -58,7 +58,7 @@ void main() { #include #include -#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 ) vViewPosition = - mvPosition.xyz; diff --git a/src/renderers/webgl/WebGLProgram.js b/src/renderers/webgl/WebGLProgram.js index d8ae626dc67b45e5cf74303a7e3e1247d76d1d06..4da986f08ac1b119a8b8cde748a21184a0e074f8 100644 --- a/src/renderers/webgl/WebGLProgram.js +++ b/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.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,7 @@ 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.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '', parameters.specularMap ? '#define USE_SPECULARMAP' : '', parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', @@ -500,6 +501,7 @@ 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.specularMap ? '#define USE_SPECULARMAP' : '', parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', diff --git a/src/renderers/webgl/WebGLPrograms.js b/src/renderers/webgl/WebGLPrograms.js index d790e453a53c04391da1f63697d3b7b30ff9ea9a..39fc74b2cdd6bc9f9943d4b37f448303bfc7bfec 100644 --- a/src/renderers/webgl/WebGLPrograms.js +++ b/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", "displacementMap", "specularMap", "roughnessMap", "metalnessMap", "gradientMap", "alphaMap", "combine", "vertexColors", "vertexTangents", "fog", "useFog", "fogExp", "flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning", @@ -153,6 +153,7 @@ function WebGLPrograms( renderer, extensions, capabilities ) { bumpMap: !! material.bumpMap, normalMap: !! material.normalMap, objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap, + clearCoatNormalMap: !! material.clearCoatNormalMap, displacementMap: !! material.displacementMap, roughnessMap: !! material.roughnessMap, metalnessMap: !! material.metalnessMap,