Skip to content

Commit b274e2e

Browse files
authored
Add iri/sheen/rafraction in glsl version (#2518)
* feat: support iri/sheen/rafraction in glsl version
1 parent d3cf162 commit b274e2e

File tree

13 files changed

+445
-46
lines changed

13 files changed

+445
-46
lines changed

packages/core/src/shaderlib/common.glsl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#define RECIPROCAL_PI 0.31830988618
33
#define EPSILON 1e-6
44
#define LOG2 1.442695
5+
#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
6+
#define HALF_EPS 4.8828125e-4 // 2^-11, machine epsilon: 1 + EPS = 1 (half of the ULP for 1.0f)
57

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

@@ -93,3 +95,9 @@ float remapDepthBufferLinear01(float z){
9395

9496
#define INVERSE_MAT(mat) inverseMat(mat)
9597
#endif
98+
99+
100+
vec3 safeNormalize(vec3 inVec) {
101+
float dp3 = max(float(HALF_MIN), dot(inVec, inVec));
102+
return inVec * inversesqrt(dp3);
103+
}

packages/core/src/shaderlib/extra/pbr.fs.glsl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#define IS_METALLIC_WORKFLOW
22
#include <common>
33
#include <camera_declare>
4+
#include <transform_declare>
45

56
#include <FogFragmentDeclaration>
67

packages/core/src/shaderlib/pbr/brdf.glsl

Lines changed: 139 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11

2+
#ifdef MATERIAL_ENABLE_SHEEN
3+
uniform sampler2D scene_PrefilteredDFG;
4+
#endif
5+
26
float F_Schlick(float f0, float dotLH) {
37
return f0 + 0.96 * (pow(1.0 - dotLH, 5.0));
48
}
@@ -53,6 +57,39 @@ float D_GGX(float alpha, float dotNH ) {
5357

5458
}
5559

60+
#ifdef MATERIAL_ENABLE_SHEEN
61+
// http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf
62+
float D_Charlie(float roughness, float dotNH) {
63+
float invAlpha = 1.0 / roughness;
64+
float cos2h = dotNH * dotNH;
65+
float sin2h = max(1.0 - cos2h, 0.0078125); // 2^(-14/2), so sin2h^2 > 0 in fp16
66+
return (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI);
67+
}
68+
69+
// Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886".
70+
float V_Neubelt(float NoV, float NoL) {
71+
return saturate(1.0 / (4.0 * (NoL + NoV - NoL * NoV)));
72+
}
73+
74+
vec3 sheenBRDF(vec3 incidentDirection, Geometry geometry, vec3 sheenColor, float sheenRoughness) {
75+
vec3 halfDir = normalize(incidentDirection + geometry.viewDir);
76+
float dotNL = saturate(dot(geometry.normal, incidentDirection));
77+
float dotNH = saturate(dot(geometry.normal, halfDir));
78+
float D = D_Charlie(sheenRoughness, dotNH);
79+
float V = V_Neubelt(geometry.dotNV, dotNL);
80+
vec3 F = sheenColor;
81+
return D * V * F;
82+
}
83+
84+
float prefilteredSheenDFG(float dotNV, float sheenRoughness) {
85+
#ifdef HAS_TEX_LOD
86+
return texture2DLodEXT(scene_PrefilteredDFG, vec2(dotNV, sheenRoughness), 0.0).b;
87+
#else
88+
return texture2D(scene_PrefilteredDFG, vec2(dotNV, sheenRoughness),0.0).b;
89+
#endif
90+
}
91+
#endif
92+
5693
#ifdef MATERIAL_ENABLE_ANISOTROPY
5794
// GGX Distribution Anisotropic
5895
// https://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v3.pdf Addenda
@@ -65,16 +102,14 @@ float D_GGX(float alpha, float dotNH ) {
65102
}
66103
#endif
67104

68-
vec3 isotropicLobe(vec3 specularColor, float alpha, float dotNV, float dotNL, float dotNH, float dotLH) {
69-
vec3 F = F_Schlick( specularColor, dotLH );
105+
float DG_GGX(float alpha, float dotNV, float dotNL, float dotNH) {
70106
float D = D_GGX( alpha, dotNH );
71107
float G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );
72-
73-
return F * ( G * D );
108+
return G * D;
74109
}
75110

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

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

99-
return F * ( G * D );
133+
return G * D;
134+
}
135+
#endif
136+
137+
#ifdef MATERIAL_ENABLE_IRIDESCENCE
138+
vec3 iorToFresnel0(vec3 transmittedIOR, float incidentIOR) {
139+
return pow((transmittedIOR - incidentIOR) / (transmittedIOR + incidentIOR),vec3(2.0));
140+
}
141+
142+
float iorToFresnel0(float transmittedIOR, float incidentIOR) {
143+
return pow((transmittedIOR - incidentIOR) / (transmittedIOR + incidentIOR),2.0);
144+
}
145+
146+
// Assume air interface for top
147+
// Note: We don't handle the case fresnel0 == 1
148+
vec3 fresnelToIOR(vec3 f0){
149+
vec3 sqrtF0 = sqrt(f0);
150+
return (vec3(1.0) + sqrtF0) / (vec3(1.0) - sqrtF0);
151+
}
152+
153+
// Fresnel equations for dielectric/dielectric interfaces.
154+
// Ref: https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html
155+
// Evaluation XYZ sensitivity curves in Fourier space
156+
vec3 evalSensitivity(float opd, vec3 shift){
157+
// Use Gaussian fits, given by 3 parameters: val, pos and var
158+
float phase = 2.0 * PI * opd * 1.0e-9;
159+
const vec3 val = vec3(5.4856e-13, 4.4201e-13, 5.2481e-13);
160+
const vec3 pos = vec3(1.6810e+06, 1.7953e+06, 2.2084e+06);
161+
const vec3 var = vec3(4.3278e+09, 9.3046e+09, 6.6121e+09);
162+
vec3 xyz = val * sqrt(2.0 * PI * var) * cos(pos * phase + shift) * exp(-var * pow2(phase));
163+
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));
164+
xyz /= 1.0685e-7;
165+
// XYZ to RGB color space
166+
const mat3 XYZ_TO_RGB = mat3( 3.2404542, -0.9692660, 0.0556434,
167+
-1.5371385, 1.8760108, -0.2040259,
168+
-0.4985314, 0.0415560, 1.0572252);
169+
vec3 rgb = XYZ_TO_RGB * xyz;
170+
return rgb;
171+
}
172+
173+
vec3 evalIridescenceSpecular(float outsideIOR, float dotNV, float thinIOR, vec3 baseF0,float iridescenceThickness){
174+
vec3 iridescence = vec3(1.0);
175+
// Force iridescenceIOR -> outsideIOR when thinFilmThickness -> 0.0
176+
float iridescenceIOR = mix( outsideIOR, thinIOR, smoothstep( 0.0, 0.03, iridescenceThickness ) );
177+
// Evaluate the cosTheta on the base layer (Snell law)
178+
float sinTheta2Sq = pow( outsideIOR / iridescenceIOR, 2.0) * (1.0 - pow( dotNV, 2.0));
179+
float cosTheta2Sq = 1.0 - sinTheta2Sq;
180+
// Handle total internal reflection
181+
if (cosTheta2Sq < 0.0) {
182+
return iridescence;
183+
}
184+
float cosTheta2 = sqrt(cosTheta2Sq);
185+
186+
// First interface
187+
float f0 = iorToFresnel0(iridescenceIOR, outsideIOR);
188+
float reflectance = F_Schlick(f0, dotNV);
189+
float t121 = 1.0 - reflectance;
190+
float phi12 = 0.0;
191+
// iridescenceIOR has limited greater than 1.0
192+
// if (iridescenceIOR < outsideIOR) {phi12 = PI;}
193+
float phi21 = PI - phi12;
194+
195+
// Second interface
196+
vec3 baseIOR = fresnelToIOR(clamp(baseF0, 0.0, 0.9999)); // guard against 1.0
197+
vec3 r1 = iorToFresnel0(baseIOR, iridescenceIOR);
198+
vec3 r23 = F_Schlick(r1, cosTheta2);
199+
vec3 phi23 =vec3(0.0);
200+
if (baseIOR[0] < iridescenceIOR) {phi23[0] = PI;}
201+
if (baseIOR[1] < iridescenceIOR) {phi23[1] = PI;}
202+
if (baseIOR[2] < iridescenceIOR) {phi23[2] = PI;}
203+
204+
// Phase shift
205+
float opd = 2.0 * iridescenceIOR * iridescenceThickness * cosTheta2;
206+
vec3 phi = vec3(phi21) + phi23;
207+
208+
// Compound terms
209+
vec3 r123 = clamp(reflectance * r23, 1e-5, 0.9999);
210+
vec3 sr123 = sqrt(r123);
211+
vec3 rs = pow2(t121) * r23 / (vec3(1.0) - r123);
212+
// Reflectance term for m = 0 (DC term amplitude)
213+
vec3 c0 = reflectance + rs;
214+
iridescence = c0;
215+
// Reflectance term for m > 0 (pairs of diracs)
216+
vec3 cm = rs - t121;
217+
for (int m = 1; m <= 2; ++m) {
218+
cm *= sr123;
219+
vec3 sm = 2.0 * evalSensitivity(float(m) * opd, float(m) * phi);
220+
iridescence += cm * sm;
221+
}
222+
return iridescence = max(iridescence, vec3(0.0));
100223
}
101224
#endif
102225

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

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

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

