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
相关产品推荐
相关产品推荐

