光线追踪:由于相机移动引起的球体畸变

4
我正在从头开始构建一个光线追踪器。我的问题是:当我改变相机坐标时,球体会变成椭圆形。我不明白为什么会发生这种情况。
以下是一些图像,展示了这些伪影:
Sphere: 1 1 -1 1.0 (Center, radius)
Camera: 0 0 5 0 0 0 0 1 0 45.0 1.0 (eyepos, lookat, up, foy, aspect)

输入相机 0 0 5 0 0 0 0 1 0 45.0 1.0

但是当我更改相机坐标后,球体看起来会发生形变,如下所示:

Camera: -2 -2 2 0 0 0 0 1 0 45.0 1.0

这里输入图片描述

我不明白出了什么问题。如果有人能帮忙,那太好了!

我如下设置了我的imagePlane:

   //Computing u,v,w axes coordinates of Camera as follows:

 {       
        Vector a = Normalize(eye - lookat);  //Camera_eye - Camera_lookAt
        Vector b = up;    //Camera Up Vector 
        m_w = a;
        m_u = b.cross(m_w);
        m_u.normalize();
        m_v = m_w.cross(m_u);
}

接下来,我会根据相机位置(眼睛)计算每个像素的方向,具体方法如下:

//Then Computing direction as follows:

int half_w = m_width * 0.5;
    int half_h = m_height * 0.5;

double half_fy = fovy() * 0.5;
double angle = tan( ( M_PI * half_fy) / (double)180.0 );

for(int k=0; k<pixels.size(); k++){
    double j = pixels[k].x();       //width
    double i = pixels[k].y();       //height

    double XX = aspect() * angle * ( (j - half_w ) / (double)half_w );
    double YY  =           angle * ( (half_h - i ) / (double)half_h );

    Vector dir = (m_u * XX + m_v * YY) - m_w ;


 directions.push_back(dir);
}

之后:
 for each dir:

    Ray ray(eye, dir);
    int depth = 0;
    t_color += Trace(g_primitive, ray, depth);

1
你看过这个问题的答案吗? - jon hanson
谢谢Jon-Hanson。我对我的实现进行了很多测试,发现如果我的相机的所有三个xyz坐标都不为零,那么它会显示扭曲,但是如果任何一个xyz坐标为零,那么它就可以正常工作。 我认为这可能是透视失真引起的,但我想知道是否还有其他原因导致这个问题。 - sinner
谢谢提供链接。我检查了FOV参数的值,看起来没问题。我将其分别更改为30和15的值,但结果仍然相同。 - sinner
但是我仍然没有找到这个问题的正确答案。如果有人知道那就太好了! - sinner
1
尝试扩展您的程序以呈现球形数组(也称为网格)。例如,从左到右5个,从下到上5个。中间的球体将位于视图的中心。使球体的半径小于它们之间距离的一半。如果这不能帮助您,请发布图片。 - jon hanson
似乎我一切都做得没问题。球体扭曲的行为是由于透视造成的。我很快会回答这个问题,并添加更多例子来总结这个主题。非常感谢@jon-hanson的帮助! :) - sinner
2个回答

5

在玩了很多次并得到大家评论的帮助后,我成功地创建了我的光线追踪器。抱歉回复晚了,但我想用几句话结束这个主题。

因此,上述代码是完全正确的。基于我自己的假设(如上面的评论中所提到的),我已经决定设置相机参数。

我上面提到的问题是相机的正常行为(也如上面评论中所提到的)。

现在我已经得到了很好的结果,但编写光线追踪器时有一些要注意的事项:

  1. 始终确保在计算FOV和宽高比时进行弧度和角度(或反之亦然)的转换。我这样做:
     double angle = tan((M_PI * 0.5 * fovy) / 180.0);
     double y = angle;
     double x = aspect * angle;

2) 在计算三角形交点时,请确保正确实现叉积。

3) 在使用不同对象的交点时,请确保找到距离相机最近的交点。

下面是我得到的结果: enter image description here

上面是一个非常简单的模型(由UCBerkeley提供),我进行了光线追踪。


2
这是正确的行为。使用广角镜头的相机,将球体放在视野边缘并拍照。然后在照片应用程序中,在球体照片上绘制一个圆圈,你会发现它不是一个圆形投影。
由于你将宽高比设置为1.0,但你的图像不是正方形,因此这种效果会被放大。
需要修复一些问题:
- 方向向量应该是(to - from),而你的是(from - to),所以a指向后方。你需要在末尾添加m_w,而不是减去它。此外,这个修复将使你的m_u、m_v旋转180度,这将使你将(j - half_w)更改为(half_w - j)。 - 此外,将所有像素和所有方向放入列表中,不如只循环x、y值高效。

你好 Rage,感谢您的评论,但是: 1)“Vecter”是我自己定义的数学向量数据类型。 2)方向故意设置成这样,以便与OpenGL相机规格保持一致(即,在OpenGL中,Z轴向下为负),并且保持图像不翻转。 3)由于我认为我的图像(最终生成的结果)原点位于左上角,因此它的j-half_whalf_h-i - sinner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接