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

Add iri/sheen/rafraction in glsl version #2518

Merged
merged 4 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
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
8 changes: 8 additions & 0 deletions packages/core/src/shaderlib/common.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#define RECIPROCAL_PI 0.31830988618
#define EPSILON 1e-6
#define LOG2 1.442695
#define HALF_MIN 6.103515625e-5 // 2^-14, the same value for 10, 11 and 16-bit: https://www.khronos.org/opengl/wiki/Small_Float_Formats
#define HALF_EPS 4.8828125e-4 // 2^-11, machine epsilon: 1 + EPS = 1 (half of the ULP for 1.0f)

#define saturate( a ) clamp( a, 0.0, 1.0 )

Expand Down Expand Up @@ -93,3 +95,9 @@ float remapDepthBufferLinear01(float z){

#define INVERSE_MAT(mat) inverseMat(mat)
#endif


vec3 safeNormalize(vec3 inVec) {
float dp3 = max(float(HALF_MIN), dot(inVec, inVec));
return inVec * inversesqrt(dp3);
}
1 change: 1 addition & 0 deletions packages/core/src/shaderlib/extra/pbr.fs.glsl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#define IS_METALLIC_WORKFLOW
#include <common>
#include <camera_declare>
#include <transform_declare>

#include <FogFragmentDeclaration>

Expand Down
149 changes: 139 additions & 10 deletions packages/core/src/shaderlib/pbr/brdf.glsl
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@

#ifdef MATERIAL_ENABLE_SHEEN
uniform sampler2D scene_PrefilteredDFG;
#endif

float F_Schlick(float f0, float dotLH) {
return f0 + 0.96 * (pow(1.0 - dotLH, 5.0));
}
Expand Down Expand Up @@ -53,6 +57,39 @@ float D_GGX(float alpha, float dotNH ) {

}

#ifdef MATERIAL_ENABLE_SHEEN
// http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf
float D_Charlie(float roughness, float dotNH) {
float invAlpha = 1.0 / roughness;
float cos2h = dotNH * dotNH;
float sin2h = max(1.0 - cos2h, 0.0078125); // 2^(-14/2), so sin2h^2 > 0 in fp16
return (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI);
}

// Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886".
float V_Neubelt(float NoV, float NoL) {
return saturate(1.0 / (4.0 * (NoL + NoV - NoL * NoV)));
}

vec3 sheenBRDF(vec3 incidentDirection, Geometry geometry, vec3 sheenColor, float sheenRoughness) {
vec3 halfDir = normalize(incidentDirection + geometry.viewDir);
float dotNL = saturate(dot(geometry.normal, incidentDirection));
float dotNH = saturate(dot(geometry.normal, halfDir));
float D = D_Charlie(sheenRoughness, dotNH);
float V = V_Neubelt(geometry.dotNV, dotNL);
vec3 F = sheenColor;
return D * V * F;
}

float prefilteredSheenDFG(float dotNV, float sheenRoughness) {
#ifdef HAS_TEX_LOD
return texture2DLodEXT(scene_PrefilteredDFG, vec2(dotNV, sheenRoughness), 0.0).b;
#else
return texture2D(scene_PrefilteredDFG, vec2(dotNV, sheenRoughness),0.0).b;
#endif
}
#endif

#ifdef MATERIAL_ENABLE_ANISOTROPY
// GGX Distribution Anisotropic
// https://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v3.pdf Addenda
Expand All @@ -65,16 +102,14 @@ float D_GGX(float alpha, float dotNH ) {
}
#endif

vec3 isotropicLobe(vec3 specularColor, float alpha, float dotNV, float dotNL, float dotNH, float dotLH) {
vec3 F = F_Schlick( specularColor, dotLH );
float DG_GGX(float alpha, float dotNV, float dotNL, float dotNH) {
float D = D_GGX( alpha, dotNH );
float G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );

return F * ( G * D );
return G * D;
}

#ifdef MATERIAL_ENABLE_ANISOTROPY
vec3 anisotropicLobe(vec3 h, vec3 l, Geometry geometry, vec3 specularColor, float alpha, float dotNV, float dotNL, float dotNH, float dotLH) {
float DG_GGX_anisotropic(vec3 h, vec3 l, Geometry geometry, float alpha, float dotNV, float dotNL, float dotNH) {
vec3 t = geometry.anisotropicT;
vec3 b = geometry.anisotropicB;
vec3 v = geometry.viewDir;
Expand All @@ -92,16 +127,104 @@ vec3 isotropicLobe(vec3 specularColor, float alpha, float dotNV, float dotNL, fl
float ab = max(alpha * (1.0 - geometry.anisotropy), MIN_ROUGHNESS);

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

return F * ( G * D );
return G * D;
}
#endif

#ifdef MATERIAL_ENABLE_IRIDESCENCE
vec3 iorToFresnel0(vec3 transmittedIOR, float incidentIOR) {
return pow((transmittedIOR - incidentIOR) / (transmittedIOR + incidentIOR),vec3(2.0));
}

float iorToFresnel0(float transmittedIOR, float incidentIOR) {
return pow((transmittedIOR - incidentIOR) / (transmittedIOR + incidentIOR),2.0);
}

// Assume air interface for top
// Note: We don't handle the case fresnel0 == 1
vec3 fresnelToIOR(vec3 f0){
vec3 sqrtF0 = sqrt(f0);
return (vec3(1.0) + sqrtF0) / (vec3(1.0) - sqrtF0);
}

// Fresnel equations for dielectric/dielectric interfaces.
// Ref: https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html
// Evaluation XYZ sensitivity curves in Fourier space
vec3 evalSensitivity(float opd, vec3 shift){
// Use Gaussian fits, given by 3 parameters: val, pos and var
float phase = 2.0 * PI * opd * 1.0e-9;
const vec3 val = vec3(5.4856e-13, 4.4201e-13, 5.2481e-13);
const vec3 pos = vec3(1.6810e+06, 1.7953e+06, 2.2084e+06);
const vec3 var = vec3(4.3278e+09, 9.3046e+09, 6.6121e+09);
vec3 xyz = val * sqrt(2.0 * PI * var) * cos(pos * phase + shift) * exp(-var * pow2(phase));
xyz.x += 9.7470e-14 * sqrt(2.0 * PI * 4.5282e+09) * cos(2.2399e+06 * phase + shift[0]) * exp(-4.5282e+09 * pow2(phase));
xyz /= 1.0685e-7;
// XYZ to RGB color space
const mat3 XYZ_TO_RGB = mat3( 3.2404542, -0.9692660, 0.0556434,
-1.5371385, 1.8760108, -0.2040259,
-0.4985314, 0.0415560, 1.0572252);
vec3 rgb = XYZ_TO_RGB * xyz;
return rgb;
}

vec3 evalIridescenceSpecular(float outsideIOR, float dotNV, float thinIOR, vec3 baseF0,float iridescenceThickness){
vec3 iridescence = vec3(1.0);
// Force iridescenceIOR -> outsideIOR when thinFilmThickness -> 0.0
float iridescenceIOR = mix( outsideIOR, thinIOR, smoothstep( 0.0, 0.03, iridescenceThickness ) );
// Evaluate the cosTheta on the base layer (Snell law)
float sinTheta2Sq = pow( outsideIOR / iridescenceIOR, 2.0) * (1.0 - pow( dotNV, 2.0));
float cosTheta2Sq = 1.0 - sinTheta2Sq;
// Handle total internal reflection
if (cosTheta2Sq < 0.0) {
return iridescence;
}
float cosTheta2 = sqrt(cosTheta2Sq);

// First interface
float f0 = iorToFresnel0(iridescenceIOR, outsideIOR);
float reflectance = F_Schlick(f0, dotNV);
float t121 = 1.0 - reflectance;
float phi12 = 0.0;
// iridescenceIOR has limited greater than 1.0
// if (iridescenceIOR < outsideIOR) {phi12 = PI;}
float phi21 = PI - phi12;

// Second interface
vec3 baseIOR = fresnelToIOR(clamp(baseF0, 0.0, 0.9999)); // guard against 1.0
vec3 r1 = iorToFresnel0(baseIOR, iridescenceIOR);
vec3 r23 = F_Schlick(r1, cosTheta2);
vec3 phi23 =vec3(0.0);
if (baseIOR[0] < iridescenceIOR) {phi23[0] = PI;}
if (baseIOR[1] < iridescenceIOR) {phi23[1] = PI;}
if (baseIOR[2] < iridescenceIOR) {phi23[2] = PI;}

// Phase shift
float opd = 2.0 * iridescenceIOR * iridescenceThickness * cosTheta2;
vec3 phi = vec3(phi21) + phi23;

// Compound terms
vec3 r123 = clamp(reflectance * r23, 1e-5, 0.9999);
vec3 sr123 = sqrt(r123);
vec3 rs = pow2(t121) * r23 / (vec3(1.0) - r123);
// Reflectance term for m = 0 (DC term amplitude)
vec3 c0 = reflectance + rs;
iridescence = c0;
// Reflectance term for m > 0 (pairs of diracs)
vec3 cm = rs - t121;
for (int m = 1; m <= 2; ++m) {
cm *= sr123;
vec3 sm = 2.0 * evalSensitivity(float(m) * opd, float(m) * phi);
iridescence += cm * sm;
}
return iridescence = max(iridescence, vec3(0.0));
}
#endif

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

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

Expand All @@ -112,12 +235,18 @@ vec3 BRDF_Specular_GGX(vec3 incidentDirection, Geometry geometry, vec3 normal, v
float dotNH = saturate( dot( normal, halfDir ) );
float dotLH = saturate( dot( incidentDirection, halfDir ) );

vec3 F = F_Schlick( specularColor, dotLH );
#ifdef MATERIAL_ENABLE_IRIDESCENCE
F = mix(F, material.iridescenceSpecularColor, material.iridescenceFactor);
#endif

#ifdef MATERIAL_ENABLE_ANISOTROPY
return anisotropicLobe(halfDir, incidentDirection, geometry, specularColor, alpha, dotNV, dotNL, dotNH, dotLH);
float GD = DG_GGX_anisotropic(halfDir, incidentDirection, geometry, alpha, dotNV, dotNL, dotNH);
#else
return isotropicLobe(specularColor, alpha, dotNV, dotNL, dotNH, dotLH);
float GD = DG_GGX(alpha, dotNV, dotNL, dotNH);
#endif

return F * GD;
}

vec3 BRDF_Diffuse_Lambert(vec3 diffuseColor ) {
Expand Down
37 changes: 37 additions & 0 deletions packages/core/src/shaderlib/pbr/btdf.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <refraction>

#ifdef MATERIAL_ENABLE_TRANSMISSION
uniform sampler2D camera_OpaqueTexture;
vec3 evaluateTransmission(Geometry geometry, Material material) {
RefractionModelResult ray;
#if REFRACTION_MODE == 0
// RefractionMode.Sphere
refractionModelSphere(-geometry.viewDir, geometry.position, geometry.normal, material.IOR, material.thickness, ray);
#elif REFRACTION_MODE == 1
// RefractionMode.Planar
refractionModelPlanar(-geometry.viewDir, geometry.position, geometry.normal, material.IOR, material.thickness, ray);
#endif

vec3 refractedRayExit = ray.positionExit;

// We calculate the screen space position of the refracted point
vec4 samplingPositionNDC = camera_ProjMat * camera_ViewMat * vec4( refractedRayExit, 1.0 );
vec2 refractionCoords = (samplingPositionNDC.xy / samplingPositionNDC.w) * 0.5 + 0.5;

// Sample the opaque texture to get the transmitted light
vec3 refractionTransmitted = texture2D(camera_OpaqueTexture, refractionCoords).rgb;
refractionTransmitted *= material.diffuseColor;

// Use specularFGD as an approximation of the fresnel effect
// https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf
refractionTransmitted *= (1.0 - material.envSpecularDFG);

#ifdef MATERIAL_HAS_THICKNESS
// Absorption coefficient from Disney: http://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf
vec3 transmittance = min(vec3(1.0), exp(-material.absorptionCoefficient * ray.transmissionLength));
refractionTransmitted *= transmittance;
#endif

return refractionTransmitted;
}
#endif
16 changes: 14 additions & 2 deletions packages/core/src/shaderlib/pbr/direct_irradiance_frag_define.glsl
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
#include <ShadowFragmentDeclaration>

void sheenLobe(Geometry geometry, Material material, vec3 incidentDirection, vec3 attenuationIrradiance, inout vec3 diffuseColor, inout vec3 specularColor){
#ifdef MATERIAL_ENABLE_SHEEN
diffuseColor *= material.sheenScaling;
specularColor *= material.sheenScaling;

specularColor += attenuationIrradiance * sheenBRDF(incidentDirection, geometry, material.sheenColor, material.sheenRoughness);
#endif
}

void addDirectRadiance(vec3 incidentDirection, vec3 color, Geometry geometry, Material material, inout ReflectedLight reflectedLight) {
float attenuation = 1.0;

#ifdef MATERIAL_ENABLE_CLEAR_COAT
float clearCoatDotNL = saturate( dot( geometry.clearCoatNormal, incidentDirection ) );
vec3 clearCoatIrradiance = clearCoatDotNL * color;

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

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

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

// Sheen Lobe
sheenLobe(geometry, material, incidentDirection, attenuation * irradiance, reflectedLight.directDiffuse, reflectedLight.directSpecular);

}

#ifdef SCENE_DIRECT_LIGHT_COUNT
Expand Down
11 changes: 11 additions & 0 deletions packages/core/src/shaderlib/pbr/ibl_frag_define.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,15 @@ vec3 getLightProbeRadiance(Geometry geometry, vec3 normal, float roughness, int

#endif

}


void evaluateSheenIBL(Geometry geometry, Material material, float radianceAttenuation, inout vec3 diffuseColor, inout vec3 specularColor){
#ifdef MATERIAL_ENABLE_SHEEN
diffuseColor *= material.sheenScaling;
specularColor *= material.sheenScaling;

vec3 reflectance = material.specularAO * radianceAttenuation * material.approxIBLSheenDG * material.sheenColor;
specularColor += reflectance;
#endif
}
8 changes: 7 additions & 1 deletion packages/core/src/shaderlib/pbr/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import ibl_frag_define from "./ibl_frag_define.glsl";

import pbr_frag from "./pbr_frag.glsl";

import btdf from "./btdf.glsl";
import refraction from "./refraction.glsl";

export default {
pbr_frag_define,

Expand All @@ -16,5 +19,8 @@ export default {
direct_irradiance_frag_define,
ibl_frag_define,

pbr_frag
pbr_frag,

btdf,
refraction
};
Loading
Loading