Skip to content

Commit

Permalink
Ray visibility flags for lights
Browse files Browse the repository at this point in the history
  • Loading branch information
sergcpp committed Jul 28, 2024
1 parent 45cd6d5 commit d6ad998
Show file tree
Hide file tree
Showing 82 changed files with 422 additions and 320 deletions.
32 changes: 25 additions & 7 deletions SceneBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,17 +195,23 @@ struct tex_desc_t {
struct directional_light_desc_t {
float color[3] = {1.0f, 1.0f, 1.0f};
float direction[3] = {0.0f, -1.0f, 0.0f}, angle = 0.0f;
bool visible = true; // visibility only affects secondary bounces
bool visible = true;
bool cast_shadow = true;
bool diffuse_visibility = true; ///< Light visibility to diffuse rays
bool specular_visibility = true; ///< Light visibility to specular rays
bool refraction_visibility = true; ///< Light visibility to refraction (transmission) rays
};

/// Spherical light source description
struct sphere_light_desc_t {
float color[3] = {1.0f, 1.0f, 1.0f};
float position[3] = {0.0f, 0.0f, 0.0f};
float radius = 1.0f;
bool visible = true; // visibility only affects secondary bounces
bool visible = true;
bool cast_shadow = true;
bool diffuse_visibility = true; ///< Light visibility to diffuse rays
bool specular_visibility = true; ///< Light visibility to specular rays
bool refraction_visibility = true; ///< Light visibility to refraction (transmission) rays
};

/// Spotlight description
Expand All @@ -216,35 +222,47 @@ struct spot_light_desc_t {
float spot_size = 45.0f;
float spot_blend = 0.15f;
float radius = 1.0f;
bool visible = true; // visibility only affects secondary bounces
bool visible = true;
bool cast_shadow = true;
bool diffuse_visibility = true; ///< Light visibility to diffuse rays
bool specular_visibility = true; ///< Light visibility to specular rays
bool refraction_visibility = true; ///< Light visibility to refraction (transmission) rays
};

/// Rectangular lightsource description
struct rect_light_desc_t {
float color[3] = {1.0f, 1.0f, 1.0f};
float width = 1.0f, height = 1.0f;
bool sky_portal = false;
bool visible = true; // visibility only affects secondary bounces
bool visible = true;
bool cast_shadow = true;
bool diffuse_visibility = true; ///< Light visibility to diffuse rays
bool specular_visibility = true; ///< Light visibility to specular rays
bool refraction_visibility = true; ///< Light visibility to refraction (transmission) rays
};

/// Disk lightsource description
struct disk_light_desc_t {
float color[3] = {1.0f, 1.0f, 1.0f};
float size_x = 1.0f, size_y = 1.0f;
bool sky_portal = false;
bool visible = true; // visibility only affects secondary bounces
bool visible = true;
bool cast_shadow = true;
bool diffuse_visibility = true; ///< Light visibility to diffuse rays
bool specular_visibility = true; ///< Light visibility to specular rays
bool refraction_visibility = true; ///< Light visibility to refraction (transmission) rays
};

/// Line light description
struct line_light_desc_t {
float color[3] = {1.0f, 1.0f, 1.0f};
float radius = 1.0f, height = 1.0f;
bool sky_portal = false;
bool visible = true; // visibility only affects secondary bounces
bool visible = true;
bool cast_shadow = true;
bool diffuse_visibility = true; ///< Light visibility to diffuse rays
bool specular_visibility = true; ///< Light visibility to specular rays
bool refraction_visibility = true; ///< Light visibility to refraction (transmission) rays
};

/// Camera description
Expand Down Expand Up @@ -310,7 +328,7 @@ struct atmosphere_params_t {
float atmosphere_density = 1.0f; ///< Atmosphere density multiplier
float stars_brightness = 1.0f; ///< Brightness of the stars in the sky (set to 0.0 to disable)
float moon_radius = 1737400.0f; ///< Moon radius (set to 0.0 to disable)
float moon_distance = 100000000.0f;//363100000.0f; ///< Distance from Earth to the Moon
float moon_distance = 100000000.0f; // 363100000.0f; ///< Distance from Earth to the Moon
alignas(16) float moon_dir[4] = {0.707f, 0.707f, 0.0f, 0.0f};
alignas(16) float rayleigh_scattering[4] = {5.802f * 1e-6f, 13.558f * 1e-6f, 33.100f * 1e-6f, 0.0f};
alignas(16) float mie_scattering[4] = {3.996f * 1e-6f, 3.996f * 1e-6f, 3.996f * 1e-6f, 0.0f};
Expand Down
6 changes: 6 additions & 0 deletions internal/Constants.inl
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ const int RAY_TYPE_SPECULAR = 2;
const int RAY_TYPE_REFR = 3;
const int RAY_TYPE_SHADOW = 4;

const uint RAY_TYPE_CAMERA_BIT = (1u << RAY_TYPE_CAMERA);
const uint RAY_TYPE_DIFFUSE_BIT = (1u << RAY_TYPE_DIFFUSE);
const uint RAY_TYPE_SPECULAR_BIT = (1u << RAY_TYPE_SPECULAR);
const uint RAY_TYPE_REFR_BIT = (1u << RAY_TYPE_REFR);
const uint RAY_TYPE_SHADOW_BIT = (1u << RAY_TYPE_SHADOW);

//
// Material constants
//
Expand Down
4 changes: 2 additions & 2 deletions internal/Core.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,8 @@ struct light_t {
uint32_t cast_shadow : 1;
uint32_t visible : 1;
uint32_t sky_portal : 1;
uint32_t blocking : 1;
uint32_t _unused : 24;
uint32_t ray_visibility : 8;
uint32_t _unused0 : 17;
float col[3];
union {
struct {
Expand Down
17 changes: 14 additions & 3 deletions internal/CoreRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2739,6 +2739,7 @@ void Ray::Ref::SampleLightSource(const fvec4 &P, const fvec4 &T, const fvec4 &B,
}
ls.L = sampled_dir;
ls.area = l.sph.area;
ls.ray_flags = l.ray_visibility;

if (!l.visible) {
ls.area = 0.0f;
Expand Down Expand Up @@ -2769,6 +2770,7 @@ void Ray::Ref::SampleLightSource(const fvec4 &P, const fvec4 &T, const fvec4 &B,
}
ls.lp = P + ls.L;
ls.dist_mul = MAX_DIST;
ls.ray_flags = l.ray_visibility;

if (!l.visible) {
ls.area = 0.0f;
Expand All @@ -2791,6 +2793,7 @@ void Ray::Ref::SampleLightSource(const fvec4 &P, const fvec4 &T, const fvec4 &B,

float ls_dist;
ls.L = normalize_len(lp - P, ls_dist);
ls.ray_flags = l.ray_visibility;

const float cos_theta = dot(-ls.L, light_forward);
if (cos_theta > 0.0f) {
Expand Down Expand Up @@ -2835,6 +2838,7 @@ void Ray::Ref::SampleLightSource(const fvec4 &P, const fvec4 &T, const fvec4 &B,
float ls_dist;
ls.L = normalize_len(lp - P, ls_dist);
ls.area = l.disk.area;
ls.ray_flags = l.ray_visibility;

const float cos_theta = dot(-ls.L, light_forward);
if (cos_theta > 0.0f) {
Expand Down Expand Up @@ -2874,6 +2878,7 @@ void Ray::Ref::SampleLightSource(const fvec4 &P, const fvec4 &T, const fvec4 &B,
float ls_dist;
ls.L = normalize_len(lp - P, ls_dist);
ls.area = l.line.area;
ls.ray_flags = l.ray_visibility;

const float cos_theta = 1.0f - fabsf(dot(ls.L, light_dir));
if (cos_theta != 0.0f) {
Expand All @@ -2900,6 +2905,7 @@ void Ray::Ref::SampleLightSource(const fvec4 &P, const fvec4 &T, const fvec4 &B,
float light_fwd_len;
const fvec4 light_forward = normalize_len(cross(e1, e2), light_fwd_len);
ls.area = 0.5f * light_fwd_len;
ls.ray_flags = l.ray_visibility;

fvec4 lp;
fvec2 luvs;
Expand Down Expand Up @@ -2984,6 +2990,7 @@ void Ray::Ref::SampleLightSource(const fvec4 &P, const fvec4 &T, const fvec4 &B,
ls.dist_mul = MAX_DIST;
ls.pdf = dir_and_pdf.get<3>();
ls.from_env = 1;
ls.ray_flags = l.ray_visibility;
}

ls.pdf /= factor;
Expand All @@ -2998,6 +3005,8 @@ void Ray::Ref::IntersectAreaLights(Span<const ray_data_t> rays, Span<const light
const fvec4 ro = make_fvec3(ray.o);
const fvec4 rd = make_fvec3(ray.d);

const uint32_t ray_flags = (1u << get_ray_type(ray.depth));

float inv_d[3];
safe_invert(value_ptr(rd), inv_d);

Expand Down Expand Up @@ -3096,7 +3105,7 @@ void Ray::Ref::IntersectAreaLights(Span<const ray_data_t> rays, Span<const light
////

const light_t &l = lights[light_index];
if (!l.visible) {
if (!l.visible || (l.ray_visibility & ray_flags) == 0) {
continue;
}
if (l.sky_portal && inout_inter.v >= 0.0f) {
Expand Down Expand Up @@ -3244,6 +3253,8 @@ void Ray::Ref::IntersectAreaLights(Span<const ray_data_t> rays, Span<const light
const fvec4 ro = make_fvec3(ray.o);
const fvec4 rd = make_fvec3(ray.d);

const uint32_t ray_flags = (1u << get_ray_type(ray.depth));

float inv_d[3];
safe_invert(value_ptr(rd), inv_d);

Expand Down Expand Up @@ -3292,7 +3303,7 @@ void Ray::Ref::IntersectAreaLights(Span<const ray_data_t> rays, Span<const light
////

const light_t &l = lights[light_index];
if (!l.visible) {
if (!l.visible || (l.ray_visibility & ray_flags) == 0) {
continue;
}
if (l.sky_portal && inout_inter.v >= 0.0f) {
Expand Down Expand Up @@ -3517,7 +3528,7 @@ float Ray::Ref::IntersectAreaLights(const shadow_ray_t &ray, Span<const light_t>
const int light_index = int(nodes[cur.index].child[0] & PRIM_INDEX_BITS);
assert(nodes[cur.index].child[1] == 1);
const light_t &l = lights[light_index];
if (!l.blocking) {
if ((l.ray_visibility & RAY_TYPE_SHADOW_BIT) == 0) {
continue;
}
if (l.sky_portal && ray.dist >= 0.0f) {
Expand Down
3 changes: 2 additions & 1 deletion internal/CoreRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ struct light_sample_t {
float area = 0, dist_mul = 1, pdf = 0;
uint32_t cast_shadow : 1;
uint32_t from_env : 1;
uint32_t _pad0 : 30;
uint32_t ray_flags : 8;
uint32_t _pad0 : 22;
};
static_assert(sizeof(light_sample_t) == 64, "!");

Expand Down
32 changes: 26 additions & 6 deletions internal/CoreSIMD.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ template <int S> struct surface_t {
template <int S> struct light_sample_t {
fvec<S> col[3] = {0.0f, 0.0f, 0.0f}, L[3] = {0.0f, 0.0f, 0.0f}, lp[3] = {0.0f, 0.0f, 0.0f};
fvec<S> area = 0.0f, dist_mul = 1.0f, pdf = 0.0f;
ivec<S> ray_flags = 0;
// TODO: merge these two into bitflags
ivec<S> cast_shadow = -1, from_env = 0;

Expand Down Expand Up @@ -5559,6 +5560,7 @@ void Ray::NS::SampleLightSource(const fvec<S> P[3], const fvec<S> T[3], const fv

UNROLLED_FOR(i, 3, { where(ray_queue[index], ls.L[i]) = sampled_dir[i]; })
where(ray_queue[index], ls.area) = l.sph.area;
where(ray_queue[index], ls.ray_flags) = l.ray_visibility;

if (!l.visible) {
where(ray_queue[index], ls.area) = 0.0f;
Expand Down Expand Up @@ -5598,6 +5600,7 @@ void Ray::NS::SampleLightSource(const fvec<S> P[3], const fvec<S> T[3], const fv
where(ray_queue[index], ls.pdf) = safe_div_pos(1.0f, ls.area * cos_theta);
}
UNROLLED_FOR(i, 3, { where(ray_queue[index], ls.lp[i]) = P[i] + ls.L[i]; })
where(ray_queue[index], ls.ray_flags) = l.ray_visibility;

if (!l.visible) {
where(ray_queue[index], ls.area) = 0.0f;
Expand Down Expand Up @@ -5633,6 +5636,7 @@ void Ray::NS::SampleLightSource(const fvec<S> P[3], const fvec<S> T[3], const fv
})

where(ray_queue[index], ls.area) = l.rect.area;
where(ray_queue[index], ls.ray_flags) = l.ray_visibility;

const fvec<S> cos_theta =
-ls.L[0] * light_forward[0] - ls.L[1] * light_forward[1] - ls.L[2] * light_forward[2];
Expand Down Expand Up @@ -5678,6 +5682,7 @@ void Ray::NS::SampleLightSource(const fvec<S> P[3], const fvec<S> T[3], const fv

UNROLLED_FOR(i, 3, { where(ray_queue[index], ls.L[i]) = to_light[i]; })
where(ray_queue[index], ls.area) = l.disk.area;
where(ray_queue[index], ls.ray_flags) = l.ray_visibility;

float light_forward[3];
cross(l.disk.u, l.disk.v, light_forward);
Expand Down Expand Up @@ -5743,6 +5748,7 @@ void Ray::NS::SampleLightSource(const fvec<S> P[3], const fvec<S> T[3], const fv

UNROLLED_FOR(i, 3, { where(ray_queue[index], ls.L[i]) = to_light[i]; })
where(ray_queue[index], ls.area) = l.line.area;
where(ray_queue[index], ls.ray_flags) = l.ray_visibility;

const fvec<S> cos_theta = 1.0f - abs(dot3(ls.L, light_dir));
fvec<S> pdf = safe_div_pos(ls_dist * ls_dist, ls.area * cos_theta);
Expand Down Expand Up @@ -5778,6 +5784,7 @@ void Ray::NS::SampleLightSource(const fvec<S> P[3], const fvec<S> T[3], const fv
light_forward[2] * light_forward[2]);
where(ray_queue[index], ls.area) = 0.5f * light_fwd_len;
UNROLLED_FOR(i, 3, { light_forward[i] /= light_fwd_len; })
where(ray_queue[index], ls.ray_flags) = l.ray_visibility;

fvec<S> lp[3] = {};
fvec<S> luvs[2] = {};
Expand Down Expand Up @@ -5889,6 +5896,7 @@ void Ray::NS::SampleLightSource(const fvec<S> P[3], const fvec<S> T[3], const fv
where(ray_queue[index], ls.dist_mul) = MAX_DIST;
where(ray_queue[index], ls.pdf) = dir_and_pdf[3];
where(ray_queue[index], ls.from_env) = -1;
where(ray_queue[index], ls.ray_flags) = l.ray_visibility;
}

++index;
Expand All @@ -5910,6 +5918,10 @@ void Ray::NS::IntersectAreaLights(const ray_data_t<S> &r, Span<const light_t> li
r.mask.store_to(ray_masks, vector_aligned);
inout_inter.t.store_to(inter_t, vector_aligned);

const uvec<S> _ray_flags = uvec<S>(1 << get_ray_type(r.depth));
alignas(S * 4) uint32_t ray_flags[S];
_ray_flags.store_to(ray_flags, vector_aligned);

for (int ri = 0; ri < S; ri++) {
if (!ray_masks[ri]) {
continue;
Expand Down Expand Up @@ -6012,7 +6024,7 @@ void Ray::NS::IntersectAreaLights(const ray_data_t<S> &r, Span<const light_t> li
const uint32_t light_index = (nodes[cur.index].child[0] & PRIM_INDEX_BITS);
assert(nodes[cur.index].child[1] == 1);
const light_t &l = lights[light_index];
if (!l.visible) {
if (!l.visible || (l.ray_visibility & ray_flags[ri]) == 0) {
continue;
}
// Portal lights affect only missed rays
Expand Down Expand Up @@ -6275,7 +6287,7 @@ Ray::NS::fvec<S> Ray::NS::IntersectAreaLights(const shadow_ray_t<S> &r, Span<con
const int light_index = int(nodes[cur.index].child[0] & PRIM_INDEX_BITS);
assert(nodes[cur.index].child[1] == 1);
const light_t &l = lights[light_index];
if (!l.blocking) {
if ((l.ray_visibility & RAY_TYPE_SHADOW_BIT) == 0) {
continue;
}
const ivec<S> portal_mask = l.sky_portal ? env_ray : -1;
Expand Down Expand Up @@ -6791,7 +6803,8 @@ Ray::NS::ivec<S> Ray::NS::Evaluate_PrincipledNode(
fvec<S> lcol[3] = {0.0f, 0.0f, 0.0f};
fvec<S> bsdf_pdf = 0.0f;

const ivec<S> eval_diff_lobe = simd_cast(lobe_weights.diffuse > 0.0f) & _is_frontfacing & mask;
const ivec<S> eval_diff_lobe =
simd_cast(lobe_weights.diffuse > 0.0f) & ((ls.ray_flags & RAY_TYPE_DIFFUSE_BIT) != 0) & _is_frontfacing & mask;
if (eval_diff_lobe.not_all_zeros()) {
fvec<S> diff_col[4];
Evaluate_PrincipledDiffuse_BSDF(nI, surf.N, ls.L, diff.roughness, diff.base_color, diff.sheen_color, false,
Expand All @@ -6817,6 +6830,7 @@ Ray::NS::ivec<S> Ray::NS::Evaluate_PrincipledNode(

const std::array<fvec<S>, 2> spec_alpha = calc_alpha(spec.roughness, spec.anisotropy, regularize_alpha);
const ivec<S> eval_spec_lobe = simd_cast(lobe_weights.specular > 0.0f) &
((ls.ray_flags & RAY_TYPE_SPECULAR_BIT) != 0) &
simd_cast(spec_alpha[0] * spec_alpha[1] >= 1e-7f) & _is_frontfacing & mask;
if (eval_spec_lobe.not_all_zeros()) {
fvec<S> spec_col[4], _alpha[2] = {max(spec_alpha[0], 1e-7f), max(spec_alpha[1], 1e-7f)};
Expand All @@ -6830,6 +6844,7 @@ Ray::NS::ivec<S> Ray::NS::Evaluate_PrincipledNode(

const std::array<fvec<S>, 2> coat_alpha = calc_alpha(coat.roughness, fvec<S>{0.0f}, regularize_alpha);
const ivec<S> eval_coat_lobe = simd_cast(lobe_weights.clearcoat > 0.0f) &
((ls.ray_flags & RAY_TYPE_SPECULAR_BIT) != 0) &
simd_cast(coat_alpha[0] * coat_alpha[1] >= 1e-7f) & _is_frontfacing & mask;
if (eval_coat_lobe.not_all_zeros()) {
fvec<S> clearcoat_col[4];
Expand All @@ -6844,6 +6859,7 @@ Ray::NS::ivec<S> Ray::NS::Evaluate_PrincipledNode(

const std::array<fvec<S>, 2> refr_spec_alpha = calc_alpha(spec.roughness, fvec<S>{0.0f}, regularize_alpha);
const ivec<S> eval_refr_spec_lobe = simd_cast(trans.fresnel != 0.0f) & simd_cast(lobe_weights.refraction > 0.0f) &
((ls.ray_flags & RAY_TYPE_SPECULAR_BIT) != 0) &
simd_cast(refr_spec_alpha[0] * refr_spec_alpha[1] >= 1e-7f) & _is_frontfacing &
mask;
if (eval_refr_spec_lobe.not_all_zeros()) {
Expand All @@ -6860,6 +6876,7 @@ Ray::NS::ivec<S> Ray::NS::Evaluate_PrincipledNode(

const std::array<fvec<S>, 2> refr_trans_alpha = calc_alpha(trans.roughness, fvec<S>{0.0f}, regularize_alpha);
const ivec<S> eval_refr_trans_lobe = simd_cast(trans.fresnel != 1.0f) & simd_cast(lobe_weights.refraction > 0.0f) &
((ls.ray_flags & RAY_TYPE_REFR_BIT) != 0) &
simd_cast(refr_trans_alpha[0] * refr_trans_alpha[1] >= 1e-7f) &
_is_backfacing & mask;
if (eval_refr_trans_lobe.not_all_zeros()) {
Expand Down Expand Up @@ -7654,7 +7671,8 @@ void Ray::NS::ShadeSurface(const pass_settings_t &ps, const float limits[2], con
const material_t *mat = &sc.materials[first_mi];
if (mat->type == eShadingNode::Diffuse) {
#if USE_NEE
const ivec<S> eval_light = simd_cast(ls.pdf > 0.0f) & simd_cast(N_dot_L > 0.0f) & ray_queue[index];
const ivec<S> eval_light = simd_cast(ls.pdf > 0.0f) & ((ls.ray_flags & RAY_TYPE_DIFFUSE_BIT) != 0) &
simd_cast(N_dot_L > 0.0f) & ray_queue[index];
if (eval_light.not_all_zeros()) {
assert((shadow_mask & eval_light).all_zeros());
shadow_mask |= Evaluate_DiffuseNode(ls, ray, eval_light, surf, base_color, roughness, mix_weight,
Expand All @@ -7675,7 +7693,8 @@ void Ray::NS::ShadeSurface(const pass_settings_t &ps, const float limits[2], con
const float spec_F0 = fresnel_dielectric_cos(1.0f, spec_ior);

#if USE_NEE
const ivec<S> eval_light = simd_cast(ls.pdf > 0.0f) & simd_cast(N_dot_L > 0.0f) & ray_queue[index];
const ivec<S> eval_light = simd_cast(ls.pdf > 0.0f) & ((ls.ray_flags & RAY_TYPE_SPECULAR_BIT) != 0) &
simd_cast(N_dot_L > 0.0f) & ray_queue[index];
if (eval_light.not_all_zeros()) {
assert((shadow_mask & eval_light).all_zeros());
shadow_mask |= Evaluate_GlossyNode(ls, ray, eval_light, surf, base_color, roughness,
Expand All @@ -7694,7 +7713,8 @@ void Ray::NS::ShadeSurface(const pass_settings_t &ps, const float limits[2], con
}
} else if (mat->type == eShadingNode::Refractive) {
#if USE_NEE
const ivec<S> eval_light = simd_cast(ls.pdf > 0.0f) & simd_cast(N_dot_L < 0.0f) & ray_queue[index];
const ivec<S> eval_light = simd_cast(ls.pdf > 0.0f) & ((ls.ray_flags & RAY_TYPE_REFR_BIT) != 0) &
simd_cast(N_dot_L < 0.0f) & ray_queue[index];
if (eval_light.not_all_zeros()) {
assert((shadow_mask & eval_light).all_zeros());
const fvec<S> eta = select(is_backfacing, mat->ior / ext_ior, ext_ior / mat->ior);
Expand Down
Loading

0 comments on commit d6ad998

Please sign in to comment.