8000 PBR add multi scattering as energy compensation by zhuxudong · Pull Request #1370 · galacean/engine · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

PBR add multi scattering as energy compensation #1370

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commi 8000 ts
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion packages/core/src/material/PBRBaseMaterial.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Color, Vector4 } from "@oasis-engine/math";
import { Color, Vector3, Vector4 } from "@oasis-engine/math";
import { Logger } from "..";
import { Engine } from "../Engine";
import { Shader } from "../shader/Shader";
Expand All @@ -20,6 +20,9 @@ export abstract class PBRBaseMaterial extends BaseMaterial {
private static _clearCoatRoughnessTextureProp = Shader.getPropertyByName("u_clearCoatRoughnessTexture");
private static _clearCoatNormalTextureProp = Shader.getPropertyByName("u_clearCoatNormalTexture");

private static _anisotropyProp = Shader.getPropertyByName("u_anisotropy");
private static _anisotropyDirectionProp = Shader.getPropertyByName("u_anisotropyDirection");

/**
* Base color.
*/
Expand Down Expand Up @@ -243,6 +246,38 @@ export abstract class PBRBaseMaterial extends BaseMaterial {
}
}

/**
* The Amount of anisotropy. Scalar between −1 and 1
*/
get anisotropy(): number {
return this.shaderData.getFloat(PBRBaseMaterial._anisotropyProp);
}

set anisotropy(value: number) {
if (!!this.shaderData.getFloat(PBRBaseMaterial._anisotropyProp) !== !!value) {
if (value === 0) {
this.shaderData.disableMacro("HAS_ANISOTROPY");
} else {
this.shaderData.enableMacro("HAS_ANISOTROPY");
}
}
this.shaderData.setFloat(PBRBaseMaterial._anisotropyProp, value);
}

/**
* The direction of the surface to control the shape of the specular highlights
*/
get anisotropyDirection(): Vector3 {
return this.shaderData.getVector3(PBRBaseMaterial._anisotropyDirectionProp);
}

set anisotropyDirection(value: Vector3) {
const direction = this.shaderData.getVector3(PBRBaseMaterial._anisotropyDirectionProp);
if (value !== direction) {
direction.copyFrom(value);
}
}

