diff --git a/packages/ludic.render3d/scatter.ludic b/packages/ludic.render3d/scatter.ludic index 48d70f6a..fcbea5de 100644 --- a/packages/ludic.render3d/scatter.ludic +++ b/packages/ludic.render3d/scatter.ludic @@ -1058,6 +1058,7 @@ function scatter_draw(render3d_st: mut Render3dState) -> void { # whole class of caster vanish at a fixed distance, which is exactly the popping. A layer # with an impostor now casts its entire instance list from the card in every cascade; # only layers that have no impostor at all fall back to the mesh. +const SC_IMP_CAST_CASCADE: int = 2 function scatter_draw_casters(render3d_st: mut Render3dState, light_vp: floats) -> void { for i in 0 .. len(render3d_st.sc_layers) { let l = render3d_st.sc_layers[i] @@ -1067,7 +1068,10 @@ function scatter_draw_casters(render3d_st: mut Render3dState, light_vp: floats) if render3d_st.r3d_no_trees and l.imp != null and not l.card { continue } layer_update(render3d_st, l) if l.imp != null { - layer_draw_shadow(render3d_st, l, light_vp) + # the impostor casts only into the far cascades: every tree on the map was drawn as a card + # into the near two as well, whose receivers (within 60 m) are shaded by the near trees' + # own LOD2 meshes, cast just below + if render3d_st.sh_cascade >= SC_IMP_CAST_CASCADE { layer_draw_shadow(render3d_st, l, light_vp) } # Shadow LOD (the practice in every production engine: a caster uses a low mesh LOD, # the billboard only far away). The card alone is a side-view silhouette and a # crown of drooping needle cards is mostly slivers from the side, so the sun, which