diff --git a/packages/core/src/asset/request.ts b/packages/core/src/asset/request.ts index fd6bae53e0..bf79bba6cc 100644 --- a/packages/core/src/asset/request.ts +++ b/packages/core/src/asset/request.ts @@ -122,7 +122,7 @@ function requestRes(url: string, config: RequestConfig): AssetPromise { xhr.setRequestHeader(name, headers[name]); }); } - xhr.send(config.body as XMLHttpRequestBodyInit); + xhr.send(config.body as any); }); } diff --git a/packages/core/src/material/PBRBaseMaterial.ts b/packages/core/src/material/PBRBaseMaterial.ts index b4aaf04b6c..c677160564 100644 --- a/packages/core/src/material/PBRBaseMaterial.ts +++ b/packages/core/src/material/PBRBaseMaterial.ts @@ -21,6 +21,12 @@ export abstract class PBRBaseMaterial extends BaseMaterial { private static _emissiveTextureProp = Shader.getPropertyByName("u_emissiveSampler"); private static _occlusionTextureProp = Shader.getPropertyByName("u_occlusionSampler"); + private static _clearCoatProp = Shader.getPropertyByName("u_clearCoat"); + private static _clearCoatTextureProp = Shader.getPropertyByName("u_clearCoatTexture"); + private static _clearCoatRoughnessProp = Shader.getPropertyByName("u_clearCoatRoughness"); + private static _clearCoatRoughnessTextureProp = Shader.getPropertyByName("u_clearCoatRoughnessTexture"); + private static _clearCoatNormalTextureProp = Shader.getPropertyByName("u_clearCoatNormalTexture"); + /** * Base color. */ @@ -164,6 +170,86 @@ export abstract class PBRBaseMaterial extends BaseMaterial { } } + /** + * The clearCoat layer intensity, default 0. + */ + get clearCoat(): number { + return this.shaderData.getFloat(PBRBaseMaterial._clearCoatProp); + } + + set clearCoat(value: number) { + if (!!this.shaderData.getFloat(PBRBaseMaterial._clearCoatProp) !== !!value) { + if (value === 0) { + this.shaderData.disableMacro("CLEARCOAT"); + } else { + this.shaderData.enableMacro("CLEARCOAT"); + } + } + this.shaderData.setFloat(PBRBaseMaterial._clearCoatProp, value); + } + + /** + * The clearCoat layer intensity texture. + */ + get clearCoatTexture(): Texture2D { + return this.shaderData.getTexture(PBRBaseMaterial._clearCoatTextureProp); + } + + set clearCoatTexture(value: Texture2D) { + this.shaderData.setTexture(PBRBaseMaterial._clearCoatTextureProp, value); + + if (value) { + this.shaderData.enableMacro("HAS_CLEARCOATTEXTURE"); + } else { + this.shaderData.disableMacro("HAS_CLEARCOATTEXTURE"); + } + } + + /** + * The clearCoat layer roughness, default 0. + */ + get clearCoatRoughness(): number { + return this.shaderData.getFloat(PBRBaseMaterial._clearCoatRoughnessProp); + } + + set clearCoatRoughness(value: number) { + this.shaderData.setFloat(PBRBaseMaterial._clearCoatRoughnessProp, value); + } + + /** + * The clearCoat layer roughness texture. + */ + get clearCoatRoughnessTexture(): Texture2D { + return this.shaderData.getTexture(PBRBaseMaterial._clearCoatRoughnessTextureProp); + } + + set clearCoatRoughnessTexture(value: Texture2D) { + this.shaderData.setTexture(PBRBaseMaterial._clearCoatRoughnessTextureProp, value); + + if (value) { + this.shaderData.enableMacro("HAS_CLEARCOATROUGHNESSTEXTURE"); + } else { + this.shaderData.disableMacro("HAS_CLEARCOATROUGHNESSTEXTURE"); + } + } + + /** + * The clearCoat normal map texture. + */ + get clearCoatNormalTexture(): Texture2D { + return this.shaderData.getTexture(PBRBaseMaterial._clearCoatNormalTextureProp); + } + + set clearCoatNormalTexture(value: Texture2D) { + this.shaderData.setTexture(PBRBaseMaterial._clearCoatNormalTextureProp, value); + + if (value) { + this.shaderData.enableMacro("HAS_CLEARCOATNORMALTEXTURE"); + } else { + this.shaderData.disableMacro("HAS_CLEARCOATNORMALTEXTURE"); + } + } + /** * Create a pbr base material instance. * @param engine - Engine to which the material belongs @@ -184,5 +270,8 @@ export abstract class PBRBaseMaterial extends BaseMaterial { shaderData.setFloat(PBRBaseMaterial._normalTextureIntensityProp, 1); shaderData.setFloat(PBRBaseMaterial._occlusionTextureIntensityProp, 1); shaderData.setFloat(PBRBaseMaterial._occlusionTextureCoordProp, TextureCoordinate.UV0); + + shaderData.setFloat(PBRBaseMaterial._clearCoatProp, 0); + shaderData.setFloat(PBRBaseMaterial._clearCoatRoughnessProp, 0); } } diff --git a/packages/core/src/material/PBRMaterial.ts b/packages/core/src/material/PBRMaterial.ts index 3074529797..56666318e8 100644 --- a/packages/core/src/material/PBRMaterial.ts +++ b/packages/core/src/material/PBRMaterial.ts @@ -12,7 +12,7 @@ export class PBRMaterial extends PBRBaseMaterial { private static _metallicRoughnessTextureProp = Shader.getPropertyByName("u_metallicRoughnessSampler"); /** - * Metallic. + * Metallic, default 1.0. */ get metallic(): number { return this.shaderData.getFloat(PBRMaterial._metallicProp); @@ -23,7 +23,7 @@ export class PBRMaterial extends PBRBaseMaterial { } /** - * Roughness. + * Roughness, default 1.0. */ get roughness(): number { return this.shaderData.getFloat(PBRMaterial._roughnessProp); @@ -56,8 +56,8 @@ export class PBRMaterial extends PBRBaseMaterial { */ constructor(engine: Engine) { super(engine, Shader.find("pbr")); - this.shaderData.setFloat(PBRMaterial._metallicProp, 1.0); - this.shaderData.setFloat(PBRMaterial._roughnessProp, 1.0); + this.shaderData.setFloat(PBRMaterial._metallicProp, 1); + this.shaderData.setFloat(PBRMaterial._roughnessProp, 1); } /** diff --git a/packages/core/src/shaderlib/begin_normal_vert.glsl b/packages/core/src/shaderlib/begin_normal_vert.glsl index 1f0b8d165b..c7d1a3553b 100644 --- a/packages/core/src/shaderlib/begin_normal_vert.glsl +++ b/packages/core/src/shaderlib/begin_normal_vert.glsl @@ -1,11 +1,9 @@ +#ifndef OMIT_NORMAL #ifdef O3_HAS_NORMAL + vec3 normal = vec3( NORMAL ); + #endif - vec3 normal = vec3( NORMAL ); - - #if defined( O3_HAS_TANGENT ) && defined( O3_NORMAL_TEXTURE ) - + #ifdef O3_HAS_TANGENT vec4 tangent = vec4( TANGENT ); - - #endif - #endif +#endif \ No newline at end of file diff --git a/packages/core/src/shaderlib/blendShape_vert.glsl b/packages/core/src/shaderlib/blendShape_vert.glsl index 412fc6bc27..56830e882a 100644 --- a/packages/core/src/shaderlib/blendShape_vert.glsl +++ b/packages/core/src/shaderlib/blendShape_vert.glsl @@ -12,7 +12,7 @@ normal += getBlendShapeVertexElement(i, vertexElementOffset) * weight; #endif - #if defined( O3_HAS_TANGENT ) && defined( O3_NORMAL_TEXTURE ) && defined( OASIS_BLENDSHAPE_TANGENT ) + #if defined( O3_HAS_TANGENT ) && defined(OASIS_BLENDSHAPE_TANGENT) && ( defined(O3_NORMAL_TEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) ) vertexElementOffset += 1; tangent.xyz += getBlendShapeVertexElement(i, vertexElementOffset) * weight; #endif @@ -33,7 +33,7 @@ normal += NORMAL_BS3 * u_blendShapeWeights[3]; #endif - #if defined( O3_HAS_TANGENT ) && defined( O3_NORMAL_TEXTURE ) && defined( OASIS_BLENDSHAPE_TANGENT ) + #if defined( O3_HAS_TANGENT ) && defined(OASIS_BLENDSHAPE_TANGENT) && ( defined(O3_NORMAL_TEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) ) tangent.xyz += TANGENT_BS0 * u_blendShapeWeights[0]; tangent.xyz += TANGENT_BS1 * u_blendShapeWeights[1]; tangent.xyz += TANGENT_BS2 * u_blendShapeWeights[2]; diff --git a/packages/core/src/shaderlib/common.glsl b/packages/core/src/shaderlib/common.glsl index 026ff80b34..615638debf 100644 --- a/packages/core/src/shaderlib/common.glsl +++ b/packages/core/src/shaderlib/common.glsl @@ -6,6 +6,10 @@ #define saturate( a ) clamp( a, 0.0, 1.0 ) #define whiteCompliment(a) ( 1.0 - saturate( a ) ) +float pow2(float x ) { + return x * x; +} + vec4 RGBMToLinear(vec4 value, float maxRange ) { return vec4( value.rgb * value.a * maxRange, 1.0 ); } diff --git a/packages/core/src/shaderlib/mobile_blinnphong_frag.glsl b/packages/core/src/shaderlib/mobile_blinnphong_frag.glsl index 3b2b08c78f..0beae8db71 100644 --- a/packages/core/src/shaderlib/mobile_blinnphong_frag.glsl +++ b/packages/core/src/shaderlib/mobile_blinnphong_frag.glsl @@ -1,4 +1,10 @@ - vec3 N = getNormal(); + #ifdef O3_NORMAL_TEXTURE + mat3 tbn = getTBN(); + vec3 N = getNormalByNormalTexture(tbn, u_normalTexture, u_normalIntensity, v_uv); + #else + vec3 N = getNormal(); + #endif + vec3 lightDiffuse = vec3( 0.0, 0.0, 0.0 ); vec3 lightSpecular = vec3( 0.0, 0.0, 0.0 ); diff --git a/packages/core/src/shaderlib/normal_get.glsl b/packages/core/src/shaderlib/normal_get.glsl index b7b2223d71..05db910870 100644 --- a/packages/core/src/shaderlib/normal_get.glsl +++ b/packages/core/src/shaderlib/normal_get.glsl @@ -1,47 +1,55 @@ -vec3 getNormal() -{ - #ifdef O3_NORMAL_TEXTURE - #ifndef O3_HAS_TANGENT - #ifdef HAS_DERIVATIVES - vec3 pos_dx = dFdx(v_pos); - vec3 pos_dy = dFdy(v_pos); - vec3 tex_dx = dFdx(vec3(v_uv, 0.0)); - vec3 tex_dy = dFdy(vec3(v_uv, 0.0)); - vec3 t = (tex_dy.t * pos_dx - tex_dx.t * pos_dy) / (tex_dx.s * tex_dy.t - tex_dy.s * tex_dx.t); - #ifdef O3_HAS_NORMAL - vec3 ng = normalize(v_normal); - #else - vec3 ng = normalize( cross(pos_dx, pos_dy) ); - #endif - t = normalize(t - ng * dot(ng, t)); - vec3 b = normalize(cross(ng, t)); - mat3 tbn = mat3(t, b, ng); - #else - #ifdef O3_HAS_NORMAL - vec3 ng = normalize(v_normal); - #else - vec3 ng = vec3(0.0, 0.0, 1.0); - #endif - mat3 tbn = mat3(vec3(0.0), vec3(0.0), ng); - #endif - #else - mat3 tbn = v_TBN; - #endif - vec3 n = texture2D(u_normalTexture, v_uv ).rgb; - n = normalize(tbn * ((2.0 * n - 1.0) * vec3(u_normalIntensity, u_normalIntensity, 1.0))); - #else +vec3 getNormal(){ #ifdef O3_HAS_NORMAL - vec3 n = normalize(v_normal); + vec3 normal = v_normal; #elif defined(HAS_DERIVATIVES) vec3 pos_dx = dFdx(v_pos); vec3 pos_dy = dFdy(v_pos); - vec3 n = normalize( cross(pos_dx, pos_dy) ); + vec3 normal = normalize( cross(pos_dx, pos_dy) ); #else - vec3 n= vec3(0.0,0.0,1.0); + vec3 normal = vec3(0, 0, 1); #endif - #endif - n *= float( gl_FrontFacing ) * 2.0 - 1.0; + normal *= float( gl_FrontFacing ) * 2.0 - 1.0; + return normal; +} + +vec3 getNormalByNormalTexture(mat3 tbn, sampler2D normalTexture, float normalIntensity, vec2 uv){ + vec3 normal = texture2D(normalTexture, uv).rgb; + normal = normalize(tbn * ((2.0 * normal - 1.0) * vec3(normalIntensity, normalIntensity, 1.0))); + normal *= float( gl_FrontFacing ) * 2.0 - 1.0; - return n; + return normal; } + +mat3 getTBN(){ + #if defined(O3_HAS_NORMAL) && defined(O3_HAS_TANGENT) && ( defined(O3_NORMAL_TEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) ) + mat3 tbn = v_TBN; + #else + vec3 normal = getNormal(); + vec3 position = v_pos; + vec2 uv = gl_FrontFacing? v_uv: -v_uv; + + #ifdef HAS_DERIVATIVES + // ref: http://www.thetenthplanet.de/archives/1180 + // get edge vectors of the pixel triangle + vec3 dp1 = dFdx(position); + vec3 dp2 = dFdy(position); + vec2 duv1 = dFdx(uv); + vec2 duv2 = dFdy(uv); + + // solve the linear system + vec3 dp2perp = cross(dp2, normal); + vec3 dp1perp = cross(normal, dp1); + vec3 tangent = dp2perp * duv1.x + dp1perp * duv2.x; + vec3 binormal = dp2perp * duv1.y + dp1perp * duv2.y; + + // construct a scale-invariant frame + float invmax = inversesqrt(max(dot(tangent, tangent), dot(binormal, binormal))); + mat3 tbn = mat3(tangent * invmax, binormal * invmax, normal); + #else + mat3 tbn = mat3(vec3(0.0), vec3(0.0), normal); + #endif + #endif + + return tbn; +} \ No newline at end of file diff --git a/packages/core/src/shaderlib/normal_share.glsl b/packages/core/src/shaderlib/normal_share.glsl index d21d9322bc..fa03d27571 100644 --- a/packages/core/src/shaderlib/normal_share.glsl +++ b/packages/core/src/shaderlib/normal_share.glsl @@ -1,13 +1,8 @@ -#ifdef O3_HAS_NORMAL - - #if defined( O3_HAS_TANGENT ) && defined( O3_NORMAL_TEXTURE ) - - varying mat3 v_TBN; - - #else - - varying vec3 v_normal; - +#ifndef OMIT_NORMAL + #ifdef O3_HAS_NORMAL + varying vec3 v_normal; + #if defined(O3_HAS_TANGENT) && ( defined(O3_NORMAL_TEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) ) + varying mat3 v_TBN; + #endif #endif - -#endif +#endif \ No newline at end of file diff --git a/packages/core/src/shaderlib/normal_vert.glsl b/packages/core/src/shaderlib/normal_vert.glsl index 938ce04cac..9c44a0b3a6 100644 --- a/packages/core/src/shaderlib/normal_vert.glsl +++ b/packages/core/src/shaderlib/normal_vert.glsl @@ -1,16 +1,13 @@ +#ifndef OMIT_NORMAL #ifdef O3_HAS_NORMAL - - #if defined( O3_HAS_TANGENT ) && defined( O3_NORMAL_TEXTURE ) - - vec3 normalW = normalize( mat3(u_normalMat) * normal.xyz ); - vec3 tangentW = normalize( mat3(u_normalMat) * tangent.xyz ); - vec3 bitangentW = cross( normalW, tangentW ) * tangent.w; - v_TBN = mat3( tangentW, bitangentW, normalW ); - - #else - v_normal = normalize( mat3(u_normalMat) * normal ); - #endif + #if defined(O3_HAS_TANGENT) && ( defined(O3_NORMAL_TEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) ) + vec3 normalW = normalize( mat3(u_normalMat) * normal.xyz ); + vec3 tangentW = normalize( mat3(u_normalMat) * tangent.xyz ); + vec3 bitangentW = cross( normalW, tangentW ) * tangent.w; + v_TBN = mat3( tangentW, bitangentW, normalW ); + #endif #endif +#endif \ No newline at end of file diff --git a/packages/core/src/shaderlib/pbr/brdf.glsl b/packages/core/src/shaderlib/pbr/brdf.glsl index 4026207888..e88bcfe381 100644 --- a/packages/core/src/shaderlib/pbr/brdf.glsl +++ b/packages/core/src/shaderlib/pbr/brdf.glsl @@ -1,3 +1,7 @@ +float F_Schlick(float dotLH) { + return 0.04 + 0.96 * (pow(1.0 - dotLH, 5.0)); +} + vec3 F_Schlick(vec3 specularColor, float dotLH ) { // Original approximation by Christophe Schlick '94 @@ -39,15 +43,15 @@ float D_GGX(float alpha, float dotNH ) { } // GGX Distribution, Schlick Fresnel, GGX-Smith Visibility -vec3 BRDF_Specular_GGX(vec3 incidentDirection, GeometricContext geometry, vec3 specularColor, float roughness ) { +vec3 BRDF_Specular_GGX(vec3 incidentDirection, vec3 viewDir, vec3 normal, vec3 specularColor, float roughness ) { float alpha = pow2( roughness ); // UE4's roughness - vec3 halfDir = normalize( incidentDirection + geometry.viewDir ); + vec3 halfDir = normalize( incidentDirection + viewDir ); - float dotNL = saturate( dot( geometry.normal, incidentDirection ) ); - float dotNV = saturate( dot( geometry.normal, geometry.viewDir ) ); - float dotNH = saturate( dot( geometry.normal, halfDir ) ); + float dotNL = saturate( dot( normal, incidentDirection ) ); + float dotNV = saturate( dot( normal, viewDir ) ); + float dotNH = saturate( dot( normal, halfDir ) ); float dotLH = saturate( dot( incidentDirection, halfDir ) ); vec3 F = F_Schlick( specularColor, dotLH ); @@ -59,3 +63,7 @@ vec3 BRDF_Specular_GGX(vec3 incidentDirection, GeometricContext geometry, vec3 s return F * ( G * D ); } + +vec3 BRDF_Diffuse_Lambert(vec3 diffuseColor ) { + return RECIPROCAL_PI * diffuseColor; +} diff --git a/packages/core/src/shaderlib/pbr/direct_irradiance_frag_define.glsl b/packages/core/src/shaderlib/pbr/direct_irradiance_frag_define.glsl index 152150dd30..98bf83fd56 100644 --- a/packages/core/src/shaderlib/pbr/direct_irradiance_frag_define.glsl +++ b/packages/core/src/shaderlib/pbr/direct_irradiance_frag_define.glsl @@ -1,18 +1,25 @@ -void addDirectRadiance(vec3 incidentDirection, vec3 color, GeometricContext geometry, PhysicalMaterial material, inout ReflectedLight reflectedLight) { - float dotNL = saturate( dot( geometry.normal, incidentDirection ) ); +void addDirectRadiance(vec3 incidentDirection, vec3 color, Geometry geometry, Material material, inout ReflectedLight reflectedLight) { + float attenuation = 1.0; + + #ifdef CLEARCOAT + float clearCoatDotNL = saturate( dot( geometry.clearCoatNormal, incidentDirection ) ); + vec3 clearCoatIrradiance = clearCoatDotNL * color; + + reflectedLight.directSpecular += material.clearCoat * clearCoatIrradiance * BRDF_Specular_GGX( incidentDirection, geometry.viewDir, geometry.clearCoatNormal, vec3( 0.04 ), material.clearCoatRoughness ); + attenuation -= material.clearCoat * F_Schlick(geometry.clearCoatDotNV); + #endif - vec3 irradiance = dotNL * color; - irradiance *= PI; - - reflectedLight.directSpecular += irradiance * BRDF_Specular_GGX( incidentDirection, geometry, material.specularColor, material.roughness); + float dotNL = saturate( dot( geometry.normal, incidentDirection ) ); + vec3 irradiance = dotNL * color * PI; - reflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ); + reflectedLight.directSpecular += attenuation * irradiance * BRDF_Specular_GGX( incidentDirection, geometry.viewDir, geometry.normal, material.specularColor, material.roughness); + reflectedLight.directDiffuse += attenuation * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ); } #ifdef O3_DIRECT_LIGHT_COUNT - void addDirectionalDirectLightRadiance(DirectLight directionalLight, GeometricContext geometry, PhysicalMaterial material, inout ReflectedLight reflectedLight) { + void addDirectionalDirectLightRadiance(DirectLight directionalLight, Geometry geometry, Material material, inout ReflectedLight reflectedLight) { vec3 color = directionalLight.color; vec3 direction = -directionalLight.direction; @@ -24,7 +31,7 @@ void addDirectRadiance(vec3 incidentDirection, vec3 color, GeometricContext geom #ifdef O3_POINT_LIGHT_COUNT - void addPointDirectLightRadiance(PointLight pointLight, GeometricContext geometry, PhysicalMaterial material, inout ReflectedLight reflectedLight) { + void addPointDirectLightRadiance(PointLight pointLight, Geometry geometry, Material material, inout ReflectedLight reflectedLight) { vec3 lVector = pointLight.position - geometry.position; vec3 direction = normalize( lVector ); @@ -42,7 +49,7 @@ void addDirectRadiance(vec3 incidentDirection, vec3 color, GeometricContext geom #ifdef O3_SPOT_LIGHT_COUNT - void addSpotDirectLightRadiance(SpotLight spotLight, GeometricContext geometry, PhysicalMaterial material, inout ReflectedLight reflectedLight) { + void addSpotDirectLightRadiance(SpotLight spotLight, Geometry geometry, Material material, inout ReflectedLight reflectedLight) { vec3 lVector = spotLight.position - geometry.position; vec3 direction = normalize( lVector ); @@ -63,7 +70,7 @@ void addDirectRadiance(vec3 incidentDirection, vec3 color, GeometricContext geom #endif -void addTotalDirectRadiance(GeometricContext geometry, PhysicalMaterial material, inout ReflectedLight reflectedLight){ +void addTotalDirectRadiance(Geometry geometry, Material material, inout ReflectedLight reflectedLight){ #ifdef O3_DIRECT_LIGHT_COUNT DirectLight directionalLight; diff --git a/packages/core/src/shaderlib/pbr/ibl_frag_define.glsl b/packages/core/src/shaderlib/pbr/ibl_frag_define.glsl index 1a4a3ff8ff..2b523ceefa 100644 --- a/packages/core/src/shaderlib/pbr/ibl_frag_define.glsl +++ b/packages/core/src/shaderlib/pbr/ibl_frag_define.glsl @@ -42,7 +42,7 @@ float getSpecularMIPLevel(float roughness, int maxMIPLevel ) { return roughness * float(maxMIPLevel); } -vec3 getLightProbeRadiance(GeometricContext geometry, float roughness, int maxMIPLevel, float specularIntensity) { +vec3 getLightProbeRadiance(vec3 viewDir, vec3 normal, float roughness, int maxMIPLevel, float specularIntensity) { #ifndef O3_USE_SPECULAR_ENV @@ -50,7 +50,7 @@ vec3 getLightProbeRadiance(GeometricContext geometry, float roughness, int maxMI #else - vec3 reflectVec = reflect( -geometry.viewDir, geometry.normal ); + vec3 reflectVec = reflect( -viewDir, normal ); float specularMIPLevel = getSpecularMIPLevel(roughness, maxMIPLevel ); diff --git a/packages/core/src/shaderlib/pbr/pbr_frag.glsl b/packages/core/src/shaderlib/pbr/pbr_frag.glsl index 2f52e70e78..abc3a6b15b 100644 --- a/packages/core/src/shaderlib/pbr/pbr_frag.glsl +++ b/packages/core/src/shaderlib/pbr/pbr_frag.glsl @@ -1,7 +1,9 @@ -GeometricContext geometry = GeometricContext(v_pos, getNormal(), normalize(u_cameraPos - v_pos)); -PhysicalMaterial material = getPhysicalMaterial(u_baseColor, u_metal, u_roughness, u_specularColor, u_glossiness, u_alphaCutoff); -ReflectedLight reflectedLight = ReflectedLight( vec3( 0 ), vec3( 0 ), vec3( 0 ), vec3( 0 ) ); -float dotNV = saturate( dot( geometry.normal, geometry.viewDir ) ); +Geometry geometry; +Material material; +ReflectedLight reflectedLight; + +initGeometry(geometry); +initMaterial(material, geometry); // Direct Light addTotalDirectRadiance(geometry, material, reflectedLight); @@ -21,8 +23,18 @@ addTotalDirectRadiance(geometry, material, reflectedLight); reflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ); // IBL specular -vec3 radiance = getLightProbeRadiance( geometry, material.roughness, int(u_envMapLight.mipMapLevel), u_envMapLight.specularIntensity); -reflectedLight.indirectSpecular += radiance * envBRDFApprox(material.specularColor, material.roughness, dotNV ); +vec3 radiance = getLightProbeRadiance(geometry.viewDir, geometry.normal, material.roughness, int(u_envMapLight.mipMapLevel), u_envMapLight.specularIntensity); +float radianceAttenuation = 1.0; + +#ifdef CLEARCOAT + vec3 clearCoatRadiance = getLightProbeRadiance( geometry.viewDir, geometry.clearCoatNormal, material.clearCoatRoughness, int(u_envMapLight.mipMapLevel), u_envMapLight.specularIntensity ); + + reflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * envBRDFApprox(vec3( 0.04 ), material.clearCoatRoughness, geometry.clearCoatDotNV); + radianceAttenuation -= material.clearCoat * F_Schlick(geometry.clearCoatDotNV); +#endif + +reflectedLight.indirectSpecular += radianceAttenuation * radiance * envBRDFApprox(material.specularColor, material.roughness, geometry.dotNV ); + // Occlusion #ifdef HAS_OCCLUSIONMAP @@ -35,7 +47,7 @@ reflectedLight.indirectSpecular += radiance * envBRDFApprox(material.specularCol float ambientOcclusion = (texture2D(u_occlusionSampler, aoUV).r - 1.0) * u_occlusionStrength + 1.0; reflectedLight.indirectDiffuse *= ambientOcclusion; #ifdef O3_USE_SPECULAR_ENV - reflectedLight.indirectSpecular *= computeSpecularOcclusion(ambientOcclusion, material.roughness, dotNV); + reflectedLight.indirectSpecular *= computeSpecularOcclusion(ambientOcclusion, material.roughness, geometry.dotNV); #endif #endif diff --git a/packages/core/src/shaderlib/pbr/pbr_frag_define.glsl b/packages/core/src/shaderlib/pbr/pbr_frag_define.glsl index 75120b6928..928735fe78 100644 --- a/packages/core/src/shaderlib/pbr/pbr_frag_define.glsl +++ b/packages/core/src/shaderlib/pbr/pbr_frag_define.glsl @@ -1,5 +1,4 @@ uniform float u_alphaCutoff; - uniform vec4 u_baseColor; uniform float u_metal; uniform float u_roughness; @@ -7,10 +6,16 @@ uniform vec3 u_specularColor; uniform float u_glossiness; uniform vec3 u_emissiveColor; +#ifdef CLEARCOAT + uniform float u_clearCoat; + uniform float u_clearCoatRoughness; +#endif + uniform float u_normalIntensity; uniform float u_occlusionStrength; uniform float u_occlusionTextureCoord; +// Texture #ifdef HAS_BASECOLORMAP uniform sampler2D u_baseColorSampler; #endif @@ -36,21 +41,49 @@ uniform float u_occlusionTextureCoord; uniform sampler2D u_occlusionSampler; #endif +#ifdef HAS_CLEARCOATTEXTURE + uniform sampler2D u_clearCoatTexture; +#endif + +#ifdef HAS_CLEARCOATROUGHNESSTEXTURE + uniform sampler2D u_clearCoatRoughnessTexture; +#endif + +#ifdef HAS_CLEARCOATNORMALTEXTURE + uniform sampler2D u_clearCoatNormalTexture; +#endif + + +// Runtime struct ReflectedLight { vec3 directDiffuse; vec3 directSpecular; vec3 indirectDiffuse; vec3 indirectSpecular; }; -struct GeometricContext { + +struct Geometry { vec3 position; vec3 normal; vec3 viewDir; + float dotNV; + + #ifdef CLEARCOAT + vec3 clearCoatNormal; + float clearCoatDotNV; + #endif + }; -struct PhysicalMaterial { + +struct Material { vec3 diffuseColor; float roughness; vec3 specularColor; float opacity; + #ifdef CLEARCOAT + float clearCoat; + float clearCoatRoughness; + #endif + }; diff --git a/packages/core/src/shaderlib/pbr/pbr_helper.glsl b/packages/core/src/shaderlib/pbr/pbr_helper.glsl index 5d626fbc8f..8b9b8d3ffd 100644 --- a/packages/core/src/shaderlib/pbr/pbr_helper.glsl +++ b/packages/core/src/shaderlib/pbr/pbr_helper.glsl @@ -1,44 +1,70 @@ #include -float pow2(float x ) { - return x * x; +float computeSpecularOcclusion(float ambientOcclusion, float roughness, float dotNV ) { + return saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion ); } -vec3 BRDF_Diffuse_Lambert(vec3 diffuseColor ) { - return RECIPROCAL_PI * diffuseColor; +float getAARoughnessFactor(vec3 normal) { + #ifdef HAS_DERIVATIVES + vec3 dxy = max( abs(dFdx(normal)), abs(dFdy(normal)) ); + return max( max(dxy.x, dxy.y), dxy.z ); + #else + return 0.04; + #endif } +void initGeometry(out Geometry geometry){ + geometry.position = v_pos; + geometry.viewDir = normalize(u_cameraPos - v_pos); + + #if defined(O3_NORMAL_TEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) + mat3 tbn = getTBN(); + #endif + + #ifdef O3_NORMAL_TEXTURE + geometry.normal = getNormalByNormalTexture(tbn, u_normalTexture, u_normalIntensity, v_uv); + #else + geometry.normal = getNormal(); + #endif + + geometry.dotNV = saturate( dot(geometry.normal, geometry.viewDir) ); + + + #ifdef CLEARCOAT + #ifdef HAS_CLEARCOATNORMALTEXTURE + geometry.clearCoatNormal = getNormalByNormalTexture(tbn, u_clearCoatNormalTexture, u_normalIntensity, v_uv); + #else + geometry.clearCoatNormal = getNormal(); + #endif + geometry.clearCoatDotNV = saturate( dot(geometry.clearCoatNormal, geometry.viewDir) ); + #endif -float computeSpecularOcclusion(float ambientOcclusion, float roughness, float dotNV ) { - return saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion ); } -PhysicalMaterial getPhysicalMaterial( - vec4 diffuseColor, - float metal, - float roughness, - vec3 specularColor, - float glossiness, - float alphaCutoff - ){ - PhysicalMaterial material; +void initMaterial(out Material material, const in Geometry geometry){ + vec4 baseColor = u_baseColor; + float metal = u_metal; + float roughness = u_roughness; + vec3 specularColor = u_specularColor; + float glossiness = u_glossiness; + float alphaCutoff = u_alphaCutoff; #ifdef HAS_BASECOLORMAP - vec4 baseColor = texture2D(u_baseColorSampler, v_uv); + vec4 baseTextureColor = texture2D(u_baseColorSampler, v_uv); #ifndef OASIS_COLORSPACE_GAMMA - baseColor = gammaToLinear(baseColor); + baseTextureColor = gammaToLinear(baseTextureColor); #endif - diffuseColor *= baseColor; + baseColor *= baseTextureColor; #endif #ifdef O3_HAS_VERTEXCOLOR - diffuseColor *= v_color; + baseColor *= v_color; #endif #ifdef ALPHA_CUTOFF - if( diffuseColor.a < alphaCutoff ) { + if( baseColor.a < alphaCutoff ) { discard; } #endif @@ -51,25 +77,41 @@ PhysicalMaterial getPhysicalMaterial( #ifdef HAS_SPECULARGLOSSINESSMAP vec4 specularGlossinessColor = texture2D(u_specularGlossinessSampler, v_uv ); + #ifndef OASIS_COLORSPACE_GAMMA + specularGlossinessColor = gammaToLinear(specularGlossinessColor); + #endif specularColor *= specularGlossinessColor.rgb; glossiness *= specularGlossinessColor.a; #endif #ifdef IS_METALLIC_WORKFLOW - material.diffuseColor = diffuseColor.rgb * ( 1.0 - metal ); - material.specularColor = mix( vec3( 0.04), diffuseColor.rgb, metal ); - material.roughness = clamp( roughness, 0.04, 1.0 ); + material.diffuseColor = baseColor.rgb * ( 1.0 - metal ); + material.specularColor = mix( vec3( 0.04), baseColor.rgb, metal ); + material.roughness = roughness; #else float specularStrength = max( max( specularColor.r, specularColor.g ), specularColor.b ); - material.diffuseColor = diffuseColor.rgb * ( 1.0 - specularStrength ); + material.diffuseColor = baseColor.rgb * ( 1.0 - specularStrength ); material.specularColor = specularColor; - material.roughness = clamp( 1.0 - glossiness, 0.04, 1.0 ); + material.roughness = 1.0 - glossiness; #endif - material.opacity = diffuseColor.a; - return material; + material.roughness = max(material.roughness, getAARoughnessFactor(geometry.normal)); + + #ifdef CLEARCOAT + material.clearCoat = u_clearCoat; + material.clearCoatRoughness = u_clearCoatRoughness; + #ifdef HAS_CLEARCOATTEXTURE + material.clearCoat *= texture2D( u_clearCoatTexture, v_uv ).r; + #endif + #ifdef HAS_CLEARCOATROUGHNESSTEXTURE + material.clearCoatRoughness *= texture2D( u_clearCoatRoughnessTexture, v_uv ).g; + #endif + material.clearCoat = saturate( material.clearCoat ); + material.clearCoatRoughness = max(material.clearCoatRoughness, getAARoughnessFactor(geometry.clearCoatNormal)); + #endif + material.opacity = baseColor.a; } // direct + indirect diff --git a/packages/core/src/shaderlib/skinning_vert.glsl b/packages/core/src/shaderlib/skinning_vert.glsl index 0874956155..b0eba9a14e 100644 --- a/packages/core/src/shaderlib/skinning_vert.glsl +++ b/packages/core/src/shaderlib/skinning_vert.glsl @@ -19,7 +19,7 @@ #if defined(O3_HAS_NORMAL) && !defined(OMIT_NORMAL) normal = vec4( skinMatrix * vec4( normal, 0.0 ) ).xyz; - #if defined( O3_HAS_TANGENT ) && defined( O3_NORMAL_TEXTURE ) + #if defined(O3_HAS_TANGENT) && ( defined(O3_NORMAL_TEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) ) tangent.xyz = vec4( skinMatrix * vec4( tangent.xyz, 0.0 ) ).xyz; #endif diff --git a/packages/loader/src/gltf/extensions/KHR_materials_clearcoat.ts b/packages/loader/src/gltf/extensions/KHR_materials_clearcoat.ts index e69de29bb2..1c204e4ae8 100644 --- a/packages/loader/src/gltf/extensions/KHR_materials_clearcoat.ts +++ b/packages/loader/src/gltf/extensions/KHR_materials_clearcoat.ts @@ -0,0 +1,36 @@ +import { PBRMaterial } from "@oasis-engine/core"; +import { GLTFResource } from "../GLTFResource"; +import { MaterialParser } from "../parser/MaterialParser"; +import { registerExtension } from "../parser/Parser"; +import { ExtensionParser } from "./ExtensionParser"; +import { IKHRMaterialsClearcoat } from "./Schema"; + +@registerExtension("KHR_materials_clearcoat") +class KHR_materials_clearcoat extends ExtensionParser { + parseEngineResource(schema: IKHRMaterialsClearcoat, material: PBRMaterial, context: GLTFResource): void { + const { textures } = context; + const { + clearcoatFactor = 0, + clearcoatTexture, + clearcoatRoughnessFactor = 0, + clearcoatRoughnessTexture, + clearcoatNormalTexture + } = schema; + + material.clearCoat = clearcoatFactor; + material.clearCoatRoughness = clearcoatRoughnessFactor; + + if (clearcoatTexture) { + material.clearCoatTexture = textures[clearcoatTexture.index]; + MaterialParser._parseTextureTransform(material, clearcoatTexture.extensions, context); + } + if (clearcoatRoughnessTexture) { + material.clearCoatRoughnessTexture = textures[clearcoatRoughnessTexture.index]; + MaterialParser._parseTextureTransform(material, clearcoatRoughnessTexture.extensions, context); + } + if (clearcoatNormalTexture) { + material.clearCoatNormalTexture = textures[clearcoatNormalTexture.index]; + MaterialParser._parseTextureTransform(material, clearcoatNormalTexture.extensions, context); + } + } +} diff --git a/packages/loader/src/gltf/extensions/KHR_materials_pbrSpecularGlossiness.ts b/packages/loader/src/gltf/extensions/KHR_materials_pbrSpecularGlossiness.ts index fd78e27579..6faeef7983 100644 --- a/packages/loader/src/gltf/extensions/KHR_materials_pbrSpecularGlossiness.ts +++ b/packages/loader/src/gltf/extensions/KHR_materials_pbrSpecularGlossiness.ts @@ -14,7 +14,12 @@ class KHR_materials_pbrSpecularGlossiness extends ExtensionParser { const { diffuseFactor, diffuseTexture, specularFactor, glossinessFactor, specularGlossinessTexture } = schema; if (diffuseFactor) { - material.baseColor = new Color(...diffuseFactor); + material.baseColor = new Color( + Color.linearToGammaSpace(diffuseFactor[0]), + Color.linearToGammaSpace(diffuseFactor[1]), + Color.linearToGammaSpace(diffuseFactor[2]), + diffuseFactor[3] + ); } if (diffuseTexture) { @@ -23,7 +28,11 @@ class KHR_materials_pbrSpecularGlossiness extends ExtensionParser { } if (specularFactor) { - material.specularColor = new Color(...specularFactor); + material.specularColor = new Color( + Color.linearToGammaSpace(specularFactor[0]), + Color.linearToGammaSpace(specularFactor[1]), + Color.linearToGammaSpace(specularFactor[2]) + ); } if (glossinessFactor !== undefined) { diff --git a/packages/loader/src/gltf/parser/MaterialParser.ts b/packages/loader/src/gltf/parser/MaterialParser.ts index c06a097fc8..802a9278b7 100644 --- a/packages/loader/src/gltf/parser/MaterialParser.ts +++ b/packages/loader/src/gltf/parser/MaterialParser.ts @@ -41,7 +41,7 @@ export class MaterialParser extends Parser { name = "" } = gltf.materials[i]; - const { KHR_materials_unlit, KHR_materials_pbrSpecularGlossiness } = extensions; + const { KHR_materials_unlit, KHR_materials_pbrSpecularGlossiness, KHR_materials_clearcoat } = extensions; let material: UnlitMaterial | PBRMaterial | PBRSpecularMaterial = null; @@ -61,12 +61,21 @@ export class MaterialParser extends Parser { material.name = name; + if (KHR_materials_clearcoat) { + Parser.parseEngineResource("KHR_materials_clearcoat", KHR_materials_clearcoat, material, context); + } + if (pbrMetallicRoughness) { const { baseColorFactor, baseColorTexture, metallicFactor, roughnessFactor, metallicRoughnessTexture } = pbrMetallicRoughness; if (baseColorFactor) { - material.baseColor = new Color(...baseColorFactor); + material.baseColor = new Color( + Color.linearToGammaSpace(baseColorFactor[0]), + Color.linearToGammaSpace(baseColorFactor[1]), + Color.linearToGammaSpace(baseColorFactor[2]), + baseColorFactor[3] + ); } if (baseColorTexture) { material.baseTexture = textures[baseColorTexture.index]; @@ -93,7 +102,11 @@ export class MaterialParser extends Parser { } if (emissiveFactor) { - m.emissiveColor = new Color(...emissiveFactor); + m.emissiveColor = new Color( + Color.linearToGammaSpace(emissiveFactor[0]), + Color.linearToGammaSpace(emissiveFactor[1]), + Color.linearToGammaSpace(emissiveFactor[2]) + ); } if (normalTexture) {