c++ - 光线追踪程序中的全向光给出了错误的渲染 C++

标签 c++ visual-studio raytracing

我正在尝试在我的 C++ 光线追踪程序中实现全向光源(又名点光源)。我没有得到预期的结果,但我无法找出问题所在。也许有人可以看到我做错了什么。 我已经包含了负责光线追踪和光线的两个函数。 ClosestIntersection 函数查找最近的交点和三角形。稍后将在 DirectLight 函数中使用。 如果有任何帮助,我将不胜感激。

#include <iostream>
#include <glm/glm.hpp>
#include <SDL.h>
#include "SDLauxiliary.h"
#include "TestModel.h"
#include "math.h"

using namespace std;
using glm::vec3;
using glm::mat3;

// ----------------------------------------------------------------------------
// GLOBAL VARIABLES

const int SCREEN_WIDTH = 500;
const int SCREEN_HEIGHT = 500;
SDL_Surface* screen;
int t;
vector<Triangle> triangles;
float focalLength = 900;
vec3 cameraPos(0, 0, -4.5);

vec3 lightPos(0.5, 0.5, 0);
vec3 lightColor = 14.f * vec3(1,1,1);

// Translate camera
float translation = 0.1;        // use this to set translation increment

// Rotate camera
float yaw;
vec3 trueCameraPos;

const float PI = 3.1415927;

// ----------------------------------------------------------------------------
// CLASSES

class Intersection;

// ----------------------------------------------------------------------------
// FUNCTIONS
void Update();
void Draw();
bool ClosestIntersection(vec3 start, vec3 dir, const vector<Triangle>& triangles,
    Intersection& closestIntersection);
vec3 DirectLight(const Intersection& i);
// ----------------------------------------------------------------------------
// STRUCTURES
struct Intersection
{
    vec3 position;
    float distance;
    int triangleIndex;
};

float m = std::numeric_limits<float>::max();

int main(int argc, char* argv[])
{
    LoadTestModel(triangles);

    screen = InitializeSDL(SCREEN_WIDTH, SCREEN_HEIGHT);
    t = SDL_GetTicks(); // Set start value for timer.

    while (NoQuitMessageSDL())
    {
        Update();
        Draw();
    }

    SDL_SaveBMP(screen, "screenshot.bmp");
    return 0;
}

void Update()
{
    // Compute frame time:
    int t2 = SDL_GetTicks();
    float dt = float(t2 - t);
    t = t2;
    cout << "Render time: " << dt << " ms." << endl;
    }
}

void Draw()
{
    if (SDL_MUSTLOCK(screen))
        SDL_LockSurface(screen);

    for (int y = 0; y<SCREEN_HEIGHT; ++y)
    {
for (int x = 0; x < SCREEN_WIDTH; ++x)
{
    vec3 start = cameraPos;
    vec3 dir(x - SCREEN_WIDTH / 2, y - SCREEN_HEIGHT / 2, focalLength);
    Intersection intersection;
    if (ClosestIntersection(start, dir, triangles, intersection))
    {
        //vec3 theColor = triangles[intersection.triangleIndex].color;
        vec3 theColor = DirectLight(intersection);
        PutPixelSDL(screen, x, y, theColor);
    }
    else
    {
        vec3 color(0, 0, 0);
        PutPixelSDL(screen, x, y, color);
    }
}
    }

    if (SDL_MUSTLOCK(screen))
        SDL_UnlockSurface(screen);

    SDL_UpdateRect(screen, 0, 0, 0, 0);
}