238+
vec3 F = F_Schlick( specularColor, dotLH );
239+
#ifdef MATERIAL_ENABLE_IRIDESCENCE
240+
F = mix(F, material.iridescenceSpecularColor, material.iridescenceFactor);
241+
#endif
242+
115243
#ifdef MATERIAL_ENABLE_ANISOTROPY
116-
return anisotropicLobe(halfDir, incidentDirection, geometry, specularColor, alpha, dotNV, dotNL, dotNH, dotLH);
244+
float GD = DG_GGX_anisotropic(halfDir, incidentDirection, geometry, alpha, dotNV, dotNL, dotNH);
117245
#else
118-
return isotropicLobe(specularColor, alpha, dotNV, dotNL, dotNH, dotLH);
246+
float GD = DG_GGX(alpha, dotNV, dotNL, dotNH);
119247
#endif
120248

249+
return F * GD;
121250
}
122251

123252
vec3 BRDF_Diffuse_Lambert(vec3 diffuseColor ) {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include <refraction>
2+
3+
#ifdef MATERIAL_ENABLE_TRANSMISSION
4+
uniform sampler2D camera_OpaqueTexture;
5+
vec3 evaluateTransmission(Geometry geometry, Material material) {
6+
RefractionModelResult ray;
7+
#if REFRACTION_MODE == 0
8+
// RefractionMode.Sphere
9+
refractionModelSphere(-geometry.viewDir, geometry.position, geometry.normal, material.IOR, material.thickness, ray);
10+
#elif REFRACTION_MODE == 1
11+
// RefractionMode.Planar
12+
refractionModelPlanar(-geometry.viewDir, geometry.position, geometry.normal, material.IOR, material.thickness, ray);
13+
#endif
14+
15+
vec3 refractedRayExit = ray.positionExit;
16+
17+
// We calculate the screen space position of the refracted point
18+
vec4 samplingPositionNDC = camera_ProjMat * camera_ViewMat * vec4( refractedRayExit, 1.0 );
19+
vec2 refractionCoords = (samplingPositionNDC.xy / samplingPositionNDC.w) * 0.5 + 0.5;
20+
21+
// Sample the opaque texture to get the transmitted light
22+
vec3 refractionTransmitted = texture2D(camera_OpaqueTexture, refractionCoords).rgb;
23+
refractionTransmitted *= material.diffuseColor;
24+
25+
// Use specularFGD as an approximation of the fresnel effect
26+
// https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf
27+
refractionTransmitted *= (1.0 - material.envSpecularDFG);
28+
29+
#ifdef MATERIAL_HAS_THICKNESS
30+
// Absorption coefficient from Disney: http://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf
31+
vec3 transmittance = min(vec3(1.0), exp(-material.absorptionCoefficient * ray.transmissionLength));
32+
refractionTransmitted *= transmittance;
33+
#endif
34+
35+
return refractionTransmitted;
36+
}
37+
#endif

packages/core/src/shaderlib/pbr/direct_irradiance_frag_define.glsl

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,34 @@
11
#include <ShadowFragmentDeclaration>
22

3+
void sheenLobe(Geometry geometry, Material material, vec3 incidentDirection, vec3 attenuationIrradiance, inout vec3 diffuseColor, inout vec3 specularColor){
4+
#ifdef MATERIAL_ENABLE_SHEEN
5+
diffuseColor *= material.sheenScaling;
6+
specularColor *= material.sheenScaling;
7+
8+
specularColor += attenuationIrradiance * sheenBRDF(incidentDirection, geometry, material.sheenColor, material.sheenRoughness);
9+
#endif
10+
}
11+
312
void addDirectRadiance(vec3 incidentDirection, vec3 color, Geometry geometry, Material material, inout ReflectedLight reflectedLight) {
413
float attenuation = 1.0;
514

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

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

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

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

29+
// Sheen Lobe
30+
sheenLobe(geometry, material, incidentDirection, attenuation * irradiance, reflectedLight.directDiffuse, reflectedLight.directSpecular);
31+
2032
}
2133

2234
#ifdef SCENE_DIRECT_LIGHT_COUNT

packages/core/src/shaderlib/pbr/ibl_frag_define.glsl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,15 @@ vec3 getLightProbeRadiance(Geometry geometry, vec3 normal, float roughness, int
8383

8484
#endif
8585

86+
}
87+
88+
89+
void evaluateSheenIBL(Geometry geometry, Material material, float radianceAttenuation, inout vec3 diffuseColor, inout vec3 specularColor){
90+
#ifdef MATERIAL_ENABLE_SHEEN
91+
diffuseColor *= material.sheenScaling;
92+
specularColor *= material.sheenScaling;
93+
94+
vec3 reflectance = material.specularAO * radianceAttenuation * material.approxIBLSheenDG * material.sheenColor;
95+
specularColor += reflectance;
96+
#endif
8697
}

packages/core/src/shaderlib/pbr/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import ibl_frag_define from "./ibl_frag_define.glsl";
88

99
import pbr_frag from "./pbr_frag.glsl";
1010

11+
import btdf from "./btdf.glsl";
12+
import refraction from "./refraction.glsl";
13+
1114
export default {
1215
pbr_frag_define,
1316

@@ -16,5 +19,8 @@ export default {
1619
direct_irradiance_frag_define,
1720
ibl_frag_define,
1821

19-
pbr_frag
22+
pbr_frag,
23+
24+
btdf,
25+
refraction
2026
};

0 commit comments

Comments
 (0)