光线追踪:为什么我的球体呈现为椭圆形?

ale*_*lex 2 c++ raytracing

我要编写一个raytracer,但是我似乎已经遇到了我的第一个大问题。出于任何原因,我的球体(自从我才开始-当光线被击中时,我只是将颜色涂成白色)被渲染为椭圆形。

此外,当我将球的中心远离 x = 0 and y = 0

这是交集和主循环代码:

double const Sphere::getIntersection(Ray const& ray) const
{
  double t;
  double A = 1;
  double B = 2*( ray.dir[0]*(ray.origin[0] - center_[0]) + ray.dir[1] * (ray.origin[1] - center_[1]) + ray.dir[2] * (ray.origin[2] - center_[2]));
  double C = pow(ray.origin[0]-center_[0], 2) + pow(ray.origin[1]-center_[1], 2) + pow(ray.origin[2] - center_[2], 2) - radius_pow2_;
  double discr = B*B - 4*C;

  if(discr > 0)
  {
    t = (-B - sqrt(discr))/2;
    if(t <= 0)
    {
      t = (-B + sqrt(discr))/2;
    }
  }
  else t = 0;

  return t;
}

Sphere blub = Sphere(math3d::point(300., 300., -500.), 200.);
Ray mu = Ray();
// for all pixels of window
for (std::size_t y = 0; y < window.height(); ++y) {
  for (std::size_t x = 0; x < window.width(); ++x) {
    Pixel p(x, y);
    mu = Ray(math3d::point(0., 0., 0.), math3d::vector(float(x), float(y), -300.));

    if (blub.getIntersection(mu) == 0. ) {
      p.color = Color(0.0, 0.0, 0.0);
    } else {
      p.color = Color(1., 1., 1.);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

球形,中心位于300,300,-500 中心为0,0,-500的球面

我还不明白的是为什么我的“椭圆形”没有集中在图片上。我有一个600 x 600像素的窗口,因此将球体的中心置于300 x 300时,afaik也应将球体也置于窗口的中心。


我的具体解决方案

(感谢托马斯将我推向正确的方向!)

正如托马斯正确说的那样,我的问题是两个截然不同的问题。考虑到将球体投影到中心,我按照他的建议做了,并更改了射线的起源和投影。

为了获得正确的视角,我没有意识到我已经必须从尺寸中计算焦距。

focal_length = sqrt(width^2 + height^2) / ( 2*tan( 45/2 ) )

结果:

中心为200,300的球体-focal_length

Tho*_*mas 5

对于线性透视投影,这是正常现象,并且由于摄像机的广角而加剧了这种情况;参见http://en.wikipedia.org/wiki/Perspective_projection_distortion。大多数游戏在水平方向上使用的角度约为90度,而两侧则为45度。但是,通过将光线沿x方向投射到600个像素上,而将z方向投射到300个像素上,则您的光线将变得更宽,精确到126度。


球体未居中的原因是您正在投射屏幕左下角的光线:

mu = Ray(math3d::point(0.,0.,0.),math3d::vector(float(x),float(y),-300.));
Run Code Online (Sandbox Code Playgroud)

那应该是这样的:

mu = Ray(math3d::point(width/2,height/2,0.),math3d::vector(float(x-width/2),float(y-height/2),-300.));
Run Code Online (Sandbox Code Playgroud)