@@ -28,15 +28,14 @@ int traceRay(inout float intersectionT, in vec3 origin, in vec3 direction)
28
28
return objectID;
29
29
}
30
30
31
- #if 0
31
+
32
32
// the interaction here is the interaction at the illuminator-end of the ray, not the receiver
33
33
vec3 nbl_glsl_light_deferred_eval_and_prob(out float pdf, in Sphere sphere, in vec3 origin, in nbl_glsl_AnisotropicViewSurfaceInteraction interaction, in Light light)
34
34
{
35
35
// we don't have to worry about solid angle of the light w.r.t. surface of the light because this function only ever gets called from closestHit routine, so such ray cannot be produced
36
36
pdf = scene_getLightChoicePdf(light)/ Sphere_getSolidAngle(sphere,origin);
37
37
return Light_getRadiance(light);
38
38
}
39
- #endif
40
39
41
40
nbl_glsl_LightSample nbl_glsl_light_generate_and_remainder_and_pdf(out vec3 remainder, out float pdf, out float newRayMaxT, in vec3 origin, in nbl_glsl_AnisotropicViewSurfaceInteraction interaction, in vec3 u, in uint depth)
42
41
{
@@ -82,15 +81,37 @@ bool closestHitProgram(in uint depth, in uint _sample, inout Ray_t ray, inout nb
82
81
const MutableRay_t _mutable = ray._mutable;
83
82
84
83
Sphere sphere = spheres[_mutable.objectID];
84
+
85
+ // interaction stuffs
86
+ const vec3 intersection = ray._immutable.origin+ ray._immutable.direction* _mutable.intersectionT;
87
+ nbl_glsl_AnisotropicViewSurfaceInteraction interaction;
88
+ {
89
+ nbl_glsl_IsotropicViewSurfaceInteraction isotropic;
90
+
91
+ isotropic.V.dir = - ray._immutable.direction;
92
+ // isotropic.V.dPosdScreen = screw that
93
+ isotropic.N = Sphere_getNormal(sphere,intersection);
94
+ isotropic.NdotV = dot (isotropic.V.dir,isotropic.N);
95
+ isotropic.NdotV_squared = isotropic.NdotV* isotropic.NdotV;
96
+
97
+ interaction = nbl_glsl_calcAnisotropicInteraction(isotropic);
98
+ }
99
+
100
+ //
85
101
const uint bsdfLightIDs = sphere.bsdfLightIDs;
86
102
103
+ //
87
104
vec3 throughput = ray._payload.throughput;
88
- #if 0
89
- // add emissive
105
+
106
+ // add emissive and finish MIS
90
107
const uint lightID = bitfieldExtract(bsdfLightIDs,16 ,16 );
91
108
if (lightID!= INVALID_ID_16BIT) // has emissive
92
- ray._payload.accumulation += throughput* Light_getRadiance(lights[lightID]);
93
- #endif
109
+ {
110
+ float lightPdf;
111
+ vec3 lightVal = nbl_glsl_light_deferred_eval_and_prob(lightPdf,sphere,ray._immutable.origin,interaction,lights[lightID]);
112
+ ray._payload.accumulation += lightVal* throughput/ (1.0 + lightPdf* lightPdf* ray._payload.otherTechniqueHeuristic);
113
+ }
114
+
94
115
// check if we even have a BSDF at all
95
116
uint bsdfID = bitfieldExtract(bsdfLightIDs,0 ,16 );
96
117
if (bsdfID!= INVALID_ID_16BIT)
@@ -108,21 +129,6 @@ bool closestHitProgram(in uint depth, in uint _sample, inout Ray_t ray, inout nb
108
129
109
130
// rand
110
131
mat2x3 epsilon = rand3d(depth,_sample,scramble_state);
111
-
112
- // interaction stuffs
113
- const vec3 intersection = ray._immutable.origin+ ray._immutable.direction* _mutable.intersectionT;
114
- nbl_glsl_AnisotropicViewSurfaceInteraction interaction;
115
- {
116
- nbl_glsl_IsotropicViewSurfaceInteraction isotropic;
117
-
118
- isotropic.V.dir = - ray._immutable.direction;
119
- // isotropic.V.dPosdScreen = screw that
120
- isotropic.N = Sphere_getNormal(sphere,intersection);
121
- isotropic.NdotV = dot (isotropic.V.dir,isotropic.N);
122
- isotropic.NdotV_squared = isotropic.NdotV* isotropic.NdotV;
123
-
124
- interaction = nbl_glsl_calcAnisotropicInteraction(isotropic);
125
- }
126
132
127
133
// thresholds
128
134
const float bsdfPdfThreshold = 0.0001 ;
@@ -131,7 +137,8 @@ bool closestHitProgram(in uint depth, in uint _sample, inout Ray_t ray, inout nb
131
137
const float monochromeEta = dot (throughputCIE_Y,BSDFNode_getEta(bsdf)[0 ])/ (throughputCIE_Y.r+ throughputCIE_Y.g+ throughputCIE_Y.b);
132
138
133
139
// do NEE
134
- float rcpNEEProb = 1.0 ;
140
+ const float neeProbability = 1.0 ;// BSDFNode_getMISWeight(bsdf);
141
+ const float neeProbability2 = neeProbability* neeProbability;
135
142
if (true)
136
143
{
137
144
vec3 neeContrib; float lightPdf, t;
@@ -145,8 +152,9 @@ bool closestHitProgram(in uint depth, in uint _sample, inout Ray_t ray, inout nb
145
152
{
146
153
float bsdfPdf;
147
154
neeContrib *= nbl_glsl_bsdf_cos_remainder_and_pdf(bsdfPdf,_sample,interaction,bsdf,monochromeEta,_cache)* throughput;
155
+ neeContrib /= bsdfPdf/ (lightPdf* lightPdf)+ neeProbability2/ bsdfPdf; // MIS weight
148
156
if (bsdfPdf< FLT_MAX && getLuma(neeContrib)> lumaContributionThreshold && traceRay(t,intersection+ _sample.L* t* getStartTolerance(depth),_sample.L)==-1 )
149
- ray._payload.accumulation += neeContrib* bsdfPdf ;
157
+ ray._payload.accumulation += neeContrib;
150
158
}
151
159
}
152
160
@@ -166,6 +174,7 @@ bool closestHitProgram(in uint depth, in uint _sample, inout Ray_t ray, inout nb
166
174
if (bsdfPdf> bsdfPdfThreshold && getLuma(throughput)> lumaThroughputThreshold)
167
175
{
168
176
ray._payload.throughput = throughput;
177
+ ray._payload.otherTechniqueHeuristic = neeProbability2/ (bsdfPdf* bsdfPdf); // numerically stable, don't touch
169
178
170
179
// trace new ray
171
180
ray._immutable.origin = intersection+ bsdfSampleL* (1.0 /* kSceneSize*/ )* getStartTolerance(depth);
@@ -176,46 +185,5 @@ bool closestHitProgram(in uint depth, in uint _sample, inout Ray_t ray, inout nb
176
185
return false;
177
186
}
178
187
#if 0
179
- // finish MIS
180
- if (lightID!= INVALID_ID_16BIT) // has emissive
181
- {
182
- float lightPdf;
183
- vec3 lightVal = nbl_glsl_light_deferred_eval_and_prob(lightPdf,sphere,ray._immutable.origin,interaction,lights[lightID]);
184
- ray._payload.accumulation += ray._payload.throughput* lightVal/ (1.0 + lightPdf* lightPdf* ray._payload.otherTechniqueHeuristic);
185
- }
186
-
187
-
188
-
189
-
190
-
191
- const float bsdfGeneratorProbability = BSDFNode_getMISWeight(bsdf);
192
188
const bool doNEE = nbl_glsl_partitionRandVariable(bsdfGeneratorProbability,epsilon[0 ].z,rcpChoiceProb);
193
-
194
- float maxT;
195
- // the probability of generating a sample w.r.t. the light generator only possible and used when it was generated with it!
196
- float lightPdf;
197
- nbl_glsl_LightSample _sample;
198
-
199
-
200
- // OETF smallest perceptible value
201
- const float bsdfPdfThreshold = getLuma(nbl_glsl_eotf_sRGB(vec3 (1.0 )/ 255.0 ));
202
- const float lumaThroughputThreshold = bsdfPdfThreshold;
203
- if (bsdfPdf> bsdfPdfThreshold && (! doNEE || bsdfPdf< FLT_MAX) && getLuma(throughput)> lumaThroughputThreshold)
204
- {
205
- ray._payload.throughput = throughput* rcpChoiceProb;
206
-
207
- float heuristicFactor = rcpChoiceProb- 1.0 ; // weightNonGenerator/weightGenerator
208
- heuristicFactor /= doNEE ? lightPdf: bsdfPdf; // weightNonGenerator/(weightGenerator*probGenerated)
209
- heuristicFactor *= heuristicFactor; // (weightNonGenerator/(weightGenerator*probGenerated))^2
210
- if (doNEE)
211
- heuristicFactor = 1.0 / (1.0 / bsdfPdf+ heuristicFactor* bsdfPdf); // numerically stable, don't touch
212
- ray._payload.otherTechniqueHeuristic = heuristicFactor;
213
-
214
- // trace new ray
215
- ray._immutable.origin = intersection+ _sample.L* (doNEE ? maxT: 1.0 /* kSceneSize*/ )* getStartTolerance(depth);
216
- ray._immutable.maxT = maxT;
217
- ray._immutable.direction = _sample.L;
218
- ray._immutable.anyHit = doNEE;
219
- return false;
220
- }
221
189
#endif
0 commit comments