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

同一场景中光线投射与光栅化的世界坐标不匹配问题

光线投射与光栅化立方体渲染不匹配问题

我正在渲染两个边长为1、以原点为中心(最小坐标[-.5, -.5, -.5],最大坐标[.5, .5, .5])的立方体:一个采用光栅化方式(通过顶点着色器设置顶点),另一个采用光线投射方式(每个像素发射一条射线穿过立方体)。问题在于,经过投影、视图、模型矩阵及其逆矩阵变换后,二者的世界空间坐标无法匹配。

光栅化立方体实现

光栅化立方体通过顶点着色器传入顶点坐标,用标准方式设置gl_Position:

gl_Position = proj * view * model * vec4(in_position, 1);

光线投射立方体实现

光线投射立方体使用逆投影矩阵和逆视图矩阵,模型矩阵设为单位矩阵。

射线生成逻辑

  • 射线起点计算:
vec4 ray_origin = inverse(view) * vec4(0,0,0,1);
  • 射线方向计算函数(注:原代码中view_coords为笔误,已修正为eye):
uniform vec2 resolution; // 视口的宽高(像素)

vec3 ray_dir(){
    // 归一化设备坐标(透视除法后的状态)
    vec2 ndc = (gl_FragCoord.xy / resolution) * 2.0 - 1.0;

    // 从归一化屏幕空间计算裁剪空间坐标
    vec4 clip = vec4( ndc.xy, -1, 0);

    // 通过逆投影矩阵转换到眼空间
    vec4 eye = inverse(proj) * clip;
    eye = vec4(eye.xy, -1, 0);

    // 通过逆视图矩阵转换到世界空间
    vec4 world = inverse(view) * eye;

    return normalize(world.xyz);
}

射线-包围盒相交检测

uniform vec3 start; // 相机的世界空间位置
vec2 cube_intersection() {
    vec3 dir = ray_dir();
    // 无相交时vec.x > vec.y
    float size = 0.5;
    vec3 t_min = (-vec3(size) - start) / dir;
    vec3 t_max = (+vec3(size) - start) / dir;
    vec3 t1 = min(t_min, t_max);
    vec3 t2 = max(t_min, t_max);    
    float t_near = max(max(t1.x, t1.y), t1.z);
    float t_far = min(min(t2.x, t2.y), t2.z);
    return vec2(max(t_near, 0), t_far);
}

其中start是存储相机世界空间位置的uniform变量,会丢弃所有t_near > t_far的片段。

问题现象

视图矩阵包含常规旋转和平移,投影矩阵是标准透视矩阵,理论上两个立方体在世界空间中应完全一致,但实际渲染结果存在偏差:

  • 相机距离原点1个单位时:光线投射的立方体明显比光栅化的大
  • 相机距离原点0.5个单位时:光线投射的立方体大小是预期的2倍
  • 相机距离原点10个单位时:光线投射的立方体大小接近正确值
  • 相机距离原点100个单位时:二者几乎完全匹配

注:每次测试都会调整投影矩阵的FOV以适配不同距离

可见规律:相机离原点越近,光线投射的立方体越大;离原点越远,立方体越小,渐近趋近于正确大小。

尝试的临时修复及遗留问题

若将相机位置start乘以(1.0 / length(start) + 1.0),立方体的大小会变得正确(比如距离1个单位时渲染匹配):

uniform vec3 start; // 相机的世界空间位置
vec2 cube_intersection() {
    vec3 dir = ray_dir();
    // 无相交时vec.x > vec.y
    float size = 0.5;
    vec3 t_min = (-vec3(size) - start*(1.0 / length(start) + 1.0)) / dir; // 修改处
    vec3 t_max = (+vec3(size) - start*(1.0 / length(start) + 1.0)) / dir; // 修改处
    vec3 t1 = min(t_min, t_max);
    vec3 t2 = max(t_min, t_max);    
    float t_near = max(max(t1.x, t1.y), t1.z);
    float t_far = min(min(t2.x, t2.y), t2.z);
    return vec2(max(t_near, 0), t_far);
}

但当相机朝向偏离原点时(比如相机位于(sqrt(3), sqrt(3), sqrt(3)),看向(0,0,0.5)),光线投射的立方体偏移量是光栅化立方体的2倍,仍不匹配。

我怀疑问题与光栅化过程中片段着色器之后的w分量除法有关,但不确定具体原因及光线投射中的修复方法。光线投射与光栅化在世界空间中应该可以共存,求解决方案!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 18:57:04