11
2+ #ifdef MATERIAL_ENABLE_SHEEN
3+ uniform sampler2D scene_PrefilteredDFG;
4+ #endif
5+
26float 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
123252vec3 BRDF_Diffuse_Lambert(vec3 diffuseColor ) {
0 commit comments