This repository was archived by the owner on Aug 14, 2026. It is now read-only.
forked from TeJota1337/DramaticShapeVoxelMod
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathWorldCurve.lua
More file actions
118 lines (105 loc) · 5.12 KB
/
Copy pathWorldCurve.lua
File metadata and controls
118 lines (105 loc) · 5.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
-- Voxel world mode: the curved world -- the Animal Crossing horizon.
--
-- Every vertex is pushed DOWN by the square of its horizontal distance from
-- the camera's focus:
--
-- y' = y - k * ((x - cx)^2 + (z - cz)^2)
--
-- and that is the whole effect. The ground you are standing on stays flat
-- (a quadratic is nearly zero near its vertex -- at half a tile out the drop
-- is a hundredth of a pixel), and the falloff accelerates with distance, so
-- the far edge of the map bends away and rolls over a near horizon. The
-- town reads as sitting on top of a small sphere.
--
-- WHAT IT IS NOT is a fisheye. A fisheye is a LENS -- a screen-space
-- warp -- and it bends straight lines everywhere, including right in front
-- of the player, and resamples every pixel to do it. On pixel art that
-- means a blurred, crawling image and a bent HUD. This bends the WORLD
-- instead: one line in the vertex shader, straight lines near the camera
-- stay straight, and not a single pixel is resampled, so the art stays as
-- crisp as it was.
--
-- Two properties are what keep it readable rather than nauseating, and both
-- fall out of displacing along Y only:
--
-- Things stay UPRIGHT. The drop depends on where a column stands, not on
-- how tall it is, so a building's whole column moves together -- the
-- world tips away, the buildings on it do not lean.
-- Shadows and the voxel grid RIDE ALONG. Both are worked out before the
-- bend -- the shadow map in flat world space, the wireframe in model
-- space -- so the bend carries them with it exactly as if it had been
-- painted on. Nothing has to be recomputed and the light frustum never
-- moves.
--
-- The strength is scaled by the VIEW HEIGHT, so a rung looks the same at
-- every zoom: `amount` is the drop, in view-heights, one view-height out.
-- the mod namespace (see main.lua): V.require loads a sibling module
local V = ...
local ModSetting = V.require("ModSetting")
local WorldCurve = {}
WorldCurve.KEY = "curve"
WorldCurve.LABEL = "V-CURVE"
-- The ladder, calibrated against the FAR EDGE of the visible ground -- a
-- little over two view-heights out at the low camera rungs. Since the drop
-- goes as the square, that edge falls `amount * 4` view-heights while the
-- ground within a screen of the player barely moves, which is the whole
-- shape of the effect: flat where you are playing, rolling where you are
-- only looking.
--
-- 1 is a hint of roll at the frame edges, 2 is the Animal Crossing read,
-- 3 is as far as it goes before the horizon closes inside the next block
-- of the town -- which stops being a look and starts being an occlusion
-- bug, since what has rolled away is still there to walk into. (The first
-- cut ran 0.18/0.35/0.60 and every rung of it was a marble.)
--
-- 4 AND 5 ARE PAST THAT LINE ON PURPOSE, and they are for the DIORAMA:
-- once the world is a model being looked at from outside rather than a
-- place being walked around in, "the horizon has closed over the next
-- block" stops being a bug and becomes the entire effect -- the town on
-- top of a little planet.
--
-- 5 is the HALF SPHERE, and it is not eyeballed. The drop is a parabola,
-- y = k d^2 with k = amount / vh, and the parabola that osculates a sphere
-- of radius R at its pole is y = d^2 / 2R -- so k = 1 / 2R, and an amount
-- of 1.0 gives R = vh / 2. The diorama's box is cut at exactly half a view
-- height (Diorama.BOX_FRAC), so at amount 1.0 the model's own rim is that
-- sphere's EQUATOR: the ground turns 45 degrees by the edge of the cut and
-- is falling vertically a view-height out. A dome, ending where the model
-- ends. 4 is the step between it and 3, geometrically rather than
-- arithmetically -- the effect goes as the square of distance, so even
-- steps in `amount` would bunch the whole ladder at the bottom.
WorldCurve.AMOUNTS = { 0, 0.05, 0.10, 0.18, 0.42, 1.00 }
WorldCurve.setting = ModSetting.new(WorldCurve.KEY, WorldCurve.LABEL,
{ 0, 1, 2, 3, 4, 5 },
{ "OFF", "1", "2", "3", "4", "5" })
function WorldCurve.level()
return WorldCurve.setting:get() or 0
end
function WorldCurve.active()
return WorldCurve.level() > 0
end
-- The quadratic's coefficient for a view `vh` world pixels tall: the drop
-- in world pixels per squared world pixel of distance. Zero when off, which
-- is also the shader's "skip it" signal.
function WorldCurve.k(vh)
local amount = WorldCurve.AMOUNTS[WorldCurve.level() + 1] or 0
if amount <= 0 or not vh or vh <= 0 then return 0 end
return amount / vh
end
-- The same displacement the vertex shader applies, for the callers that
-- have to agree with it on the CPU -- Voxel3D.project, which anchors the
-- overworld's 2D field FX (the "!" bubble, the fishing rod, the Fly bird)
-- to their ground points. Miss this and every one of them floats off its
-- own feet the moment the ground under it bends.
function WorldCurve.drop(k, cx, cy, wx, wz)
if k <= 0 then return 0 end
local dx, dz = wx - cx, wz - cy
return (dx * dx + dz * dz) * k
end
function WorldCurve.row()
return WorldCurve.setting:row()
end
function WorldCurve.sync(value)
WorldCurve.setting:sync(value)
end
return WorldCurve