From a88aecb99377dd3b7efaae890560f70ec99312ba Mon Sep 17 00:00:00 2001 From: Orkuncakilkaya Date: Sat, 19 Sep 2026 21:32:11 +0300 Subject: [PATCH] fix(render3d): a body hidden from the camera still stands in the sun Actor.cast_hidden separates drawn from casting. ac_visible rejected a hidden actor from the shadow pass too, so hiding the player's own body for first person took the player's shadow with it - and in a sunlit basin your own shadow is what tells you where you are. Co-Authored-By: Claude Opus 5 --- changes/a-hidden-body-still-stands-in-the-sun.md | 8 ++++++++ packages/ludic.render3d/actor.ludic | 9 ++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 changes/a-hidden-body-still-stands-in-the-sun.md diff --git a/changes/a-hidden-body-still-stands-in-the-sun.md b/changes/a-hidden-body-still-stands-in-the-sun.md new file mode 100644 index 00000000..5c02f700 --- /dev/null +++ b/changes/a-hidden-body-still-stands-in-the-sun.md @@ -0,0 +1,8 @@ +bump: patch +type: fix +`Actor.cast_hidden` separates being DRAWN from CASTING. `ac_visible` rejected any hidden +actor from the shadow pass as well as the scene pass, so a game that hides the player's +own body - first person, or a viewfinder held to the eye - lost that player's shadow +entirely. An actor hidden because the camera is inside its head is still standing in the +sun; set this on it and it keeps its shadow. Everything else still stops casting when it +is hidden. diff --git a/packages/ludic.render3d/actor.ludic b/packages/ludic.render3d/actor.ludic index b8b34d9d..ff11fd10 100644 --- a/packages/ludic.render3d/actor.ludic +++ b/packages/ludic.render3d/actor.ludic @@ -22,6 +22,12 @@ property Actor { rough: int = 0, mat: words, # the model matrix visible: bool = true, + # Drawn and CASTING are not the same question. An actor hidden because the camera is inside + # its head still stands in the sun, and a body that stops casting the moment you look out of + # its own eyes loses its shadow - which in a game played in a sunlit basin is the one thing + # that tells you where you are standing. Set this on anything hidden for a reason the sun + # does not share; everything else keeps stopping its shadow when it is hidden. + cast_hidden: bool = false, casts: bool = true, id: int = 0, cutout: bool = false, # alpha-tested (a flame's cards) @@ -141,7 +147,8 @@ function ac_bind_scene(ap: AcProg) -> void { fog_bind(p) } function ac_visible(a: Actor, shadow: bool) -> bool { - if not a.visible or a.model == null { return false } + if a.model == null { return false } + if not a.visible and not (shadow and a.cast_hidden) { return false } if shadow and not a.casts { return false } if a.cull != 0 { let dx = f_sub(a.x, cam_pos[0]); let dz = f_sub(a.z, cam_pos[2])