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

Omni-directional light in raytracing program gives wrong render c++

我正在尝试在我的 C++ 光线追踪程序中实现全向光源(a.k.a.,点光源)。我没有得到预期的结果,但我无法找出问题所在。也许有人可以看到我做错了什么。 我已经包含了负责光线追踪和光线的两个函数。 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为三角形的一个顶点到另外两个顶点的向量。令 d 为我们正在考虑的光线的(相反)方向。
  • 设 b 为从三角形顶点到相机的向量。
  • 找到 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 是从相机到三角形中相关点的向量,它的方向是 d。你的距离并不是真正的距离,但沿着一条射线它们是实际距离的 相同的倍数 ,这意味着这可以很好地确定你击中了哪个三角形,并且这就是您使用它们的全部目的。到目前为止,还不错。

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

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

这不是一个非常好的答案,但我设法使您的代码在没有奇怪的阴影不连续的情况下工作。问题发生在 ClosestIntersection 中,也许 Gareth 的回答涵盖了它。我现在需要停止查看此内容,但我想在离开前向您展示我拥有的内容,并且我需要 post 一些代码的答案。

// This starts with some vec3 helper functions which make things
// easier to look at
float Dot(const vec3& a, const vec3& b) {
    return a.x * b.x + a.y * b.y + a.z * b.z;
}
vec3 Cross(const vec3& a, const vec3& b) {
   return vec3(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x); 
}
float L2(const vec3& v) { return v.x*v.x + v.y*v.y + v.z*v.z; }
float Abs(const vec3& v) { return std::sqrt(L2(v)); }

// Here is the replacement version of ClosestIntersection
bool ClosestIntersection(vec3 cam, vec3 dir,
    const vector<Triangle>& triangles, Intersection& closestIntersection) 
{
    closestIntersection.distance = m;
    vec3 P0 = cam;
    vec3 P1 = cam + dir;
    for (size_t i = 0; i < triangles.size(); ++i) {
        vec3 v0 = triangles[i].v0;
        vec3 v1 = triangles[i].v1;
        vec3 v2 = triangles[i].v2;
        // Dan Sunday
        // http://geomalgorithms.com/a06-_intersect-2.html
        vec3 u = v1 - v0;
        vec3 v = v2 - v0;
        // w = P-v0, solve w = su +tv (s, t are parametric scalars)

        vec3 n = Cross(u, v);
        float ri = Dot(n, (v0 - P0)) / Dot(n, (P1 - P0));
        vec3 Pi = P0 + ri * (P1- P0);
        vec3 w = Pi - v0;

        // s = w . (n x v) / (u . (n x v))
        // t = w . (n x u) / (v . (n x u))

        float s = Dot(w, Cross(n, v)) / Dot(u, Cross(n, v));
        float t = Dot(w, Cross(n, u)) / Dot(v, Cross(n, u));

        if(s >= 0 && t >= 0 && s+t <= 1) {
            float dist = Abs(cam - Pi);
            if(dist < closestIntersection.distance) {
                closestIntersection.position      = Pi;
                closestIntersection.distance      = dist;
                closestIntersection.triangleIndex = int(i);
            }
        }
    }

    return closestIntersection.distance != m;
}

祝你好运。