/**
* Create a pbr base material instance.
* @param engine - Engine to which the material belongs
Expand All @@ -266,5 +301,8 @@ export abstract class PBRBaseMaterial extends BaseMaterial {

shaderData.setFloat(PBRBaseMaterial._clearCoatProp, 0);
shaderData.setFloat(PBRBaseMaterial._clearCoatRoughnessProp, 0);

shaderData.setFloat(PBRBaseMaterial._anisotropyProp, 0);
shaderData.setVector3(PBRBaseMaterial._anisotropyDirectionProp, new Vector3(1, 0, 0));
}
}
6 changes: 3 additions & 3 deletions packages/core/src/shaderlib/normal_get.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ vec3 getNormalByNormalTexture(mat3 tbn, sampler2D normalTexture, float normalInt
}

mat3 getTBN(){
#if defined(O3_HAS_NORMAL) && defined(O3_HAS_TANGENT) && ( defined(NORMALTEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) )
#if defined(O3_HAS_NORMAL) && defined(O3_HAS_TANGENT) && ( defined(NORMALTEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) || defined(HAS_ANISOTROPY) )
mat3 tbn = v_TBN;
#else
vec3 normal = getNormal();
Expand All @@ -43,13 +43,13 @@ mat3 getTBN(){
vec3 tangent = dp2perp * duv1.x + dp1perp * duv2.x;
vec3 binormal = dp2perp * duv1.y + dp1perp * duv2.y;

// construct a scale-invariant frame
// 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;
}
2 changes: 1 addition & 1 deletion packages/core/src/shaderlib/normal_share.glsl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef OMIT_NORMAL
#ifdef O3_HAS_NORMAL
varying vec3 v_normal;
#if defined(O3_HAS_TANGENT) && ( defined(NORMALTEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) )
#if defined(O3_HAS_TANGENT) && ( defined(NORMALTEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) || defined(HAS_ANISOTROPY) )
varying mat3 v_TBN;
#endif
#endif
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/shaderlib/normal_vert.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#ifdef O3_HAS_NORMAL
v_normal = normalize( mat3(u_normalMat) * normal );

#if defined(O3_HAS_TANGENT) && ( defined(NORMALTEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) )
#if defined(O3_HAS_TANGENT) && ( defined(NORMALTEXTURE) || defined(HAS_CLEARCOATNORMALTEXTURE) || defined(HAS_ANISOTROPY) )
vec3 normalW = normalize( mat3(u_normalMat) * normal.xyz );
vec3 tangentW = normalize( mat3(u_normalMat) * tangent.xyz );
vec3 bitangentW = cross( normalW, tangentW ) * tangent.w;
Expand Down
83 changes: 73 additions & 10 deletions packages/core/src/shaderlib/pbr/brdf.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ float G_GGX_SmithCorrelated(float alpha, float dotNL, float dotNV ) {

}

#if defined(HAS_ANISOTROPY)
float G_GGX_SmithCorrelated_Anisotropic(float at, float ab, float ToV, float BoV,
float ToL, float BoL, float NoV, float NoL) {
// Heitz 2014, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs"
// TODO: lambdaV can be pre-computed for all the lights, it should be moved out of this function
float lambdaV = NoL * length(vec3(at * ToV, ab * BoV, NoV));
float lambdaL = NoV * length(vec3(at * ToL, ab * BoL, NoL));
return 0.5 / max(lambdaV + lambdaL, EPSILON);
}
#endif

// Microfacet Models for Refraction through Rough Surfaces - equation (33)
// http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
// alpha is "roughness squared" in Disney’s reparameterization
Expand All @@ -42,25 +53,77 @@ float D_GGX(float alpha, float dotNH ) {

}

#if defined(HAS_ANISOTROPY)
float D_GGX_Anisotropic(float at, float ab, float ToH, float BoH, float NoH) {
// Burley 2012, "Physically-Based Shading at Disney"

// The values at and ab are perceptualRoughness^2, a2 is therefore perceptualRoughness^4
// The dot product below computes perceptualRoughness^8. We cannot fit in fp16 without clamping
// the roughness to too high values so we perform the dot product and the division in fp32
float a2 = at * ab;
highp vec3 d = vec3(ab * ToH, at * BoH, a2 * NoH);
highp float d2 = dot(d, d);
float b2 = a2 / d2;
return a2 * b2 * b2 * RECIPROCAL_PI;
}
#endif

vec3 isotropicLobe(vec3 specularColor, float alpha, float dotNV, float dotNL, float dotNH, float dotLH) {
vec3 F = F_Schlick( specularColor, dotLH );

float G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );

float D = D_GGX( alpha, dotNH );

return F * ( G * D );
}

#if defined(HAS_ANISOTROPY)
vec3 anisotropicLobe(vec3 h, vec3 l, Geometry geometry, vec3 specularColor, float alpha, float dotNV, float dotNL, float dotNH, float dotLH) {
vec3 t = geometry.anisotropicT;
vec3 b = geometry.anisotropicB;
vec3 v = geometry.viewDir;

float dotTV = dot(t, v);
float dotBV = dot(b, v);
float dotTL = dot(t, l);
float dotBL = dot(b, l);
float dotTH = dot(t, h);
float dotBH = dot(b, h);

float MIN_ROUGHNESS = 0.007921; // mobile
// Anisotropic parameters: at and ab are the roughness along the tangent and bitangent
// to simplify materials, we derive them from a single roughness parameter
// Kulla 2017, "Revisiting Physically Based Shading at Imageworks"
float at = max(alpha * (1.0 + geometry.anisotropy), MIN_ROUGHNESS);
float ab = max(alpha * (1.0 - geometry.anisotropy), MIN_ROUGHNESS);

// specular anisotropic BRDF
float D = D_GGX_Anisotropic(at, ab, dotTH, dotBH, dotNH);
float V = G_GGX_SmithCorrelated_Anisotropic(at, ab, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL);
vec3 F = F_Schlick( specularColor, dotLH );

1E0A
return (D * V) * F;
}
#endif

// GGX Distribution, Schlick Fresnel, GGX-Smith Visibility
vec3 BRDF_Specular_GGX(vec3 incidentDirection, vec3 viewDir, vec3 normal, vec3 specularColor, float roughness ) {
vec3 BRDF_Specular_GGX(vec3 incidentDirection, Geometry geometry, vec3 normal, vec3 specularColor, float roughness ) {

float alpha = pow2( roughness ); // UE4's roughness

vec3 halfDir = normalize( incidentDirection + viewDir );
vec3 halfDir = normalize( incidentDirection + geometry.viewDir );

float dotNL = saturate( dot( normal, incidentDirection ) );
float dotNV = saturate( dot( normal, viewDir ) );
float dotNV = saturate( dot( normal, geometry.viewDir ) );
float dotNH = saturate( dot( normal, halfDir ) );
float dotLH = saturate( dot( incidentDirection, halfDir ) );

vec3 F = F_Schlick( specularColor, dotLH );

float G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );

float D = D_GGX( alpha, dotNH );

return F * ( G * D );
#if defined(HAS_ANISOTROPY)
return anisotropicLobe(halfDir, incidentDirection, geometry, specularColor, alpha, dotNV, dotNL, dotNH, dotLH);
#else
return isotropicLobe(specularColor, alpha, dotNV, dotNL, dotNH, dotLH);
#endif

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ void addDirectRadiance(vec3 incidentDirection, vec3 color, Geometry geometry, Ma
#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 );

reflectedLight.directSpecular += material.clearCoat * clearCoatIrradiance * BRDF_Specular_GGX( incidentDirection, geometry, geometry.clearCoatNormal, vec3( 0.04 ), material.clearCoatRoughness );
attenuation -= material.clearCoat * F_Schlick(geometry.clearCoatDotNV);
#endif

float dotNL = saturate( dot( geometry.normal, incidentDirection ) );
vec3 irradiance = dotNL * color * PI;

reflectedLight.directSpecular += attenuation * irradiance * BRDF_Specular_GGX( incidentDirection, geometry.viewDir, geometry.normal, material.specularColor, material.roughness);
reflectedLight.directSpecular += attenuation * irradiance * BRDF_Specular_GGX( incidentDirection, geometry, geometry.normal, material.specularColor, material.roughness);
reflectedLight.directDiffuse += attenuation * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );

}
Expand Down Expand Up @@ -42,7 +42,7 @@ void addDirectRadiance(vec3 incidentDirection, vec3 color, Geometry geometry, Ma

vec3 color = pointLight.color;
color *= clamp(1.0 - pow(lightDistance/pointLight.distance, 4.0), 0.0, 1.0);

addDirectRadiance( direction, color, geometry, material, reflectedLight );

}
Expand All @@ -64,9 +64,9 @@ void addDirectRadiance(vec3 incidentDirection, vec3 color, Geometry geometry, Ma

vec3 color = spotLight.color;
color *= spotEffect * decayEffect;

addDirectRadiance( direction, color, geometry, material, reflectedLight );

}


Expand Down
84 changes: 73 additions & 11 deletions packages/core/src/shaderlib/pbr/ibl_frag_define.glsl
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// ------------------------Diffuse------------------------

// sh need be pre-scaled in CPU.
vec3 getLightProbeIrradiance(vec3 sh[9], vec3 normal){
normal.x = -normal.x;
Expand All @@ -19,11 +17,8 @@ vec3 getLightProbeIrradiance(vec3 sh[9], vec3 normal){

}

// ------------------------Specular------------------------

// ref: https://www.unrealengine.com/blog/physically-based-shading-on-mobile - environmentBRDF for GGX on mobile
vec3 envBRDFApprox(vec3 specularColor,float roughness, float dotNV ) {

vec2 lutApprox( float roughness, float dotNV ) {
const vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );

const vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );
Expand All @@ -34,24 +29,51 @@ vec3 envBRDFApprox(vec3 specularColor,float roughness, float dotNV ) {

vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;

return specularColor * AB.x + AB.y;
return AB;
}

vec3 envBRDF(vec3 specularColor,float roughness, float dotNV ) {
vec2 AB = lutApprox(roughness, dotNV);
return specularColor * AB.x + AB.y;
}


float getSpecularMIPLevel(float roughness, int maxMIPLevel ) {
return roughness * float(maxMIPLevel);
}

vec3 getLightProbeRadiance(vec3 viewDir, vec3 normal, float roughness, int maxMIPLevel, float specularIntensity) {
/**
* Returns the reflected vector at the current shading point. The reflected vector
* return by this function might be different from shading_reflected:
* - For anisotropic material, we bend the reflection vector to simulate
* anisotropic indirect lighting
* - The reflected vector may be modified to point towards the dominant specular
* direction to match reference renderings when the roughness increases
*/

