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

光线追踪器射线方向计算错误问题排查求助

光线追踪射线方向计算错误导致渲染异常问题

问题详情

射线方向计算不正确,场景无法按预期投射射线,无法正常渲染。将射线方向以颜色显示时输出全黑帧,不符合预期效果:

  • 预期射线方向显示为红绿色混合(默认z方向为负)
  • NDC空间左上角应为纯黑色(对应取值范围-1,-1到0,0)

开发环境:Rust + wgpu + winit,光线追踪逻辑采用WGSL编写。已尝试修改射线生成算法/公式,无任何改善。

相关代码

struct Camera {
    position: vec3<f32>,
    forward: vec3<f32>,
    upward: vec3<f32>,
    rightward: vec3<f32>,
    vfov: f32,
    aspect_ratio: f32,
}

struct Ray {
    origin: vec3<f32>,
    direction: vec3<f32>,
}

fn camera_generate_ray(camera: Camera, u: f32, v: f32) -> Ray {
    // e (center)
    // u, v, w (horizontal/right, up, direction/forward)
    // r = x * u + aspect ratio * y * v + d * w

    // d = 1 / tan(alfa / 2)

    let x = 2.0 * u - 1.0;
    let y = 2.0 * v - 1.0;

    let d = 1.0 / tan(camera.vfov / 2.0);

    let ray_direction = x * camera.rightward + camera.aspect_ratio * y * camera.upward + d * camera.forward;
    
    let origin = camera.position;
    let direction = normalize(ray_direction);

    return Ray(origin, direction);
}

问题分析与修复方案

1. 视场角(vfov)单位错误

WGSL的tan()函数接收弧度值,如果传入的camera.vfov是角度值(比如90度),会导致d值计算完全错误,射线方向趋近于零向量,最终显示全黑。

修复:将vfov转换为弧度:

let vfov_rad = radians(camera.vfov);
let d = 1.0 / tan(vfov_rad / 2.0);

2. 屏幕坐标到NDC的y轴翻转

屏幕空间的v坐标通常从上到下递增,但NDC空间的y轴是从下到上递增。原代码中y = 2.0 * v - 1.0会导致左上角的y值为1(而非预期的-1),不符合NDC左上角为纯黑色的要求。

修复:翻转y轴计算:

let y = 1.0 - 2.0 * v;

3. 向量归一化问题

如果camera.rightward、camera.upward未做归一化处理,会导致射线方向的缩放比例异常,进而影响颜色显示结果。

修复:确保Camera的三个方向向量是正交归一化的(互相垂直且长度为1),或在计算时手动归一化:

let right = normalize(camera.rightward);
let up = normalize(camera.upward);
let ray_direction = x * right + (y * camera.aspect_ratio) * up + d * camera.forward;

4. 颜色映射范围错误

射线方向向量的分量范围是[-1,1],直接作为颜色输出时,负数会被截断为0,导致黑色。需要将向量映射到颜色的[0,1]范围。

修复:在输出颜色时做转换:

let color = (ray.direction + 1.0) / 2.0;

修正后的完整函数

struct Camera {
    position: vec3<f32>,
    forward: vec3<f32>,
    upward: vec3<f32>,
    rightward: vec3<f32>,
    vfov: f32,
    aspect_ratio: f32,
}

struct Ray {
    origin: vec3<f32>,
    direction: vec3<f32>,
}

fn camera_generate_ray(camera: Camera, u: f32, v: f32) -> Ray {
    let x = 2.0 * u - 1.0;
    // 翻转y轴适配NDC
    let y = 1.0 - 2.0 * v;

    // 转换vfov为弧度
    let vfov_rad = radians(camera.vfov);
    let d = 1.0 / tan(vfov_rad / 2.0);

    // 确保方向向量归一化
    let right = normalize(camera.rightward);
    let up = normalize(camera.upward);
    let ray_direction = x * right + (y * camera.aspect_ratio) * up + d * camera.forward;
    
    let origin = camera.position;
    let direction = normalize(ray_direction);

    return Ray(origin, direction);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 01:18:11