fix(Gargantua): setup_camera 改用 V3 值语义(消除旧版 &_g_cam 指针残留),移除定位用调试输出

This commit is contained in:
TermiNexus committed 2026-10-16 14:12:50 +08:00
1 parent d9b39e99a5
commit befed3904a
1 file changed
+115 -142
+115 -142
View File
@@ -1,14 +1,12 @@
import vpsdk.window as window
import vpsdk.process as process
import vpsdk.vpui as vpui
import vpsdk.stdlib as stdlib
import vpsdk.stdio as stdio
import string
import vipermath as vm
import viperlib
import math as vm
from stdint import *
import memhub
import t, c
define GW = 160
define GH = 90
@@ -25,122 +23,97 @@ define YIELD_ROWS = 4
define V3_POOL_SIZE = 8192
define V3_POOL_BYTES = V3_POOL_SIZE * 24 + 512
_v3_mem: t.CArray[uint8, V3_POOL_BYTES]
_v3_mem: [V3_POOL_BYTES]uint8
_v3_pool: memhub.MemPool*
_fb_mem: t.CArray[uint32, GW * GH]
_fb_mem: [GW * GH]uint32
class V3:
x: t.CFloat64T
y: t.CFloat64T
z: t.CFloat64T
x: double
y: double
z: double
def __new__() -> V3*:
return V3*(_v3_pool.alloc(24))
def __init__(self, x: t.CFloat64T, y: t.CFloat64T, z: t.CFloat64T):
def __init__(self, x: double, y: double, z: double):
self.x = x
self.y = y
self.z = z
def __add__(self, b: V3*) -> V3*:
def __add__(self, b: V3) -> V3:
return V3(self.x + b.x, self.y + b.y, self.z + b.z)
def __sub__(self, b: V3*) -> V3*:
def __sub__(self, b: V3) -> V3:
return V3(self.x - b.x, self.y - b.y, self.z - b.z)
def __mul__(self, s: t.CFloat64T) -> V3*:
def __mul__(self, s: double) -> V3:
return V3(self.x * s, self.y * s, self.z * s)
def __neg__(self) -> V3*:
def __neg__(self) -> V3:
return V3(-self.x, -self.y, -self.z)
def dot(self, b: V3*) -> t.CFloat64T:
def dot(self, b: V3) -> double:
return self.x * b.x + self.y * b.y + self.z * b.z
def cross(self, b: V3*) -> V3*:
def cross(self, b: V3) -> V3:
return V3(self.y * b.z - self.z * b.y, self.z * b.x - self.x * b.z, self.x * b.y - self.y * b.x)
def nrm(self) -> V3*:
l: t.CFloat64T = vm.sqrt(self.dot(self))
def nrm(self) -> V3:
l: double = vm.sqrt(self.dot(self))
if l > 1e-12:
return self * (1.0 / l)
return V3(0.0, 0.0, 0.0)
def lerp(self, b: V3*, t_val: t.CFloat64T) -> V3*:
def lerp(self, b: V3, t_val: double) -> V3:
return self * (1.0 - t_val) + b * t_val
_g_cam: t.CArray[t.CFloat64T, 3]
_g_fwd: t.CArray[t.CFloat64T, 3]
_g_right: t.CArray[t.CFloat64T, 3]
_g_up: t.CArray[t.CFloat64T, 3]
CAM: V3*
FWD: V3*
RIGHT: V3*
UP: V3*
CAM: V3
FWD: V3
RIGHT: V3
UP: V3
def v3_pool_reset():
_v3_pool.reset()
def clmp(x: t.CFloat64T, a: t.CFloat64T, b: t.CFloat64T) -> t.CFloat64T:
def clmp(x: double, a: double, b: double) -> double:
if x < a: return a
if x > b: return b
return x
def smoothstep(a: t.CFloat64T, b: t.CFloat64T, x: t.CFloat64T) -> t.CFloat64T:
t_val: t.CFloat64T = clmp((x - a) / (b - a), 0.0, 1.0)
def smoothstep(a: double, b: double, x: double) -> double:
t_val: double = clmp((x - a) / (b - a), 0.0, 1.0)
return t_val * t_val * (3.0 - 2.0 * t_val)
def setup_camera():
global CAM, FWD, RIGHT, UP
e: t.CFloat64T = CAM_ELEV * 3.14159265358979323846 / 180.0
CAM = &_g_cam
CAM.x = CAM_DIST * vm.cos(e)
CAM.y = CAM_DIST * vm.sin(e)
CAM.z = 0.0
tmp0: V3* = V3(0.0, 0.0, 0.0)
FWD = &_g_fwd
tmp1: V3* = tmp0 - CAM
n1: V3* = tmp1.nrm()
FWD.x = n1.x
FWD.y = n1.y
FWD.z = n1.z
tmp2: V3* = V3(0.0, 1.0, 0.0)
RIGHT = &_g_right
tmp3: V3* = FWD.cross(tmp2)
tmp4: V3* = tmp3.nrm()
RIGHT.x = tmp4.x
RIGHT.y = tmp4.y
RIGHT.z = tmp4.z
UP = &_g_up
tmp5: V3* = RIGHT.cross(FWD)
UP.x = tmp5.x
UP.y = tmp5.y
UP.z = tmp5.z
e: double = CAM_ELEV * 3.14159265358979323846 / 180.0
CAM = V3(CAM_DIST * vm.cos(e), CAM_DIST * vm.sin(e), 0.0)
tmp0: V3 = V3(0.0, 0.0, 0.0)
FWD = (tmp0 - CAM).nrm()
tmp2: V3 = V3(0.0, 1.0, 0.0)
RIGHT = FWD.cross(tmp2).nrm()
UP = RIGHT.cross(FWD)
def hash3(x: t.CFloat64T, y: t.CFloat64T, z: t.CFloat64T) -> t.CFloat64T:
n: t.CFloat64T = vm.sin(x * 127.1 + y * 311.7 + z * 74.7) * 43758.5453
def hash3(x: double, y: double, z: double) -> double:
n: double = vm.sin(x * 127.1 + y * 311.7 + z * 74.7) * 43758.5453
return n - vm.floor(n)
def stars(d: V3*) -> V3*:
col: V3* = V3(0.0, 0.0, 0.0)
def stars(d: V3) -> V3:
col: V3 = V3(0.0, 0.0, 0.0)
for i in range(3):
s: t.CFloat64T = 80.0 + t.CFloat64T(i) * 90.0
px: t.CFloat64T = d.x * s
py: t.CFloat64T = d.y * s
pz: t.CFloat64T = d.z * s
ix: t.CFloat64T = vm.floor(px)
iy: t.CFloat64T = vm.floor(py)
iz: t.CFloat64T = vm.floor(pz)
h: t.CFloat64T = hash3(ix, iy, iz)
s: double = 80.0 + double(i) * 90.0
px: double = d.x * s
py: double = d.y * s
pz: double = d.z * s
ix: double = vm.floor(px)
iy: double = vm.floor(py)
iz: double = vm.floor(pz)
h: double = hash3(ix, iy, iz)
if h > 0.991:
fx: t.CFloat64T = px - ix - 0.5
fy: t.CFloat64T = py - iy - 0.5
fz: t.CFloat64T = pz - iz - 0.5
d2: t.CFloat64T = fx * fx + fy * fy + fz * fz
br: t.CFloat64T = (h - 0.991) / 0.009 * vm.exp(-d2 * 9.0) * 1.4
tv: t.CFloat64T = hash3(iy, iz, ix)
tint: V3* = V3(0.0, 0.0, 0.0)
fx: double = px - ix - 0.5
fy: double = py - iy - 0.5
fz: double = pz - iz - 0.5
d2: double = fx * fx + fy * fy + fz * fz
br: double = (h - 0.991) / 0.009 * vm.exp(-d2 * 9.0) * 1.4
tv: double = hash3(iy, iz, ix)
tint: V3 = V3(0.0, 0.0, 0.0)
if tv < 0.3:
tint = V3(0.7, 0.8, 1.0)
elif tv > 0.8:
@@ -150,82 +123,82 @@ def stars(d: V3*) -> V3*:
col = col + tint * br
return col
def disk_shade(cp: V3*, rr: t.CFloat64T, gT: t.CFloat64T) -> V3*:
tt: t.CFloat64T = (rr - DISK_IN) / (DISK_OUT - DISK_IN)
edge: t.CFloat64T = smoothstep(0.0, 0.07, tt) * smoothstep(0.0, 0.18, 1.0 - tt)
ang: t.CFloat64T = vm.atan2(cp.z, cp.x)
w: t.CFloat64T = 1.0 / vm.pow(rr, 1.5)
ph: t.CFloat64T = ang - gT * 0.0011 * w * 9.0
n: t.CFloat64T = 0.5 + 0.5 * vm.sin(ph * 5.0 - rr * 1.6)
n2: t.CFloat64T = 0.5 + 0.5 * vm.sin(ph * 13.0 + rr * 0.8 + 1.7)
dens: t.CFloat64T = (0.35 + 0.65 * n) * (0.55 + 0.45 * n2)
bright: t.CFloat64T = (0.45 + 1.7 * vm.pow(1.0 - tt, 1.8)) * edge
vdir: V3* = V3(-cp.z, 0.0, cp.x).nrm()
beta: t.CFloat64T = 0.46 / vm.sqrt(rr)
to_cam: V3* = (CAM - cp).nrm()
mu: t.CFloat64T = vdir.dot(to_cam)
dop: t.CFloat64T = 1.0 / (1.0 - beta * mu)
beam: t.CFloat64T = vm.pow(dop, 3.0)
c1: V3* = V3(1.0, 0.92, 0.68)
c2: V3* = V3(1.0, 0.42, 0.13)
base: V3* = c1.lerp(c2, tt)
def disk_shade(cp: V3, rr: double, gT: double) -> V3:
tt: double = (rr - DISK_IN) / (DISK_OUT - DISK_IN)
edge: double = smoothstep(0.0, 0.07, tt) * smoothstep(0.0, 0.18, 1.0 - tt)
ang: double = vm.atan2(cp.z, cp.x)
w: double = 1.0 / vm.pow(rr, 1.5)
ph: double = ang - gT * 0.0011 * w * 9.0
n: double = 0.5 + 0.5 * vm.sin(ph * 5.0 - rr * 1.6)
n2: double = 0.5 + 0.5 * vm.sin(ph * 13.0 + rr * 0.8 + 1.7)
dens: double = (0.35 + 0.65 * n) * (0.55 + 0.45 * n2)
bright: double = (0.45 + 1.7 * vm.pow(1.0 - tt, 1.8)) * edge
vdir: V3 = V3(-cp.z, 0.0, cp.x).nrm()
beta: double = 0.46 / vm.sqrt(rr)
to_cam: V3 = (CAM - cp).nrm()
mu: double = vdir.dot(to_cam)
dop: double = 1.0 / (1.0 - beta * mu)
beam: double = vm.pow(dop, 3.0)
c1: V3 = V3(1.0, 0.92, 0.68)
c2: V3 = V3(1.0, 0.42, 0.13)
base: V3 = c1.lerp(c2, tt)
base.z += (dop - 1.0) * 0.35
base.x -= (dop - 1.0) * 0.05
inten: t.CFloat64T = bright * dens * beam * 1.25
inten: double = bright * dens * beam * 1.25
return base * inten
def trace(dir_v: V3*, gT: t.CFloat64T) -> V3*:
def trace(dir_v: V3, gT: double) -> V3:
v3_pool_reset()
pos: V3* = V3(CAM.x, CAM.y, CAM.z)
vel: V3* = V3(dir_v.x, dir_v.y, dir_v.z)
hvec: V3* = pos.cross(vel)
h2: t.CFloat64T = hvec.dot(hvec)
T: t.CFloat64T = 1.0
col: V3* = V3(0.0, 0.0, 0.0)
pos: V3 = V3(CAM.x, CAM.y, CAM.z)
vel: V3 = V3(dir_v.x, dir_v.y, dir_v.z)
hvec: V3 = pos.cross(vel)
h2: double = hvec.dot(hvec)
T: double = 1.0
col: V3 = V3(0.0, 0.0, 0.0)
for i in range(MAX_STEPS):
r2: t.CFloat64T = pos.dot(pos)
r: t.CFloat64T = vm.sqrt(r2)
r2: double = pos.dot(pos)
r: double = vm.sqrt(r2)
if r < 1.0:
break
if r > ESCAPE_R:
col = col + stars(vel.nrm()) * T
break
dt: t.CFloat64T = clmp(r * 0.08, 0.03, 2.2)
r5: t.CFloat64T = vm.pow(r2, 2.5)
coeff: t.CFloat64T = -1.5 * h2 / r5
dt: double = clmp(r * 0.08, 0.03, 2.2)
r5: double = vm.pow(r2, 2.5)
coeff: double = -1.5 * h2 / r5
k1v: V3* = pos * coeff
k2p_a: V3* = vel + k1v * (dt * 0.5)
k2v_a: V3* = pos + vel * (dt * 0.5)
r2_a: t.CFloat64T = k2v_a.dot(k2v_a)
coeff_a: t.CFloat64T = -1.5 * h2 / vm.pow(r2_a, 2.5)
k2v: V3* = k2v_a * coeff_a
k1v: V3 = pos * coeff
k2p_a: V3 = vel + k1v * (dt * 0.5)
k2v_a: V3 = pos + vel * (dt * 0.5)
r2_a: double = k2v_a.dot(k2v_a)
coeff_a: double = -1.5 * h2 / vm.pow(r2_a, 2.5)
k2v: V3 = k2v_a * coeff_a
k3p_a: V3* = vel + k2v * (dt * 0.5)
k3v_a: V3* = pos + k2p_a * (dt * 0.5)
r2_b: t.CFloat64T = k3v_a.dot(k3v_a)
coeff_b: t.CFloat64T = -1.5 * h2 / vm.pow(r2_b, 2.5)
k3v: V3* = k3v_a * coeff_b
k3p_a: V3 = vel + k2v * (dt * 0.5)
k3v_a: V3 = pos + k2p_a * (dt * 0.5)
r2_b: double = k3v_a.dot(k3v_a)
coeff_b: double = -1.5 * h2 / vm.pow(r2_b, 2.5)
k3v: V3 = k3v_a * coeff_b
k4p_a: V3* = vel + k3v * dt
k4v_a: V3* = pos + k3p_a * dt
r2_c: t.CFloat64T = k4v_a.dot(k4v_a)
coeff_c: t.CFloat64T = -1.5 * h2 / vm.pow(r2_c, 2.5)
k4v: V3* = k4v_a * coeff_c
k4p_a: V3 = vel + k3v * dt
k4v_a: V3 = pos + k3p_a * dt
r2_c: double = k4v_a.dot(k4v_a)
coeff_c: double = -1.5 * h2 / vm.pow(r2_c, 2.5)
k4v: V3 = k4v_a * coeff_c
npos: V3* = pos + (vel + k2p_a * 2.0 + k3p_a * 2.0 + k4p_a) * (dt / 6.0)
nvel: V3* = vel + (k1v + k2v * 2.0 + k3v * 2.0 + k4v) * (dt / 6.0)
npos: V3 = pos + (vel + k2p_a * 2.0 + k3p_a * 2.0 + k4p_a) * (dt / 6.0)
nvel: V3 = vel + (k1v + k2v * 2.0 + k3v * 2.0 + k4v) * (dt / 6.0)
if pos.y * npos.y < 0.0:
f: t.CFloat64T = pos.y / (pos.y - npos.y)
cp: V3* = pos.lerp(npos, f)
rr: t.CFloat64T = vm.sqrt(cp.x * cp.x + cp.z * cp.z)
f: double = pos.y / (pos.y - npos.y)
cp: V3 = pos.lerp(npos, f)
rr: double = vm.sqrt(cp.x * cp.x + cp.z * cp.z)
if rr > DISK_IN and rr < DISK_OUT:
emit: V3* = disk_shade(cp, rr, gT)
emit: V3 = disk_shade(cp, rr, gT)
col = col + emit * T
a: t.CFloat64T = clmp(smoothstep(0.0, 0.07, (rr - DISK_IN) / (DISK_OUT - DISK_IN)) * smoothstep(0.0, 0.18, 1.0 - (rr - DISK_IN) / (DISK_OUT - DISK_IN)) * 0.92, 0.0, 1.0)
a: double = clmp(smoothstep(0.0, 0.07, (rr - DISK_IN) / (DISK_OUT - DISK_IN)) * smoothstep(0.0, 0.18, 1.0 - (rr - DISK_IN) / (DISK_OUT - DISK_IN)) * 0.92, 0.0, 1.0)
T = T * (1.0 - a)
if T < 0.01:
break
@@ -234,13 +207,13 @@ def trace(dir_v: V3*, gT: t.CFloat64T) -> V3*:
vel = nvel
return col
def shade_pixel(px: int, py: int, gT: t.CFloat64T) -> uint32:
aspect: t.CFloat64T = GW_F / GH_F
sx: t.CFloat64T = (2.0 * (t.CFloat64T(px) + 0.5) / GW_F - 1.0) * aspect * FOVF
sy: t.CFloat64T = (1.0 - 2.0 * (t.CFloat64T(py) + 0.5) / GH_F) * FOVF
dir_v: V3* = (FWD + RIGHT * sx + UP * sy).nrm()
c: V3* = trace(dir_v, gT)
ex: t.CFloat64T = 1.15
def shade_pixel(px: int, py: int, gT: double) -> uint32:
aspect: double = GW_F / GH_F
sx: double = (2.0 * (double(px) + 0.5) / GW_F - 1.0) * aspect * FOVF
sy: double = (1.0 - 2.0 * (double(py) + 0.5) / GH_F) * FOVF
dir_v: V3 = (FWD + RIGHT * sx + UP * sy).nrm()
c: V3 = trace(dir_v, gT)
ex: double = 1.15
c = c * ex
c.x = c.x / (1.0 + c.x)
c.y = c.y / (1.0 + c.y)
@@ -253,8 +226,8 @@ def shade_pixel(px: int, py: int, gT: t.CFloat64T) -> uint32:
B: int = int(clmp(c.z, 0.0, 1.0) * 255.0)
return uint32((R << 16) | (G << 8) | B)
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
def _start() -> int | t.CExport:
@__attribute__(section(".text.startup"), aligned(16))
export def _start() -> int:
global _v3_pool
_v3_pool = memhub.MemPool(&_v3_mem, V3_POOL_BYTES)
setup_camera()
@@ -274,7 +247,7 @@ def _start() -> int | t.CExport:
root.geometry(100, 30, GW, GH + 32)
gT: t.CFloat64T = 0.0
gT: double = 0.0
rendered: int = 0
evt: window.InputEvent