vec3 getReflectedVector(Geometry geometry, const vec3 n, float roughness) {
#if defined(HAS_ANISOTROPY)
vec3 anisotropyDirection = geometry.anisotropy >= 0.0 ? geometry.anisotropicB : geometry.anisotropicT;
vec3 anisotropicTangent = cross(anisotropyDirection, geometry.viewDir);
vec3 anisotropicNormal = cross(anisotropicTangent, anisotropyDirection);
float bendFactor = abs(geometry.anisotropy) * saturate(5.0 * roughness);
vec3 bentNormal = normalize(mix(n, anisotropicNormal, bendFactor));

vec3 r = reflect(-geometry.viewDir, bentNormal);
#else
vec3 r = reflect(-geometry.viewDir, n);
#endif
return r;
}

vec3 getLightProbeRadiance(Geometry geometry, vec3 normal, float roughness, int maxMIPLevel, float specularIntensity) {

#ifndef O3_USE_SPECULAR_ENV

return vec3(0);

#else

vec3 reflectVec = reflect( -viewDir, normal );
vec3 reflectVec = getReflectedVector(geometry, normal, roughness);
reflectVec.x = -reflectVec.x; // TextureCube is left-hand,so x need inverse

float specularMIPLevel = getSpecularMIPLevel(roughness, maxMIPLevel );
Expand All @@ -77,4 +99,44 @@ vec3 getLightProbeRadiance(vec3 viewDir, vec3 normal, float roughness, int maxMI

#endif

}
}

