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

Rust实现《计算机图形学从零开始》光线追踪示例边缘球体变形求助

问题根源与修复方案

你的边缘球体扭曲是坐标系转换逻辑错误导致的非等比例拉伸,主要存在两处问题:

  • 视口坐标转换时,y轴偏移错误使用了画布宽度作为基准,且没有翻转y轴方向
  • 未保证视口宽高比和画布宽高比一致,导致画面被拉伸变形

修复步骤

1. 修正canvas_to_viewport转换逻辑

图像坐标系的原点在左上角,y轴向下增长,而视口坐标系原点在中心,y轴向上增长,需要先翻转y轴方向,再匹配宽高比进行缩放,修复后代码如下:

fn canvas_to_viewport(x: u32, y: u32, scene: &Scene) -> Point {
    // 计算像素相对于画布中心的偏移,翻转y轴方向
    let x_offset = x as f64 - (scene.width as f64 / 2.0);
    let y_offset = (scene.height as f64 / 2.0) - y as f64;

    // 定义视口宽度,自动计算对应高度保证和画布宽高比一致
    const VIEWPORT_WIDTH: f64 = 2.0;
    let viewport_height = VIEWPORT_WIDTH * (scene.height as f64 / scene.width as f64);

    // 转换为视口坐标
    Point {
        x: x_offset * (VIEWPORT_WIDTH / scene.width as f64),
        y: y_offset * (viewport_height / scene.height as f64),
        z: 10.0
    }
}

你可以调整VIEWPORT_WIDTH的数值来改变视场角,数值越小视场角越大。

2. 可选优化:补全t_max判断

你当前的trace_ray函数没有使用传入的_t_max参数,可能会导致超出可视范围的交点被错误计算,建议修改判断逻辑:

fn trace_ray(camera: Point, viewport: Point, t_min: f64, _t_max: f64, spheres: &Vec<Sphere>) -> Color {
    let mut closest_t = f64::INFINITY; // 改用无穷大作为初始值更合理
    let mut closest_sphere_color = Color (255,255,255);

    for sphere in spheres {
        let (t1, t2) = intersect_ray_sphere(camera, viewport, &sphere);
        if t1 > t_min && t1 < _t_max && t1 < closest_t {
            closest_t = t1;
            closest_sphere_color = sphere.color;
        };
        if t2 > t_min && t2 < _t_max && t2 < closest_t {
            closest_t = t2;
            closest_sphere_color = sphere.color;
        };
    }
    closest_sphere_color
}

原理说明

原代码中y轴偏移使用scene.width作为基准,当画布不是正方形时,y轴的坐标范围会和x轴不匹配,导致画面被非等比例拉伸,球体被拉成椭圆,越靠近画面边缘拉伸效果越明显。修正宽高比和y轴方向后即可恢复正常的透视效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 09:18:02