Raytracer : 高 FOV 失真

A.D*_*ibo 2 c++ geometry raytracing

我实际上正在实现一个 C++ 光线追踪器,但我正面临着一个关于光线追踪的经典问题。当放置高垂直 FOV 时,形状离边缘越近,变形越大。

我知道为什么会发生这种失真,但我不知道如何解决它(当然,减少 FOV 是一种选择,但我认为我的代码中有一些需要更改的地方)。我一直在浏览不同的计算论坛,但没有找到任何解决方法。

这是一个屏幕截图来说明我的问题。

球体边缘失真

我认为问题在于我投射光线的视平面实际上并不平坦,但我不知道如何解决这个问题。如果您有任何解决问题的技巧,我愿意接受建议。

我在一个面向右手的系统上。相机系统向量、方向向量和光向量被归一化。

如果你需要一些代码来检查某些东西,我会把它放在你问的部分的答案中。

射线生成代码:

        // PixelScreenX = (pixelx + 0.5) / imageWidth
        // PixelCameraX = (2 ? PixelScreenx ? 1) ?
        //      ImageAspectRatio ? tan(fov / 2)
        float x = (2 * (i + 0.5f) / (float)options.width - 1) *
                options.imageAspectRatio * options.scale;

        // PixelScreeny = (pixely + 0.5) / imageHeight
        // PixelCameraY = (1 ? 2 ? PixelScreeny) ? tan(fov / 2)
        float y = (1 - 2 * (j + 0.5f) / (float)options.height) * options.scale;

        Vec3f dir;
        options.cameraToWorld.multDirMatrix(Vec3f(x, y, -1), dir);
        dir.normalize();
        newColor = _renderer->castRay(options.orig, dir, objects, options);
Run Code Online (Sandbox Code Playgroud)

Nic*_*ler 6

你的投影没有任何问题。它生产的正是它应该生产的。

让我们考虑下图,看看所有数量是如何相互作用的:

视野

我们有相机位置、视野(作为一个角度)和图像平面。图像平面是您将 3D 场景投影到的平面。本质上,这代表您的屏幕。当您在屏幕上查看渲染时,您的眼睛就像相机。它会看到投影图像,如果它位于正确的位置,它将准确地看到实际 3D 场景在那里时会看到的内容(忽略景深等效果)。

显然,您不能修改屏幕(您可以更改窗口大小,但让我们坚持使用恒定大小的图像平面)。然后,相机的位置和视野之间存在直接关系。随着视野的增加,相机越来越靠近图像平面。像这样:

视野

因此,如果您在代码中增加视野,则需要将眼睛移近屏幕以获得正确的感知。您实际上可以尝试使用您的图像。将您的眼睛非常靠近屏幕(我说的是 3 厘米)。如果你现在看外面的球体,它们实际上又看起来像真正的球。

总之,视野应该与观察设置的几何形状大致匹配。对于给定的屏幕尺寸和平均观看距离,这可以很容易地计算出来。如果您的查看设置与您在代码中的假设不符,3D 感知就会崩溃。