@@ -162,12 +162,10 @@ void Geometry::_process_shape(
162
162
}
163
163
}
164
164
165
- void Geometry::_alpha_skip (SurfaceCandidate &c) const noexcept {
166
- auto hit = c.hit ();
167
- auto ray = c.ray ();
165
+ Bool Geometry::_alpha_skip (const Var<Ray> &ray, const Var<SurfaceHit> &hit) const noexcept {
168
166
auto bary = make_float3 (1 .f - hit.bary .x - hit.bary .y , hit.bary );
169
167
auto it = interaction (hit.inst , hit.prim , bary, -ray->direction ());
170
- auto committed = def (false );
168
+ auto skip = def (true );
171
169
$if (it->shape ().maybe_non_opaque () & it->shape ().has_surface ()) {
172
170
auto u = xxhash32 (make_uint4 (hit.inst , hit.prim , compute::as<uint2>(hit.bary ))) * 0x1p-32f ;
173
171
$switch (it->shape ().surface_tag ()) {
@@ -177,23 +175,20 @@ void Geometry::_alpha_skip(SurfaceCandidate &c) const noexcept {
177
175
$case (i) {
178
176
// TODO: pass the correct swl and time
179
177
if (auto opacity = surface->evaluate_opacity (*it, _pipeline.spectrum ()->sample (.5f ), 0 .f )) {
180
- committed = u <= *opacity;
178
+ skip = u > *opacity;
181
179
} else {
182
- committed = true ;
180
+ skip = false ;
183
181
}
184
182
};
185
- }
183
+ }
186
184
}
187
185
$default { compute::unreachable (); };
188
186
};
189
187
}
190
188
$else {
191
- committed = true ;
192
- };
193
- $if (committed) {
194
- c.commit ();
195
- // $if (terminate_on_any) { c.terminate(); };
189
+ skip = false ;
196
190
};
191
+ return skip;
197
192
}
198
193
199
194
bool Geometry::update (CommandBuffer &command_buffer, float time) noexcept {
@@ -220,16 +215,42 @@ bool Geometry::update(CommandBuffer &command_buffer, float time) noexcept {
220
215
return updated;
221
216
}
222
217
223
- Var<Hit> Geometry::trace_closest (const Var<Ray> &ray ) const noexcept {
218
+ Var<Hit> Geometry::trace_closest (const Var<Ray> &ray_in ) const noexcept {
224
219
if (!_any_non_opaque) {
225
220
// happy path
221
+ auto hit = _accel->intersect (ray_in, {});
222
+ return Var<Hit>{hit.inst , hit.prim , hit.bary };
223
+ }
224
+ // TODO: DirectX has bug with ray query, so we manually march the ray here
225
+ if (_pipeline.device ().backend_name () == " dx" ) {
226
+ auto ray = ray_in;
226
227
auto hit = _accel->intersect (ray, {});
228
+ constexpr auto max_iterations = 100u ;
229
+ constexpr auto epsilone = 1e-5f ;
230
+ $for (i [[maybe_unused]], max_iterations) {
231
+ $if (hit->miss ()) { $break ; };
232
+ $if (!this ->_alpha_skip (ray, hit)) { $break ; };
233
+ #ifndef NDEBUG
234
+ $if (i == max_iterations - 1u ) {
235
+ compute::device_log (luisa::format (
236
+ " ERROR: max iterations ({}) exceeded in trace closest" ,
237
+ max_iterations));
238
+ };
239
+ #endif
240
+ ray = compute::make_ray (ray->origin (), ray->direction (),
241
+ hit.committed_ray_t + epsilone,
242
+ ray->t_max ());
243
+ hit = _accel->intersect (ray, {});
244
+ };
227
245
return Var<Hit>{hit.inst , hit.prim , hit.bary };
228
246
}
247
+ // use ray query
229
248
auto rq_hit =
230
- _accel->traverse (ray , {})
249
+ _accel->traverse (ray_in , {})
231
250
.on_surface_candidate ([&](compute::SurfaceCandidate &c) noexcept {
232
- this ->_alpha_skip (c);
251
+ $if (!this ->_alpha_skip (c.ray (), c.hit ())) {
252
+ c.commit ();
253
+ };
233
254
})
234
255
.trace ();
235
256
return Var<Hit>{rq_hit.inst , rq_hit.prim , rq_hit.bary };
@@ -243,7 +264,9 @@ Var<bool> Geometry::trace_any(const Var<Ray> &ray) const noexcept {
243
264
auto rq_hit =
244
265
_accel->traverse_any (ray, {})
245
266
.on_surface_candidate ([&](compute::SurfaceCandidate &c) noexcept {
246
- this ->_alpha_skip (c);
267
+ $if (!this ->_alpha_skip (c.ray (), c.hit ())) {
268
+ c.commit ();
269
+ };
247
270
})
248
271
.trace ();
249
272
return !rq_hit->miss ();
0 commit comments