You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

射线投射引擎中相机俯仰与多层级实现技术问询

射线投射引擎:上下视角实现与多高度/多层级方案

一、能否实现上下视角?完全可以

传统射线投射(如Wolfenstein 3D)限制垂直视角是出于简化设计,而非技术限制。实现上下视角主要有两种实用思路:

1. 基于俯仰角的投影偏移(主流方案)

给玩家添加pitch(俯仰角)变量,在渲染墙体时通过调整垂直位置和缩放模拟抬头/低头效果:

  • 核心逻辑:俯仰角会改变投影平面的垂直倾斜度,需将墙体上下边界按俯仰角偏移,同时结合距离修正缩放避免变形。
  • SDL2环境下的代码示例:
#include <math.h>
#include <SDL2/SDL.h>

// 全局参数
const int SCREEN_W = 640;
const int SCREEN_H = 480;
const float HORIZ_FOV = M_PI / 3; // 水平60度视场
const float TILE_SIZE = 64.0f;

// 玩家状态
typedef struct {
    float x, y;       // 水平位置
    float angle;      // 水平朝向
    float pitch;      // 俯仰角(弧度:正=抬头,负=低头)
    float height;     // 玩家眼睛高度
} Player;

// 计算单条扫描线的墙体渲染参数
void calculateWallRenderParams(Player* player, float wallDist, float wallTileHeight, int* outTop, int* outBottom) {
    // 基础墙体高度计算(无俯仰时)
    float wallHeight = (TILE_SIZE / wallDist) * (SCREEN_W / 2) / tan(HORIZ_FOV / 2);
    // 俯仰角带来的垂直偏移:结合距离修正,避免远处物体偏移过度
    float pitchOffset = tan(player->pitch) * (SCREEN_W / 2) / tan(HORIZ_FOV / 2) * wallDist;
    // 玩家高度带来的垂直偏移
    float heightOffset = (player->height - TILE_SIZE/2) / wallDist * (SCREEN_W / 2) / tan(HORIZ_FOV / 2);
    
    *outTop = (SCREEN_H / 2) - (wallHeight / 2) + pitchOffset + heightOffset;
    *outBottom = (SCREEN_H / 2) + (wallHeight / 2) + pitchOffset + heightOffset;
    
    // 裁剪到屏幕范围内
    *outTop = *outTop < 0 ? 0 : *outTop;
    *outBottom = *outBottom > SCREEN_H - 1 ? SCREEN_H - 1 : *outBottom;
}
  • 注意:需处理垂直视场边界,当俯仰角过大时裁剪超出屏幕的部分,避免渲染错误。

2. 垂直射线扫描(可行但少用)

和水平射线扫描逻辑一致,只是将射线扫描方向改为垂直:

  • 从玩家位置向上/向下发射射线,检测垂直方向的墙体(天花板、地板或上层墙体),计算距离后渲染对应垂直切片。
  • 缺点:计算量翻倍,需处理水平与垂直射线的渲染叠加,效率低于俯仰角方案。

二、多高度/多层级的实现方法

突破单一层级限制,需从数据结构、射线检测、渲染顺序三个核心层面修改:

1. 重构地图数据结构

将原2D地图升级为3D分层结构,每个格子存储多维度高度信息:

// 3D瓦片结构体
typedef struct {
    // 当前层数据
    int wall_height;    // 墙体高度(相对于当前层地板)
    int floor_y;        // 地板的全局高度(如0=底层,64=中层)
    int ceiling_y;      // 天花板的全局高度
    // 跨层级数据
    int has_upper_wall; // 是否存在上层墙体
    int upper_wall_h;   // 上层墙体高度
    int has_lower_wall; // 是否存在下层墙体
    int lower_wall_h;   // 下层墙体高度
    // 过渡标记
    int is_stair;       // 是否为楼梯
    int stair_step_h;   // 楼梯台阶高度
} Tile3D;

// 3D地图数组
Tile3D game_map[MAP_WIDTH][MAP_HEIGHT];

2. 扩展射线检测逻辑

每条水平扫描线不仅检测当前层墙体,还要根据玩家俯仰角检测上层/下层碰撞:

  • 抬头时,检测当前格子的上层墙体或上层地板;
  • 低头时,检测下层墙体或下层天花板;
  • 楼梯区域实时更新玩家height属性,模拟上下楼高度变化。

3. 分层渲染与垂直遮挡处理

按照从远到近、从高到低的顺序渲染,避免遮挡错误:

  1. 先渲染最远处的高层墙体/天花板;
  2. 再渲染当前层的墙体;
  3. 最后渲染近处的低层地板/楼梯;
  • 不同层级墙体的垂直位置需基于全局高度差换算:
    // 计算上层墙体的渲染边界
    float upperWallDist = ...; // 射线到上层墙体的距离
    float upperWallHeight = (game_map[x][y].upper_wall_h / upperWallDist) * (SCREEN_W/2)/tan(HORIZ_FOV/2);
    // 上层墙体底部 = 当前层天花板对应的屏幕Y坐标
    int upperWallBottom = (SCREEN_H/2) - ((game_map[x][y].ceiling_y - player->height)/upperWallDist) * (SCREEN_W/2)/tan(HORIZ_FOV/2);
    int upperWallTop = upperWallBottom - upperWallHeight;
    

4. 地板与天花板的多层渲染

除墙体之外,地板和天花板也需支持多层:

  • 玩家在中层时,底层天花板即为当前层地板,渲染时根据层级高度差计算纹理缩放与偏移;
  • 用类似墙体的投影逻辑,计算地板/天花板每个像素的纹理坐标,实现多层地面效果。

关键注意事项

  • 距离修正:所有垂直方向渲染计算需基于射线实际3D距离,而非水平距离,避免透视变形;
  • 性能优化:多层级会增加计算量,可通过视锥体裁剪(仅渲染玩家视角范围内的层级)降低开销;
  • 遮挡测试:重叠层级元素需通过深度检测(记录每个像素深度值)确保正确遮挡关系。

内容的提问来源于stack exchange,提问作者xingharvey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 03:27:49