伪3D环境下Sprite的屏幕定位修正问题
PICO-8 Mode-7伪3D Sprite渲染修正方案
核心问题分析
原代码存在3处关键错误:
- 角度计算笔误:
theta = atan2(flag.x - cam.x, sprite.y - sprite.y)中,flag.x应为sprite.x,sprite.y - sprite.y是无效计算,应为sprite.y - cam.y;且PICO-8的atan2(y, x)参数顺序是纵轴差在前,横轴差在后,需匹配坐标系逻辑。 - 距离计算错误:
spr_dist误用了sprite.z和cam.far作为参数,Mode-7伪3D中应计算相机与Sprite的水平平面距离,而非混合高度与远平面参数。 - 深度归一化逻辑错误:
norm_depth引入了不必要的cos(cam_angle)因子,导致侧面Sprite的深度被错误压缩;且深度公式不符合"近距归0、远距归1"的预期。
修正后的代码
-- 修正角度计算:使用Sprite与相机的坐标差,匹配PICO-8 atan2(y, x)参数顺序 theta = atan2(sprite.y - cam.y, sprite.x - cam.x) -- 计算相对相机角度:0-1对应0-2π,修正偏移确保正前方为0 cam_angle = (theta - cam.a) % 1 -- 计算相机到Sprite的水平平面距离(2D距离) spr_dist = dist(sprite.x, sprite.y, cam.x, cam.y) -- 避免除以0(Sprite在相机位置时) if spr_dist < 0.1 then spr_dist = 0.1 end -- 修正深度归一化:近距(spr_dist=cam.near)时归0,远距趋近无穷时归1 -- 若未定义cam.near,可设为相机最小可视距离(如1) norm_depth = 1 - (cam.near / spr_dist) -- 修正X坐标计算:使用tan函数实现透视偏移,匹配视场角 -- cam.fovhalf为半视场角(0-1对应0-π,建议设为0.25即90度全视场) fov_rad = cam.fovhalf * 2 * PI draw_x = 64 + 64 * (tan(cam_angle * 2 * PI) / tan(fov_rad / 2)) -- Y坐标保持原逻辑,因符合"近距在底部、远距在水平线"的预期 draw_y = 128 - 64 * norm_depth
关键修正说明
- 角度计算:确保
atan2参数为(y差, x差),PICO-8坐标系中y轴向下为正,该参数顺序能正确计算方位角。 - 距离计算:仅保留水平平面的x/y坐标差计算距离,符合Mode-7基于2D地面的伪3D逻辑。
- 深度归一化:使用
1 - (cam.near / spr_dist)实现预期的深度映射:- 当
spr_dist = cam.near(近距),norm_depth = 0→ 屏幕底部(y=128) - 当
spr_dist → ∞(远距),norm_depth → 1→ 屏幕水平线(y=64)
- 当
- X坐标透视:替换
sin为tan函数,符合透视投影的水平偏移公式,确保Sprite在视锥体中正确分布。
额外优化建议
- 若Sprite有高度(
sprite.z),可在draw_y中加入高度补偿:draw_y = 128 - 64 * (norm_depth + sprite.z / spr_dist),模拟高度带来的视觉提升。 - 加入视锥体剔除:当
abs(cam_angle) > cam.fovhalf时,不渲染Sprite,提升性能。
内容的提问来源于stack exchange,提问作者Simon Weiler
相关产品推荐
相关产品推荐

