mirror of
https://github.com/DramaticShape/DramaticShapeVoxelMod.git
synced 2026-08-12 07:00:51 +02:00
fix canopy issue
This commit is contained in:
+8
-1
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -6709,6 +6709,44 @@ end)()
|
||||
mon = { level = 100 } }, 1) >= 1,
|
||||
"a trivial catch still pays at least one point")
|
||||
|
||||
-- ------- the capture seat speaks the pull's own language
|
||||
--
|
||||
-- The seat hands BattleScene a pitch, and the only thing downstream reads
|
||||
-- it is the camera-ward pull the grass and flowers are drawn with. That
|
||||
-- angle is measured off STRAIGHT DOWN -- Voxel.angle's convention, and
|
||||
-- BattleCam.rig's -- and this rig used to answer the DEPRESSION below
|
||||
-- level instead, which is its complement. A seat looking nearly level
|
||||
-- therefore read as "straight down", the end of the ladder where the pull
|
||||
-- is at its longest: 46 world pixels of bias handed to a camera standing
|
||||
-- 46 world pixels behind the player. The pull is a shove along each
|
||||
-- vertex's own eye ray, so at that range it carried the grass at the eye
|
||||
-- THROUGH the lens, and a tuft landed smeared across the top of the frame.
|
||||
do
|
||||
local CatchThrow = lib.require("CatchThrow")
|
||||
local BattleCam = lib.require("BattleCam")
|
||||
local VoxelScene = lib.require("VoxelScene")
|
||||
-- two mons two cells apart, the arena laid down unturned
|
||||
local arena = { player = { 100, 200 }, enemy = { 100, 168 },
|
||||
mid = { 100, 184 }, turn = 0 }
|
||||
local seat, pitch = CatchThrow._rig(arena, 0)
|
||||
T.check(pitch > math.rad(75),
|
||||
("the capture seat reads as NEARLY LEVEL (%.1f degrees off straight "
|
||||
.. "down), which is what it is"):format(math.deg(pitch)))
|
||||
local _, camPitch = BattleCam.rig(arena, 0, true)
|
||||
T.check(camPitch > math.rad(45) and pitch > math.rad(45),
|
||||
"in the same convention the battle's own rig hands back, so one pull "
|
||||
.. "formula can serve both seats")
|
||||
-- the invariant the bug broke: a bias along the eye ray must never
|
||||
-- reach the eye, or the vertex comes out behind the lens
|
||||
local dx, dz = seat.eye[1] - arena.player[1], seat.eye[3] - arena.player[2]
|
||||
local range = math.sqrt(dx * dx + dz * dz)
|
||||
T.check(VoxelScene.pull(math.max(pitch, 0.05)) < range * 0.5,
|
||||
("the grass pull (%.1f px) stays well inside the seat's own range to "
|
||||
.. "the player's cell (%.1f px) -- the tufts it is biasing are the "
|
||||
.. "ones standing right there")
|
||||
:format(VoxelScene.pull(math.max(pitch, 0.05)), range))
|
||||
end
|
||||
|
||||
-- and the same formula pays TRAINER knockouts under FULL, with the
|
||||
-- wild/trainer 1.5 that a catch never sees (a caught Pokemon is always
|
||||
-- wild, which is why the catch numbers above are untouched by it)
|
||||
|
||||
Reference in New Issue
Block a user