Skip to content

Commit

Permalink
alpha skip with ray query
Browse files Browse the repository at this point in the history
  • Loading branch information
Mike-Leo-Smith committed Jan 12, 2024
1 parent a0089cb commit c58b9d2
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 89 deletions.
96 changes: 90 additions & 6 deletions src/base/geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ void Geometry::_process_shape(
InstancedTransform inst_xform{t_node, instance_id};
if (!is_static) { _dynamic_transforms.emplace_back(inst_xform); }
auto object_to_world = inst_xform.matrix(init_time);
_accel.emplace_back(*mesh.resource, object_to_world, visible);
auto vertices = shape->mesh().vertices;
for (auto &v : vertices) {
_world_max = max(_world_max, make_float3(object_to_world * make_float4(v.position(), 1.f)));
Expand All @@ -117,13 +116,22 @@ void Geometry::_process_shape(

// create instance
auto surface_tag = 0u;
auto light_tag = 0u;
auto medium_tag = 0u;
auto properties = mesh.vertex_properties;
if (surface != nullptr && !surface->is_null()) {
surface_tag = _pipeline.register_surface(command_buffer, surface);
properties |= Shape::property_flag_has_surface;
if (_pipeline.surfaces().impl(surface_tag)->maybe_non_opaque()) {
properties |= Shape::property_flag_maybe_non_opaque;
_any_non_opaque = true;
}
}

// emplace instance here since we need to know the opaque property
_accel.emplace_back(*mesh.resource, object_to_world, visible, false);
//(properties & Shape::property_flag_maybe_non_opaque) == 0u);

auto light_tag = 0u;
auto medium_tag = 0u;
if (light != nullptr && !light->is_null()) {
light_tag = _pipeline.register_light(command_buffer, light);
properties |= Shape::property_flag_has_light;
Expand Down Expand Up @@ -179,12 +187,88 @@ bool Geometry::update(CommandBuffer &command_buffer, float time) noexcept {
}

Var<Hit> Geometry::trace_closest(const Var<Ray> &ray) const noexcept {
auto hit = _accel->trace_closest(ray);
return Var<Hit>{hit.inst, hit.prim, hit.bary};
if (!_any_non_opaque) {
// happy path
auto hit = _accel->intersect(ray, {});
return Var<Hit>{hit.inst, hit.prim, hit.bary};
}
auto rq_hit =
_accel->traverse(ray, {})
.on_surface_candidate([&](compute::SurfaceCandidate &c) noexcept {
auto hit = c.hit();
auto bary = make_float3(1.f - hit.bary.x - hit.bary.y, hit.bary);
auto it = interaction(hit.inst, hit.prim, bary, -ray->direction());
$if(it->shape().maybe_non_opaque() & it->shape().has_surface()) {
PolymorphicCall<Surface::Closure> call;
_pipeline.surfaces().dispatch(it->shape().surface_tag(), [&](auto surface) noexcept {
$if(surface->maybe_non_opaque()) {
// TODO: pass the correct time
surface->closure(call, *it, _pipeline.spectrum()->sample(.5f), -ray->direction(), 1.f, 0.f);
};
});
auto u1 = xxhash32(as<uint3>(ray->origin()));
auto u2 = xxhash32(as<uint3>(ray->direction()));
auto u = xxhash32(make_uint2(u1, u2)) * 0x1p-32f;
call.execute([&](const Surface::Closure *closure) noexcept {
// apply opacity map
auto alpha_skip = def(false);
if (auto o = closure->opacity()) {
auto opacity = saturate(*o);
alpha_skip = u >= opacity;
}
$if(!alpha_skip) {
c.commit();
};
});
}
$else {
c.commit();
};
})
.trace();
return Var<Hit>{rq_hit.inst, rq_hit.prim, rq_hit.bary};
}

Var<bool> Geometry::trace_any(const Var<Ray> &ray) const noexcept {
return _accel->trace_any(ray);
if (!_any_non_opaque) {
// happy path
return _accel->intersect_any(ray, {});
}
auto rq_hit =
_accel->traverse_any(ray, {})
.on_surface_candidate([&](compute::SurfaceCandidate &c) noexcept {
auto hit = c.hit();
auto bary = make_float3(1.f - hit.bary.x - hit.bary.y, hit.bary);
auto it = interaction(hit.inst, hit.prim, bary, -ray->direction());
$if(it->shape().maybe_non_opaque() & it->shape().has_surface()) {
PolymorphicCall<Surface::Closure> call;
_pipeline.surfaces().dispatch(it->shape().surface_tag(), [&](auto surface) noexcept {
$if(surface->maybe_non_opaque()) {
// TODO: pass the correct time
surface->closure(call, *it, _pipeline.spectrum()->sample(.5f), -ray->direction(), 1.f, 0.f);
};
});
auto u1 = xxhash32(as<uint3>(ray->origin()));
auto u2 = xxhash32(as<uint3>(ray->direction()));
auto u = xxhash32(make_uint2(u1, u2)) * 0x1p-32f;
call.execute([&](const Surface::Closure *closure) noexcept {
// apply opacity map
auto alpha_skip = def(false);
if (auto o = closure->opacity()) {
auto opacity = saturate(*o);
alpha_skip = u >= opacity;
}
$if(!alpha_skip) {
c.commit();
};
});
}
$else {
c.commit();
};
})
.trace();
return !rq_hit->miss();
}

luisa::shared_ptr<Interaction> Geometry::interaction(Expr<uint> inst_id, Expr<uint> prim_id,
Expand Down
4 changes: 2 additions & 2 deletions src/base/geometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ class Geometry {
Buffer<uint4> _instance_buffer;
float3 _world_min;
float3 _world_max;

uint _triangle_count; // for debug
uint _triangle_count;// for debug
bool _any_non_opaque{false};

private:
void _process_shape(
Expand Down
4 changes: 2 additions & 2 deletions src/base/pipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ luisa::unique_ptr<Pipeline> Pipeline::create(Device &device, Stream &stream, con
bool Pipeline::update(CommandBuffer &command_buffer, float time) noexcept {
// TODO: support deformable meshes
auto updated = _geometry->update(command_buffer, time);
if (_any_dynamic_transforms) {
if (_any_dynamic_transform) {
updated = true;
for (auto i = 0u; i < _transforms.size(); ++i) {
_transform_matrices[i] = _transforms[i]->matrix(time);
Expand Down Expand Up @@ -151,7 +151,7 @@ void Pipeline::register_transform(const Transform *transform) noexcept {
"Transform matrix buffer overflows.");
_transform_to_id.emplace(transform, transform_id);
_transforms.emplace_back(transform);
_any_dynamic_transforms |= !transform->is_static();
_any_dynamic_transform |= !transform->is_static();
_transform_matrices[transform_id] = transform->matrix(_initial_time);
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/base/pipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ class Pipeline {
// other things
luisa::unique_ptr<Printer> _printer;
float _initial_time{};
bool _any_dynamic_transforms{false};
bool _any_dynamic_transform{false};
bool _any_non_opaque_surface{false};

public:
// for internal use only; use Pipeline::create() instead
Expand Down Expand Up @@ -207,6 +208,7 @@ class Pipeline {
[[nodiscard]] auto spectrum() const noexcept { return _spectrum.get(); }
[[nodiscard]] auto geometry() const noexcept { return _geometry.get(); }
[[nodiscard]] auto has_lighting() const noexcept { return !_lights.empty() || _environment != nullptr; }
[[nodiscard]] auto has_non_opaque_surfaces() const noexcept { return _any_non_opaque_surface; }
[[nodiscard]] const Texture::Instance *build_texture(CommandBuffer &command_buffer, const Texture *texture) noexcept;
[[nodiscard]] const Filter::Instance *build_filter(CommandBuffer &command_buffer, const Filter *filter) noexcept;
[[nodiscard]] const PhaseFunction::Instance *build_phasefunction(CommandBuffer &command_buffer, const PhaseFunction *phasefunction) noexcept;
Expand Down
5 changes: 4 additions & 1 deletion src/base/shape.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class Shape : public SceneNode {
static constexpr auto property_flag_has_surface = 1u << 2u;
static constexpr auto property_flag_has_light = 1u << 3u;
static constexpr auto property_flag_has_medium = 1u << 4u;
static constexpr auto property_flag_maybe_non_opaque = 1u << 5u;

private:
const Surface *_surface;
Expand Down Expand Up @@ -153,7 +154,8 @@ class Shape::Handle {
private:
Handle(Expr<uint> buffer_base, Expr<uint> flags,
Expr<uint> surface_tag, Expr<uint> light_tag, Expr<uint> medium_tag,
Expr<uint> triangle_count, Expr<float> shadow_terminator, Expr<float> intersection_offset) noexcept
Expr<uint> triangle_count,
Expr<float> shadow_terminator, Expr<float> intersection_offset) noexcept
: _buffer_base{buffer_base}, _properties{flags},
_surface_tag{surface_tag}, _light_tag{light_tag}, _medium_tag{medium_tag},
_triangle_count{triangle_count},
Expand Down Expand Up @@ -184,6 +186,7 @@ class Shape::Handle {
[[nodiscard]] auto has_light() const noexcept { return test_property_flag(luisa::render::Shape::property_flag_has_light); }
[[nodiscard]] auto has_surface() const noexcept { return test_property_flag(luisa::render::Shape::property_flag_has_surface); }
[[nodiscard]] auto has_medium() const noexcept { return test_property_flag(luisa::render::Shape::property_flag_has_medium); }
[[nodiscard]] auto maybe_non_opaque() const noexcept { return test_property_flag(luisa::render::Shape::property_flag_maybe_non_opaque); }
[[nodiscard]] auto shadow_terminator_factor() const noexcept { return _shadow_terminator; }
[[nodiscard]] auto intersection_offset_factor() const noexcept { return _intersection_offset; }
};
Expand Down
8 changes: 8 additions & 0 deletions src/base/surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ class Surface : public SceneNode {
[[nodiscard]] auto node() const noexcept { return static_cast<const T *>(_surface); }
[[nodiscard]] auto &pipeline() const noexcept { return _pipeline; }

[[nodiscard]] virtual bool maybe_non_opaque() const noexcept { return false; }

void closure(PolymorphicCall<Closure> &call,
const Interaction &it, const SampledWavelengths &swl,
Expr<float3> wo, Expr<float> eta_i, Expr<float> time) const noexcept;
Expand Down Expand Up @@ -252,6 +254,12 @@ class OpacitySurfaceWrapper : public BaseSurface {
typename Closure::Context ctx{.opacity = o};
closure->bind(std::move(ctx));
}

[[nodiscard]] bool maybe_non_opaque() const noexcept override {
if (BaseInstance::maybe_non_opaque()) { return true; }
return _opacity != nullptr &&
_opacity->node()->evaluate_static().value_or(make_float4(0.f)).x < 1.f;
}
};

private:
Expand Down
56 changes: 21 additions & 35 deletions src/integrators/mega_path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,42 +117,28 @@ class MegakernelPathTracingInstance final : public ProgressiveIntegrator::Instan
surface->closure(call, *it, swl, wo, 1.f, time);
});
call.execute([&](const Surface::Closure *closure) noexcept {
// apply opacity map
auto alpha_skip = def(false);
if (auto o = closure->opacity()) {
auto opacity = saturate(*o);
alpha_skip = u_lobe >= opacity;
u_lobe = ite(alpha_skip, (u_lobe - opacity) / (1.f - opacity), u_lobe / opacity);
if (auto dispersive = closure->is_dispersive()) {
$if(*dispersive) { swl.terminate_secondary(); };
}

$if(alpha_skip) {
ray = it->spawn_ray(ray->direction());
pdf_bsdf = 1e16f;
}
$else {
if (auto dispersive = closure->is_dispersive()) {
$if(*dispersive) { swl.terminate_secondary(); };
}
// direct lighting
$if(light_sample.eval.pdf > 0.0f & !occluded) {
auto wi = light_sample.shadow_ray->direction();
auto eval = closure->evaluate(wo, wi);
auto w = balance_heuristic(light_sample.eval.pdf, eval.pdf) /
light_sample.eval.pdf;
Li += w * beta * eval.f * light_sample.eval.L;
};
// sample material
auto surface_sample = closure->sample(wo, u_lobe, u_bsdf);
ray = it->spawn_ray(surface_sample.wi);
pdf_bsdf = surface_sample.eval.pdf;
auto w = ite(surface_sample.eval.pdf > 0.f, 1.f / surface_sample.eval.pdf, 0.f);
beta *= w * surface_sample.eval.f;
// apply eta scale
auto eta = closure->eta().value_or(1.f);
$switch(surface_sample.event) {
$case(Surface::event_enter) { eta_scale = sqr(eta); };
$case(Surface::event_exit) { eta_scale = sqr(1.f / eta); };
};
// direct lighting
$if(light_sample.eval.pdf > 0.0f & !occluded) {
auto wi = light_sample.shadow_ray->direction();
auto eval = closure->evaluate(wo, wi);
auto w = balance_heuristic(light_sample.eval.pdf, eval.pdf) /
light_sample.eval.pdf;
Li += w * beta * eval.f * light_sample.eval.L;
};
// sample material
auto surface_sample = closure->sample(wo, u_lobe, u_bsdf);
ray = it->spawn_ray(surface_sample.wi);
pdf_bsdf = surface_sample.eval.pdf;
auto w = ite(surface_sample.eval.pdf > 0.f, 1.f / surface_sample.eval.pdf, 0.f);
beta *= w * surface_sample.eval.f;
// apply eta scale
auto eta = closure->eta().value_or(1.f);
$switch(surface_sample.event) {
$case(Surface::event_enter) { eta_scale = sqr(eta); };
$case(Surface::event_exit) { eta_scale = sqr(1.f / eta); };
};
});
};
Expand Down
70 changes: 28 additions & 42 deletions src/integrators/wave_path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,49 +402,35 @@ void WavefrontPathTracingInstance::_render_one_camera(
});

call.execute([&](const Surface::Closure *closure) noexcept {
// apply opacity map
auto alpha_skip = def(false);
if (auto o = closure->opacity()) {
auto opacity = saturate(*o);
alpha_skip = u_lobe >= opacity;
u_lobe = ite(alpha_skip, (u_lobe - opacity) / (1.f - opacity), u_lobe / opacity);
}

$if(alpha_skip) {
ray = it->spawn_ray(ray->direction());
path_states.write_pdf_bsdf(path_id, 1e16f);
}
$else {
if (auto dispersive = closure->is_dispersive()) {
$if(*dispersive) {
swl.terminate_secondary();
path_states.terminate_secondary_wavelengths(path_id, u_wl);
};
}
// direct lighting
auto light_wi_and_pdf = light_samples.read_wi_and_pdf(queue_id);
auto pdf_light = light_wi_and_pdf.w;
$if(light_wi_and_pdf.w > 0.f) {
auto eval = closure->evaluate(wo, light_wi_and_pdf.xyz());
auto mis_weight = balance_heuristic(pdf_light, eval.pdf);
// update Li
auto Ld = light_samples.read_emission(queue_id);
auto Li = path_states.read_radiance(path_id);
Li += mis_weight / pdf_light * beta * eval.f * Ld;
path_states.write_radiance(path_id, Li);
};
// sample material
auto surface_sample = closure->sample(wo, u_lobe, u_bsdf);
path_states.write_pdf_bsdf(path_id, surface_sample.eval.pdf);
ray = it->spawn_ray(surface_sample.wi);
auto w = ite(surface_sample.eval.pdf > 0.0f, 1.f / surface_sample.eval.pdf, 0.f);
beta *= w * surface_sample.eval.f;
// eta scale
auto eta = closure->eta().value_or(1.f);
$switch(surface_sample.event) {
$case(Surface::event_enter) { eta_scale = sqr(eta); };
$case(Surface::event_exit) { eta_scale = 1.f / sqr(eta); };
if (auto dispersive = closure->is_dispersive()) {
$if(*dispersive) {
swl.terminate_secondary();
path_states.terminate_secondary_wavelengths(path_id, u_wl);
};
}
// direct lighting
auto light_wi_and_pdf = light_samples.read_wi_and_pdf(queue_id);
auto pdf_light = light_wi_and_pdf.w;
$if(light_wi_and_pdf.w > 0.f) {
auto eval = closure->evaluate(wo, light_wi_and_pdf.xyz());
auto mis_weight = balance_heuristic(pdf_light, eval.pdf);
// update Li
auto Ld = light_samples.read_emission(queue_id);
auto Li = path_states.read_radiance(path_id);
Li += mis_weight / pdf_light * beta * eval.f * Ld;
path_states.write_radiance(path_id, Li);
};
// sample material
auto surface_sample = closure->sample(wo, u_lobe, u_bsdf);
path_states.write_pdf_bsdf(path_id, surface_sample.eval.pdf);
ray = it->spawn_ray(surface_sample.wi);
auto w = ite(surface_sample.eval.pdf > 0.0f, 1.f / surface_sample.eval.pdf, 0.f);
beta *= w * surface_sample.eval.f;
// eta scale
auto eta = closure->eta().value_or(1.f);
$switch(surface_sample.event) {
$case(Surface::event_enter) { eta_scale = sqr(eta); };
$case(Surface::event_exit) { eta_scale = 1.f / sqr(eta); };
};
});

Expand Down
4 changes: 4 additions & 0 deletions src/surfaces/layered.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ class LayeredSurfaceInstance : public Surface::Instance {
}
[[nodiscard]] luisa::unique_ptr<Surface::Closure> create_closure(const SampledWavelengths &swl, Expr<float> time) const noexcept override;
void populate_closure(Surface::Closure *closure, const Interaction &it, Expr<float3> wo, Expr<float> eta_i) const noexcept override;

[[nodiscard]] bool maybe_non_opaque() const noexcept override {
return _top->maybe_non_opaque() || _bottom->maybe_non_opaque();
}
};

luisa::unique_ptr<Surface::Instance> LayeredSurface::_build(Pipeline &pipeline, CommandBuffer &command_buffer) const noexcept {
Expand Down
4 changes: 4 additions & 0 deletions src/surfaces/mix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ class MixSurfaceInstance : public Surface::Instance {
}
[[nodiscard]] luisa::unique_ptr<Surface::Closure> create_closure(const SampledWavelengths &swl, Expr<float> time) const noexcept override;
void populate_closure(Surface::Closure *closure, const Interaction &it, Expr<float3> wo, Expr<float> eta_i) const noexcept override;

[[nodiscard]] bool maybe_non_opaque() const noexcept override {
return _a->maybe_non_opaque() || _b->maybe_non_opaque();
}
};

luisa::unique_ptr<Surface::Instance> MixSurface::_build(
Expand Down

0 comments on commit c58b9d2

Please sign in to comment.