bool ClosestIntersection(vec3 s, vec3 d,
    const vector<Triangle>& triangles, Intersection& closestIntersection)
{
    closestIntersection.distance = m;
    for (size_t i = 0; i < triangles.size(); i++)
    {
        vec3 v0 = triangles[i].v0;
        vec3 v1 = triangles[i].v1;
        vec3 v2 = triangles[i].v2;
        vec3 u = v1 - v0;
        vec3 v = v2 - v0;
        vec3 b = s - v0;
        vec3 x;

        // Determinant of A = [-d u v]
        float det = -d.x * ((u.y * v.z) - (v.y * u.z)) -
            u.x * ((-d.y * v.z) - (v.y * -d.z)) +
            v.x * ((-d.y * u.z) - (u.y * -d.z));

        // Cramer'r Rule for t = x.x
        x.x = (b.x * ((u.y * v.z) - (v.y * u.z)) -
            u.x * ((b.y * v.z) - (v.y * b.z)) +
            v.x * ((b.y * u.z) - (u.y * b.z))) / det;

        if (x.x >= 0)
        {
            // Cramer'r Rule for u = x.y
            x.y = (-d.x * ((b.y * v.z) - (v.y * b.z)) -
                b.x * ((-d.y * v.z) - (v.y * -d.z)) +
                v.x * ((-d.y * b.z) - (b.y * -d.z))) / det;

            // Cramer'r Rule for v = x.z
            x.z = (-d.x * ((u.y * b.z) - (b.y * u.z)) -
                u.x * ((-d.y * b.z) - (b.y * -d.z)) +
                b.x * ((-d.y * u.z) - (u.y * -d.z))) / det;

            if (x.y >= 0 && x.z >= 0 && x.y + x.z <= 1 && x.x < closestIntersection.distance)
            {
                closestIntersection.position = x;
                closestIntersection.distance = x.x;
                closestIntersection.triangleIndex = i;
            }
        }

    }
    //end of for loop

    if (closestIntersection.distance != m)
    {
        return true;
    }
    else
    {
        return false;
    }

}

vec3 DirectLight(const Intersection& i)
{
    vec3 n = triangles[i.triangleIndex].normal;
    vec3 r = lightPos - i.position;
    float R2 = r.x * r.x + r.y * r.y + r.z * r.z;
    vec3 D = (lightColor * fmaxf((glm::dot(glm::normalize(r), n)), 0)) / (4 * PI * R2);
    return D;
}

最佳答案

如果我正确理解 ClosestIntersection 中的代码,下面是它对每个三角形所做的事情:

  • 令 u,v 为从三角形的一个顶点到另外两个顶点的 vector 。设 d 是我们正在考虑的光线的(相反)方向。
  • 设 b 为从三角形顶点到相机的 vector 。
  • 找到 p,q,r 使得 b = pd+qu+rv(p,q,r 是您的代码调用的 x.x、x.y、x.z)。
  • 现在如果 p>0, q>=0, r>=0, q+r<=1 则射线与三角形相交并且到交点的距离为 p。

所以,关于 q,r 的条件是有意义的;这个想法是 b-qu-rv 是从相机到三角形中相关点的 vector ,它的方向是 d。你的距离并不是真正的距离,但沿着一条射线它们是实际距离的相同倍数,这意味着这可以很好地确定你击中了哪个三角形,这就是你的全部使用它们。到目前为止,还不错。

但是你说 closestIntersection.position = x; 肯定是错的,因为这个 x 与你的相机位置不在同一个坐标系中,三角形顶点等。在这个有趣的“d 的多少,u 的多少,v 的多少”坐标系中,从一个三角形到下一个三角形甚至都不相同。 (我认为,这就是为什么即使在一个面内,三角形边界也会出现不连续的原因。)

尝试将其设置为 v0+x.y*(v1-v0)+x.z*(v2-v0)(我认为这是正确的;它意味着光线穿过三角形的实际点,在相同的坐标中和你所有的其他观点一样),看看它做了什么。

关于c++ - 光线追踪程序中的全向光给出了错误的渲染 C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36708800/

相关文章:

visual-studio - DNX 错误 : Unable to start the process

c++ - 单击窗口 x 轴的末端时,鼠标单击会导致 OpenGL 中的光线创建不正确吗?

math - 如何计算圆柱表面的法线?

c++ - 分配大小无效 - 对象变量

c++ - 访问冲突读取位置 0xfeef002A

c++ - C++ 命名空间后的类名

visual-studio - Visual Studio 项目与解决方案

c++ - 从 cpu 代码到 gpu 着色器获取漫反射 Material

c++ - 如何测量 CMake 中每个对象的编译时间?

c++ - 模板类中嵌套类的问题