【GAMES101】作业5——光线与三角形相交

作业内容:实现的内容为求光线与物体的交点,需要实现的函数如下

Renderer.cpp 中的 Render()需要为每个像素生成一条对应的光线,然后调用函数 castRay() 来得到颜色,最后将颜色存储在帧缓冲区的相应像素中
Triangle.hpp 中的 rayTriangleIntersect(): v0, v1, v2 是三角形的三个顶点,orig 是光线的起点,dir 是光线单位化的方向向量。tnear, u, v 是需要使用我们课上推导的 Moller-Trumbore 算法来更新的参数

main函数整体框架

复制代码
int main()
{
    //创建一个1280*960的场景
    Scene scene(1280, 960);

    //make_unique智能指针 创建一个中心为(-1,0,-12)半径为2的球 并返回该指针
    auto sph1 = std::make_unique<Sphere>(Vector3f(-1, 0, -12), 2);
    //设定Sphere类继承object类的材质类型:漫反射和高光
    sph1->materialType = DIFFUSE_AND_GLOSSY;
    //设定漫反射系数
    sph1->diffuseColor = Vector3f(0.6, 0.7, 0.8);

    //另一个球
    auto sph2 = std::make_unique<Sphere>(Vector3f(0.5, -0.5, -8), 1.5);
    //设定折射率
    sph2->ior = 1.5;
    //设定材质类型:反射与折射
    sph2->materialType = REFLECTION_AND_REFRACTION;

    //将物体加入scene 强制右值引用 
    scene.Add(std::move(sph1));
    scene.Add(std::move(sph2));

    //加入地板
    //地板的四个顶点
    Vector3f verts[4] = {{-5,-3,-6}, {5,-3,-6}, {5,-3,-16}, {-5,-3,-16}};
    //unsigned int
    uint32_t vertIndex[6] = {0, 1, 3, 1, 2, 3};
    Vector2f st[4] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
    auto mesh = std::make_unique<MeshTriangle>(verts, vertIndex, 2, st);
    //设置材质为漫反射与高光
    mesh->materialType = DIFFUSE_AND_GLOSSY;
    //加入地板
    scene.Add(std::move(mesh));

    //加入光源
    scene.Add(std::make_unique<Light>(Vector3f(-20, 70, 20), 0.5));
    scene.Add(std::make_unique<Light>(Vector3f(30, 50, -12), 0.5));    

    Renderer r;
    //渲染
    r.Render(scene);
    return 0;
}
复制代码

Render()实现

需要实现屏幕空间对于scene上的映射,分为两步

第一步:将栅格空间映射到[-1,1]^2范围

1. 先对i,j加上0.5获取像素点的坐标,且由于像素点的范围为(width-1,height-1),故除以其使得目前空间范围在x∈[0,1],y∈[0,1]上,即此时x=(i+0.5)/(width-1) y=(j+0.5)/(height-1)

2.将x∈[0,1],y∈[0,1]转换到x∈[-1,1],y∈[-1,1]上,对x,y乘以2减1即可,此时x=2*(i+0.5)/(width-1)-1 y=2*(j+0.5)/(height-1)-1

3.由于给的框架中y的初始坐标是在上方,需要对y取-1,不然图像是上下颠倒的,此时x=2*(i+0.5)/(width-1)-1 y=1-2*(j+0.5)/(height-1)

第二步:投影

从Vector3f dir = Vector3f(x, y, -1)可知,我们视角到成像的平面距离为1,利用forY(框架中为scale)与AspectRatio算出最终位置

x=tan(forY/2)*AspectRatio*[2*(i+0.5)/(width-1)-1]  y=[1-2*(j+0.5)/(height-1)]*tan(forY/2)

复制代码
  float scale = std::tan(deg2rad(scene.fov * 0.5f));//for=90
    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;
            float y;
            //查找栅格空间在屏幕像素点上的映射      
            x = scale * imageAspectRatio * (2 * ((i + 0.5f) / (float)scene.width - 1) - 1);
            y = scale * (2 * (j + 0.5f) / (float)height - 1) - 1);
            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);
    }
复制代码

rayTriangleIntersect()实现

P0,P1,P2为三角形顶点 O为射线顶点 D为射线方向,直接套公式就可以了

 

复制代码
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.0 && b1 > 0.0 && b2 > 0.0 && (1 - b1 - b2) > 0.0) {
        tnear = t;
        u = b1;
        v = b2;
        return true;
    }
  
    // TODO: Implement this function that tests whether the triangle
    // that's specified bt v0, v1 and v2 intersects with the ray (whose
    // origin is *orig* and direction is *dir*)
    // Also don't forget to update tnear, u and v.
    return false;
}
复制代码

结果图片:

 

 

posted @   一只雷史莱姆  阅读(281)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示