fix canopy issue

This commit is contained in:
DramaticShape
2026-08-08 12:27:19 -04:00
parent 0d245c4ccb
commit de54e4ea26
4 changed files with 85 additions and 5 deletions
+8 -1
View File
@@ -579,7 +579,14 @@ function BattleScene.render(state, arena, textures, token)
local cap = BattleScene.capture
if cap and cap.rig then
local okRig, c, p, fh = pcall(cap.rig, arena, groundY)
if okRig and c then cam, pitch, capFrameH = c, p or 0.15, fh end
-- The pitch is off STRAIGHT DOWN, like Voxel.angle and like the one
-- BattleCam.rig hands back -- the only thing downstream reads it is the
-- grass and flower pull below. A seat that declines to say stands in
-- for a near-LEVEL one rather than a top-down one, which is what every
-- staged seat actually is: the pull grows toward straight down, and a
-- default that guessed the wrong end of that would spend tens of world
-- pixels of bias on a camera standing two cells from its subject.
if okRig and c then cam, pitch, capFrameH = c, p or math.rad(80), fh end
end
if not cam then cam, pitch = BattleCam.rig(arena, groundY) end
cam.fov = BattleScene.letterboxFov(cam.fov, ph, s)
+25 -3
View File
@@ -332,9 +332,25 @@ local function captureRig(arena, groundY)
focus = { ex, groundY + 8, ez },
fov = SEAT_FOV,
}
-- the pitch VoxelScene.pull wants: how far below level the seat looks
local pitch = math.atan2(SEAT_UP - 8, back + l)
return cam, math.max(pitch, 0.05), SEAT_FRAME
-- The pitch VoxelScene.pull wants, and it is the angle off STRAIGHT DOWN
-- -- the convention Voxel.angle keeps and BattleCam.rig hands back
-- (atan2(horizontal run, height over the focus)). This used to answer the
-- DEPRESSION below level instead, which is that angle's complement, and
-- the two are as far apart as a camera can be: a seat looking nearly
-- level read as 0.06 radians, which is what the pull formula means by
-- LOOKING STRAIGHT DOWN, so the grass and the flowers were pulled 46
-- world pixels camera-ward instead of 6.
--
-- 46 is the whole distance this seat stands behind the player. The pull
-- is a bias along each vertex's own eye ray, harmless while it is short
-- of the range -- and past it, it drags geometry THROUGH the lens, where
-- the projection turns inside out and one tuft of grass at the eye smears
-- across the frame. That was the greenery hanging over the top of a
-- capture shot, on a route or a city street with grass rows either side.
-- (Voxel3D's vertex stage now clamps the pull to half the range as well,
-- so no camera this close can be smeared by a bias again.)
local pitch = math.atan2(back + l, math.max(1e-3, SEAT_UP - 8))
return cam, pitch, SEAT_FRAME
end
-- The ring in GB space, centred on the CREATURE. The pinned mark is the
@@ -1063,6 +1079,12 @@ CatchThrow.pickBall = function()
return owned[1]
end
-- The seat, named for the suite: it is a pure function of the arena and the
-- floor height, so the framing and -- the reason it is reachable at all --
-- the PITCH convention it hands BattleScene can both be asserted without a
-- battle, a canvas or a game.
CatchThrow._rig = captureRig
-- ------- session lifecycle
-- The capture table BattleScene consults: one shape, installed by the
+14 -1
View File
@@ -236,8 +236,21 @@ local SHADER = [[
// (An earlier CPU version translated along the central view axis,
// which preserved only the screen centre and made off-centre sprites
// and grass swim against the ground while the camera scrolled.)
//
// NEVER PAST THE EYE, which is the one way this can stop being a pure
// depth bias: a vertex nearer the lens than `pull` is carried through
// it and out the other side, where the projection turns inside out and
// the thing lands wherever the far side of the frame happens to be --
// a single tuft of grass smeared across the whole picture. Impossible
// on an orbit rung, where the eye is a screen height away and the pull
// is tens of pixels; ordinary for a staged fight's seat, which stands
// a couple of cells from what it is looking at, and for a first-person
// eye standing in the grass. Half the range is the ceiling: at that
// distance nothing is losing a depth fight the other half would win.
if (pull > 0.0) {
w.xyz += normalize(eye - w.xyz) * pull;
vec3 toEye = eye - w.xyz;
float range = length(toEye);
w.xyz += toEye / max(range, 1e-4) * min(pull, range * 0.5);
}
return vp * w;
}