GAMES101作业(05)- 光线与三角形相交(Moller Trumbore算法)

作业来自官网

知识点整理

总览

在光线追踪中最重要的操作之一就是找到光线与物体的交点。一旦找到光线与物体的交点,就可以执行着色并返回像素颜色。在这次作业中,我们需要实现两个部分:光线的
生成和光线与三角的相交。本次代码框架的工作流程为:

  1. 从 main 函数开始。我们定义场景的参数,添加物体(球体或三角形)到场景
    中,并设置其材质,然后将光源添加到场景中。
  2. 调用 Render(scene) 函数。在遍历所有像素的循环里,生成对应的光线并将
    返回的颜色保存在帧缓冲区(framebuffer)中。在渲染过程结束后,帧缓冲
    区中的信息将被保存为图像。
  3. 在生成像素对应的光线后,我们调用 CastRay 函数,该函数调用 trace 来
    查询光线与场景中最近的对象的交点。
  4. 然后,我们在此交点执行着色。我们设置了三种不同的着色情况,并且已经
    为你提供了代码。

解答

Renderer.cpp

  1. 先把x和y坐标放缩到[-1,1]空间内。
  2. 然后在把它转换到lrbt空间中,所以要乘以scale。
  3. 然而scale是仰角算出来的,是上下的scale,所以水平想放缩的话,还要乘以分辨率。

注意计算xy的时候的精度丢失,别忘了*1.0,要不然可能会没有图像。

void Renderer::Render(const Scene& scene)
{
    
    
    std::vector<Vector3f> framebuffer(scene.width * scene.height);
    //先把x和y坐标放缩到[-1,1]空间内。
    //然后在把它转换到lrbt空间中,所以要乘以scale。
    //然而scale是仰角算出来的,是上下的scale,所以水平想放缩的话,还要乘以分辨率。
    float scale = std::tan(deg2rad(scene.fov * 0.5f));
    float imageAspectRatio = scene.width / (float)scene.height;

    // Use this variable as the eye position to start your rays.
    Vector3f eye_pos(0);
    int m = 0;
    for (int j = 0; j < scene.height; ++j)
    {
    
    
        for (int i = 0; i < scene.width; ++i)
        {
    
    
            // generate primary ray direction
            float x=(2.0*i/scene.width-1)*scale*imageAspectRatio;
            float y=(1-2.0*j/scene.height)*scale;
            //t(op)=n*tan(fovY/2)
            Vector3f dir = Vector3f(x, y, -1); // Don't forget to normalize this direction!
            dir=normalize(dir);
            framebuffer[m++] = castRay(eye_pos, dir, scene, 0);
        }
        UpdateProgress(j / (float)scene.height);
    }

    // save framebuffer to file
    FILE* fp = fopen("binary.ppm", "wb");
    (void)fprintf(fp, "P6\n%d %d\n255\n", scene.width, scene.height);
    for (auto i = 0; i < scene.height * scene.width; ++i) {
    
    
        static unsigned char color[3];
        color[0] = (char)(255 * clamp(0, 1, framebuffer[i].x));
        color[1] = (char)(255 * clamp(0, 1, framebuffer[i].y));
        color[2] = (char)(255 * clamp(0, 1, framebuffer[i].z));
        fwrite(color, 1, 3, fp);
    }
    fclose(fp);    
}

Triangle.hpp

使用Moller Trumbore算法,直接代入公式即可。

bool rayTriangleIntersect(const Vector3f& v0, const Vector3f& v1, const Vector3f& v2, const Vector3f& orig,
                          const Vector3f& dir, float& tnear, float& u, float& v)
{
    
    
    Vector3f E1=v1-v0;
    Vector3f E2=v2-v0;
    Vector3f S=orig-v0;
    Vector3f S1=crossProduct(dir,E2);
    Vector3f S2=crossProduct(S,E1);
    float t=dotProduct(S2,E2)/dotProduct(S1,E1);
    float b1=dotProduct(S1,S)/dotProduct(S1,E1);
    float b2=dotProduct(S2,dir)/dotProduct(S1,E1);
    if(t>0&&b1>0&&b2>0&&1-(b1+b2)>0){
    
    
        tnear=t;
        u=b1;
        v=b2;
        return true;
    }
    return false;
}

结果

结果是build目录下的ppm格式(没见过的格式)图片。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43399489/article/details/121575868