Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: support pbr clearcoat #669

Merged
merged 19 commits into from
Apr 21, 2022
2 changes: 1 addition & 1 deletion packages/core/src/asset/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ function requestRes<T>(url: string, config: RequestConfig): AssetPromise<T> {
xhr.setRequestHeader(name, headers[name]);
});
}
xhr.send(config.body as XMLHttpRequestBodyInit);
xhr.send(config.body as any);
});
}

Expand Down
89 changes: 89 additions & 0 deletions packages/core/src/material/PBRBaseMaterial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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 <Texture2D>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 <Texture2D>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 <Texture2D>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
Expand All @@ -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);
}
}
8 changes: 4 additions & 4 deletions packages/core/src/material/PBRMaterial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -23,7 +23,7 @@ export class PBRMaterial extends PBRBaseMaterial {
}

/**
* Roughness.
* Roughness, default 1.0.
*/
get roughness(): number {
return this.shaderData.getFloat(PBRMaterial._roughnessProp);
Expand Down Expand Up @@ -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);
}

/**
Expand Down
12 changes: 5 additions & 7 deletions packages/core/src/shaderlib/begin_normal_vert.glsl
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions packages/core/src/shaderlib/blendShape_vert.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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];
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/shaderlib/common.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
}
Expand Down
8 changes: 7 additions & 1 deletion packages/core/src/shaderlib/mobile_blinnphong_frag.glsl
Original file line number Diff line number Diff line change
@@ -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 );

Expand Down
84 changes: 46 additions & 38 deletions packages/core/src/shaderlib/normal_get.glsl
Original file line number Diff line number Diff line change
@@ -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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe Mesh has tangent, only no normal?

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;
}
19 changes: 7 additions & 12 deletions packages/core/src/shaderlib/normal_share.glsl
Original file line number Diff line number Diff line change
@@ -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
19 changes: 8 additions & 11 deletions packages/core/src/shaderlib/normal_vert.glsl
Original file line number Diff line number Diff line change
@@ -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
18 changes: 13 additions & 5 deletions packages/core/src/shaderlib/pbr/brdf.glsl
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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 );
Expand All @@ -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;
}
Loading