void evaluateIBL(inout ReflectedLight reflectedLight, const Geometry geometry, const Material material ){
#ifdef O3_USE_SH
vec3 irradiance = getLightProbeIrradiance(u_env_sh, geometry.normal);
#ifdef OASIS_COLORSPACE_GAMMA
irradiance = linearToGamma(vec4(irradiance, 1.0)).rgb;
#endif
irradiance *= u_envMapLight.diffuseIntensity;
#else
vec3 irradiance = u_envMapLight.diffuse * u_envMapLight.diffuseIntensity;
irradiance *= PI;
#endif

reflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );


float radianceAttenuation = 1.0;
#ifdef CLEARCOAT
vec3 clearCoatRadiance = getLightProbeRadiance( geometry, geometry.clearCoatNormal, material.clearCoatRoughness, int(u_envMapLight.mipMapLevel), u_envMapLight.specularIntensity );

reflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * envBRDF(vec3( 0.04 ), material.clearCoatRoughness, geometry.clearCoatDotNV);
radianceAttenuation -= material.clearCoat * F_Schlick(geometry.clearCoatDotNV);
#endif

vec3 radiance = radianceAttenuation * getLightProbeRadiance(geometry, geometry.normal, material.roughness, int(u_envMapLight.mipMapLevel), u_envMapLight.specularIntensity);
vec2 fab = lutApprox( material.roughness, geometry.dotNV );
vec3 FssEss = material.specularColor * fab.x + fab.y;
reflectedLight.indirectSpecular += FssEss * radiance;

// multi scattering
float Ess = fab.x + fab.y;
float Ems = 1.0 - Ess;
vec3 Favg = material.specularColor + ( 1.0 - material.specularColor ) * 0.047619; // F0 + (1 - F0)/21;
vec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );
vec3 energyCompensation = Fms * Ems;
vec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;

reflectedLight.indirectSpecular += energyCompensation * cosineWeightedIrradiance;

}
Loading
0