@@ -36,34 +36,39 @@ float DisneyPdf(in Ray ray, inout State state, in vec3 bsdfDir)
36
36
vec3 L = bsdfDir;
37
37
vec3 H = normalize (L + V);
38
38
39
- // if (dot(N, L) < 0.0)
40
- // return 1 .0;
39
+ float brdfPdf = 0.0 ;
40
+ float bsdfPdf = 0 .0 ;
41
41
42
- float NDotH = dot (N, H);
42
+ float NDotH = abs ( dot (N, H) );
43
43
44
- float specularAlpha = mix (0.1 , 0.001 , state.mat.roughness);
44
+ // TODO: Fix importance sampling for microfacet transmission
45
+ if (dot (N, L) <= 0.0 && state.mat.transmission > 0.0 )
46
+ return 1.0 ;
47
+
48
+ float specularAlpha = max (0.001 , state.mat.roughness);
45
49
float clearcoatAlpha = mix (0.1 , 0.001 , state.mat.clearcoatGloss);
46
50
47
51
float diffuseRatio = 0.5 * (1.0 - state.mat.metallic);
48
52
float specularRatio = 1.0 - diffuseRatio;
49
53
50
54
float aspect = sqrt (1.0 - state.mat.anisotropic * 0.9 );
51
- float ax = max (0.001 , ( state.mat.roughness * state.mat.roughness) / aspect);
52
- float ay = max (0.001 , ( state.mat.roughness * state.mat.roughness) * aspect);
55
+ float ax = max (0.001 , state.mat.roughness / aspect);
56
+ float ay = max (0.001 , state.mat.roughness * aspect);
53
57
54
58
// PDFs for brdf
55
59
float pdfGTR2_aniso = GTR2_aniso(NDotH, dot (H, state.tangent), dot (H, state.bitangent), ax, ay) * NDotH;
56
60
float pdfGTR1 = GTR1(NDotH, clearcoatAlpha) * NDotH;
57
61
float ratio = 1.0 / (1.0 + state.mat.clearcoat);
58
62
float pdfSpec = mix (pdfGTR1, pdfGTR2_aniso, ratio) / (4.0 * abs (dot (L, H)));
59
63
float pdfDiff = abs (dot (L, N)) * (1.0 / PI);
60
- float brdfPdf = diffuseRatio * pdfDiff + specularRatio * pdfSpec;
64
+ brdfPdf = diffuseRatio * pdfDiff + specularRatio * pdfSpec;
61
65
62
66
// PDFs for bsdf
63
67
float pdfGTR2 = GTR2(NDotH, specularAlpha) * NDotH;
64
- float bsdfPdf = pdfGTR2 / (4.0 * abs (dot (L, H)));
68
+ float F = Fresnel(abs (dot (L, H)), 1.0 , state.mat.ior);
69
+ bsdfPdf = pdfGTR2 * F / (4.0 * abs (dot (L, H)));
65
70
66
- return brdfPdf; // mix(brdfPdf, bsdfPdf, state.mat.transmission);
71
+ return mix (brdfPdf, bsdfPdf, state.mat.transmission);
67
72
}
68
73
69
74
// -----------------------------------------------------------------------
@@ -72,39 +77,42 @@ vec3 DisneySample(in Ray ray, inout State state)
72
77
{
73
78
vec3 N = state.ffnormal;
74
79
vec3 V = - ray.direction;
80
+ state.specularBounce = false;
75
81
76
82
vec3 dir;
77
83
78
84
float r1 = rand();
79
85
float r2 = rand();
80
- // float bsdfProb = rand();
81
86
82
87
// BSDF
83
- /* if (bsdfProb < state.mat.transmission)
88
+ if (rand() < state.mat.transmission)
84
89
{
85
90
float n1 = 1.0 ;
86
91
float n2 = state.mat.ior;
87
92
93
+ vec3 H = ImportanceSampleGGX(state.mat.roughness, r1, r2);
94
+ H = state.tangent * H.x + state.bitangent * H.y + N * H.z;
95
+
88
96
float theta = abs (dot (- V, N));
89
97
float eta = dot (state.normal, state.ffnormal) > 0.0 ? (n1 / n2) : (n2 / n1);
90
98
float cos2t = 1.0 - eta * eta * (1.0 - theta * theta);
91
99
92
- vec3 H = ImportanceSampleGGX(state.mat.roughness, r1, r2);
93
- H = state.tangent * H.x + state.bitangent * H.y + N * H.z;
94
-
95
100
float F = Fresnel(theta, n1, n2);
96
101
97
102
if (cos2t < 0.0 || rand() < F)
98
103
dir = normalize (reflect (- V, H));
99
104
else
105
+ {
100
106
dir = normalize (refract (- V, H, eta));
107
+ state.specularBounce = true;
108
+ }
101
109
}
102
- else*/
110
+ // BRDF
111
+ else
103
112
{
104
- float probability = rand();
105
113
float diffuseRatio = 0.5 * (1.0 - state.mat.metallic);
106
114
107
- if (probability < diffuseRatio)
115
+ if (rand() < diffuseRatio)
108
116
{
109
117
vec3 H = CosineSampleHemisphere(r1, r2);
110
118
H = state.tangent * H.x + state.bitangent * H.y + N * H.z;
@@ -128,63 +136,75 @@ vec3 DisneyEval(in Ray ray, inout State state, in vec3 bsdfDir)
128
136
vec3 V = - ray.direction;
129
137
vec3 L = bsdfDir;
130
138
131
- float NDotL = dot (N, L);
132
- float NDotV = dot (N, V);
133
-
134
- if (NDotL <= 0.0 || NDotV <= 0.0 )
135
- return vec3 (0.0 );
139
+ float NDotL = abs (dot (N, L));
140
+ float NDotV = abs (dot (N, V));
136
141
137
142
vec3 H = normalize (L + V);
138
- float NDotH = dot (N, H);
139
- float LDotH = dot (L, H);
140
-
141
- vec3 Cdlin = state.mat.albedo;
142
- float Cdlum = 0.3 * Cdlin.x + 0.6 * Cdlin.y + 0.1 * Cdlin.z; // luminance approx.
143
-
144
- vec3 Ctint = Cdlum > 0.0 ? Cdlin / Cdlum : vec3 (1 .0f); // normalize lum. to isolate hue+sat
145
- vec3 Cspec0 = mix (state.mat.specular * 0.08 * mix (vec3 (1.0 ), Ctint, state.mat.specularTint), Cdlin, state.mat.metallic);
146
- vec3 Csheen = mix (vec3 (1.0 ), Ctint, state.mat.sheenTint);
147
-
148
- // Diffuse fresnel - go from 1 at normal incidence to .5 at grazing
149
- // and mix in diffuse retro-reflection based on roughness
150
- float FL = SchlickFresnel(NDotL);
151
- float FV = SchlickFresnel(NDotV);
152
- float Fd90 = 0.5 + 2.0 * LDotH * LDotH * state.mat.roughness;
153
- float Fd = mix (1.0 , Fd90, FL) * mix (1.0 , Fd90, FV);
154
-
155
- // Based on Hanrahan-Krueger brdf approximation of isotropic bssrdf
156
- // 1.25 scale is used to (roughly) preserve albedo
157
- // Fss90 used to "flatten" retroreflection based on roughness
158
- float Fss90 = LDotH * LDotH * state.mat.roughness;
159
- float Fss = mix (1.0 , Fss90, FL) * mix (1.0 , Fss90, FV);
160
- float ss = 1.25 * (Fss * (1.0 / (NDotL + NDotV) - 0.5 ) + 0.5 );
161
-
162
- // specular
163
- /* float a = max(0.001, state.mat.roughness);
164
- float Ds = GTR2(NDotH, a);
165
- float FH = SchlickFresnel(LDotH);
166
- vec3 Fs = mix(Cspec0, vec3(1.0), FH);
167
- float roughg = (state.mat.roughness * 0.5 + 0.5);
168
- roughg *= roughg;
169
- float Gs = SmithG_GGX(NDotL, roughg) * SmithG_GGX(NDotV, roughg);*/
170
-
171
- // specular
172
- float aspect = sqrt (1.0 - state.mat.anisotropic * 0.9 );
173
- float ax = max (0.001 , (state.mat.roughness * state.mat.roughness) / aspect);
174
- float ay = max (0.001 , (state.mat.roughness * state.mat.roughness) * aspect);
175
- float Ds = GTR2_aniso(NDotH, dot (H, state.tangent), dot (H, state.bitangent), ax, ay);
176
- float FH = SchlickFresnel(LDotH);
177
- vec3 Fs = mix (Cspec0, vec3 (1.0 ), FH);
178
- float Gs = SmithG_GGX_aniso(NDotL, dot (L, state.tangent), dot (L, state.bitangent), ax, ay);
179
- Gs *= SmithG_GGX_aniso(NDotV, dot (V, state.tangent), dot (V, state.bitangent), ax, ay);
180
-
181
- // sheen
182
- vec3 Fsheen = FH * state.mat.sheen * Csheen;
183
-
184
- // clearcoat (ior = 1.5 -> F0 = 0.04)
185
- float Dr = GTR1(NDotH, mix (0.1 , 0.001 , state.mat.clearcoatGloss));
186
- float Fr = mix (0.04 , 1.0 , FH);
187
- float Gr = SmithG_GGX(NDotL, 0.25 ) * SmithG_GGX(NDotV, 0.25 );
188
-
189
- return ((1.0 / PI) * mix (Fd, ss, state.mat.subsurface) * Cdlin + Fsheen) * (1.0 - state.mat.metallic) + Gs * Fs * Ds + 0.25 * state.mat.clearcoat * Gr * Fr * Dr;
143
+
144
+ float NDotH = abs (dot (N, H));
145
+ float LDotH = abs (dot (L, H));
146
+
147
+ vec3 brdf = vec3 (0.0 );
148
+ vec3 bsdf = vec3 (0.0 );
149
+
150
+ // TODO: Fix bsdf for microfacet transmission
151
+ if (state.mat.transmission > 0.0 )
152
+ {
153
+ if (dot (N, L) <= 0.0 )
154
+ bsdf = state.mat.albedo / abs (NDotL);
155
+ else
156
+ {
157
+ float a = max (0.001 , state.mat.roughness);
158
+ float F = Fresnel(LDotH, 1.0 , state.mat.ior);
159
+ float D = GTR2(NDotH, a);
160
+ float G = SmithG_GGX(NDotL, a) * SmithG_GGX(NDotV, a);
161
+ bsdf = state.mat.albedo * F * G * D;
162
+ }
163
+ }
164
+
165
+ if (state.mat.transmission < 1.0 )
166
+ {
167
+ vec3 Cdlin = state.mat.albedo;
168
+ float Cdlum = 0.3 * Cdlin.x + 0.6 * Cdlin.y + 0.1 * Cdlin.z; // luminance approx.
169
+
170
+ vec3 Ctint = Cdlum > 0.0 ? Cdlin / Cdlum : vec3 (1 .0f); // normalize lum. to isolate hue+sat
171
+ vec3 Cspec0 = mix (state.mat.specular * 0.08 * mix (vec3 (1.0 ), Ctint, state.mat.specularTint), Cdlin, state.mat.metallic);
172
+ vec3 Csheen = mix (vec3 (1.0 ), Ctint, state.mat.sheenTint);
173
+
174
+ // Diffuse fresnel - go from 1 at normal incidence to .5 at grazing
175
+ // and mix in diffuse retro-reflection based on roughness
176
+ float FL = SchlickFresnel(NDotL);
177
+ float FV = SchlickFresnel(NDotV);
178
+ float Fd90 = 0.5 + 2.0 * LDotH * LDotH * state.mat.roughness;
179
+ float Fd = mix (1.0 , Fd90, FL) * mix (1.0 , Fd90, FV);
180
+
181
+ // Based on Hanrahan-Krueger brdf approximation of isotropic bssrdf
182
+ // 1.25 scale is used to (roughly) preserve albedo
183
+ // Fss90 used to "flatten" retroreflection based on roughness
184
+ float Fss90 = LDotH * LDotH * state.mat.roughness;
185
+ float Fss = mix (1.0 , Fss90, FL) * mix (1.0 , Fss90, FV);
186
+ float ss = 1.25 * (Fss * (1.0 / (NDotL + NDotV) - 0.5 ) + 0.5 );
187
+
188
+ // specular
189
+ float aspect = sqrt (1.0 - state.mat.anisotropic * 0.9 );
190
+ float ax = max (0.001 , state.mat.roughness / aspect);
191
+ float ay = max (0.001 , state.mat.roughness * aspect);
192
+ float Ds = GTR2_aniso(NDotH, dot (H, state.tangent), dot (H, state.bitangent), ax, ay);
193
+ float FH = SchlickFresnel(LDotH);
194
+ vec3 Fs = mix (Cspec0, vec3 (1.0 ), FH);
195
+ float Gs = SmithG_GGX_aniso(NDotL, dot (L, state.tangent), dot (L, state.bitangent), ax, ay);
196
+ Gs *= SmithG_GGX_aniso(NDotV, dot (V, state.tangent), dot (V, state.bitangent), ax, ay);
197
+
198
+ // sheen
199
+ vec3 Fsheen = FH * state.mat.sheen * Csheen;
200
+
201
+ // clearcoat (ior = 1.5 -> F0 = 0.04)
202
+ float Dr = GTR1(NDotH, mix (0.1 , 0.001 , state.mat.clearcoatGloss));
203
+ float Fr = mix (0.04 , 1.0 , FH);
204
+ float Gr = SmithG_GGX(NDotL, 0.25 ) * SmithG_GGX(NDotV, 0.25 );
205
+
206
+ brdf = ((1.0 / PI) * mix (Fd, ss, state.mat.subsurface) * Cdlin + Fsheen) * (1.0 - state.mat.metallic) + Gs * Fs * Ds + 0.25 * state.mat.clearcoat * Gr * Fr * Dr;
207
+ }
208
+
209
+ return mix (brdf, bsdf, state.mat.transmission);
190
210
}
0 commit comments