首页 > 其他分享 >GAMES101——作业5 光线与三角形相交(菲涅尔反射率)

GAMES101——作业5 光线与三角形相交(菲涅尔反射率)

时间:2024-08-17 16:58:20浏览次数:13  
标签:Vector3f float 反射率 菲涅尔 scene height cosi 坐标 GAMES101

任务 

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

实现

        Render

        在这里我们要做的就是将像素的位置变换成像素在空间的坐标,然后根据像素在空间的坐标和相机的坐标,得到该像素对应的光线,从而实现光线追踪。

       一个像素是通过下面的步骤得来的 ,那么假如知道一个像素的位置,我们可以倒着推出其在世界坐标的位置。

        ①将像素坐标转换到图像坐标。

        像素坐标左上角为(0,0),范围是x∈[0,1],y∈[0,1],而图像坐标原点则为正中心,先转化成NDC坐标,坐标范围是x∈[-1,1],y∈[-1,1],再通过宽高比计算出图像的坐标,x∈[-width/2,width/2],y∈[-height/2,height/2],因此我们先计算出像素中心点的图像坐标。

        设某一个像素点的坐标为(x0,y0),则

        x = (2 * (x0+0.5)/width - 1 )*imageAspectRatio

        y = (1 -2*(y0+0.5)/scene.height )

        括号内是点在NDC坐标的位置,x乘以宽高比就得到了图像坐标。

        ②将图像坐标转化为相机坐标

        得到了点在图像坐标的位置后,就可以将其转化为相机坐标了,这时候只需要知道该图像与相机的距离,就可以推算出其大小。因为图像离相机无论多远,都会规范化到[-1,1]的NDC坐标上,而第一步就是将其变为NDC坐标,再调整了一下宽高而已,并且经过上面的处理后这里的高总为[-1,1]。和相机的距离可以通过视角的大小的一半的正切值求出。

        tan(forY/2) =( height/2 ) / 距离,在这里也就是,1/距离。因此距离就是 1/tan(forY/2),结合上面的推到,可以得到最终的相机坐标系的x,y位置。  

            float scale = std::tan(deg2rad(scene.fov * 0.5f));      

                ...............

            x = (2 * ((float)i+0.5)/scene.width - 1 )*imageAspectRatio*scale;

            y = (1.0f -2*((float)j+0.5)/scene.height )*scale;    

        ③将相机坐标转化为世界坐标

        其实就是乘以视图矩阵的逆矩阵就好了,该作业框架里,直接将相机放在了世界坐标的原点,所以我们不需要进行此变换。

void Renderer::Render(const Scene& scene)
{
    std::vector<Vector3f> framebuffer(scene.width * scene.height);

    float scale = std::tan(deg2rad(scene.fov * 0.5f));
    float imageAspectRatio = scene.width / (float)scene.height;

    Vector3f eye_pos(0);
    int m = 0;
    for (int j = 0; j < scene.height; ++j)
    {
        for (int i = 0; i < scene.width; ++i)
        {
            float x;
            float y;

            x = (2 * ((float)i+0.5)/scene.width - 1 )*imageAspectRatio*scale;
            y = (1.0f -2*((float)j+0.5)/scene.height )*scale;     

            Vector3f dir = normalize(Vector3f(x, y, -1)); 
            framebuffer[m++] = castRay(eye_pos, dir, scene, 0);
        }
        UpdateProgress( j / (float)scene.height);
    }

    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);    
}
rayTriangleIntersect

这里直接根据下面的公式代入数据了,过程的推导可以查阅相关教程,计算出结果后,需要先判断t是否大于0,重心坐标的三个值是否都大于0,都大于0说明光线与三角形相交。

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);

    tnear = dotProduct(S2,E2)/dotProduct(S1,E1);
    u = dotProduct(S1,S)/dotProduct(S1,E1);
    v = dotProduct(S2,dir)/dotProduct(S1,E1);
    if(u>=0 && v >= 0 && (1-u-v)>=0 && tnear >= 0){
        return true;
    }

    return false;
}

结果

        

值得注意的点

在该作业中,对透明的球已经实现了菲涅尔反射的模型。观察渲染的图片里透明球的边缘,可以注意到比较亮,查询代码发现了菲涅尔系数的求解,因此这里提一下菲涅尔反射系数。

float fresnel(const Vector3f &I, const Vector3f &N, const float &ior)
{
    float cosi = clamp(-1, 1, dotProduct(I, N));    //确保光线合法
    float etai = 1, etat = ior;   //etai是入射介质的折射率,etat是出射物质的折射率
    //cosi>0,说明光是从物体内射向空气的,因此交换两个折射率
    if (cosi > 0) {  std::swap(etai, etat); }
    // 利用斯涅尔公式计算出射角的正弦值
    float sint = etai / etat * sqrtf(std::max(0.f, 1 - cosi * cosi));
    // 如果大于1,说明发生了全反射,因此反射系数为1。
    if (sint >= 1) {
        return 1;
    }
    else {
        float cost = sqrtf(std::max(0.f, 1 - sint * sint));
        cosi = fabsf(cosi);
        float Rs = ((etat * cosi) - (etai * cost)) / ((etat * cosi) + (etai * cost));
        float Rp = ((etai * cosi) - (etat * cost)) / ((etai * cosi) + (etat * cost));
        return (Rs * Rs + Rp * Rp) / 2;
    }
    // As a consequence of the conservation of energy, transmittance is given by:
    // kt = 1 - kr;
}

使用斯涅尔公式求解sint,其实这个高中就学过了。

菲涅尔反射系数的精确求解法

根据公式计算出s和p偏振光的反射系数,因为光源是非偏振光,因此将两个反射系数取平均就能得到最终的反射系数

菲涅尔系数的近似求解法

代码中的反射系数明显采取了精确的求法。在castRay的代码中,可以看到其用武之地

                Vector3f reflectionColor = castRay(reflectionRayOrig, reflectionDirection, scene, depth + 1);
                Vector3f refractionColor = castRay(refractionRayOrig, refractionDirection, scene, depth + 1);
                float kr = fresnel(dir, N, payload->hit_obj->ior);
                hitColor = reflectionColor * kr + refractionColor * (1 - kr);

这里是对应的反射与折射材质(REFLECTION_AND_REFRACTION),使用菲涅尔反射系数,可以真实地分配反射与折射光的强度。

标签:Vector3f,float,反射率,菲涅尔,scene,height,cosi,坐标,GAMES101
From: https://blog.csdn.net/weixin_50780569/article/details/141270509

相关文章

  • 雷达气象学(9)——反射率因子图分析(强对流篇)
    目录9.0对流性天气的分类9.1钩状回波9.2云顶上冲9.3悬垂状回波9.4弱回波区(WER)和有界弱回波区(BWER)9.5回波墙9.6V型缺口9.7旁瓣回波9.8下击暴流和阵风锋9.9三体散射回波(TBSS)9.10弓形回波9.0对流性天气的分类按照对流风暴的强度分类有两种:\[对流风暴\begin{cases}普......
  • 雷达气象学(8)——反射率因子图分析(非气象回波篇)
    目录8.0雷达回波的分类8.1地物回波8.2海浪回波8.3干扰回波(同波长干扰)8.4生物回波8.5超折射回波8.6旁瓣回波8.0雷达回波的分类雷达回波可分为气象回波和非气象回波:\[雷达回波\begin{cases} 气象回波\begin{cases} 层状云降水回波\\ 积状云降水回波(对流性降水回......
  • 雷达气象学(7)——反射率因子图分析(气象回波篇)
    从本篇文章开始介绍反射率因子图(即雷达回波强度图)的分析与识别方法。目录7.0雷达回波的分类7.1层状云降水回波7.2积状云降水回波(对流性降水回波)7.3层积混合降水回波7.4零度层亮带7.5晴空回波7.0雷达回波的分类雷达回波可分为气象回波和非气象回波:\[雷达回波\begin{cas......
  • 【7.PIE-Engine案例—— 加载Terra星全球500m地表反射率8天合成产品(MOD09A1 V61)数据
    加载Terra星全球500m地表反射率8天合成产品(MOD09A1V61)数据集原始路径欢迎大家查看本案例原始来源最终结果具体代码/***@File:MOD09A1*@Time:2020/7/21*@Author:piesat*@Version:1.0*@Contact:400-890-0662*@License......
  • 光的反射与反射率 Reflection of Light and Reflectance/Reflectivity
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录光的反射ReflectionofLight一、光的反射ReflectionofLight二、反射的分类1.漫反射diffusereflection朗伯反射(Lambertianreflectance)关联概念参考文献2.镜面反射mirrorreflection3.回......
  • 多焦点菲涅尔透镜
    多焦点菲涅尔透镜多焦点菲涅尔透镜一、设计原理1、边光原理边光原理是非成像光学中的一个基础原理,其内容可以表述为:来自光源边缘的光线经过若干有序正则光学曲面后依然落在投射光斑的边缘,而来自光源内部的光线也将落在光斑内部。这里的边缘包含两层含义:①二维曲面边缘;②光束立......
  • 用pyart绘制雷达图像并进行反射率修正
    目录前言反射率衰减修正前言这是一篇关于使用Python库Py-ART读取雷达数据文件、绘制雷达图并进行反射率修正的教程。这篇文章是我在2020年8月做大创项目的时候写的,由于中间修改过代码,并不确定代码100%正确。原地址:Py-ART简易中文教程随着gitee关闭了pages......
  • 【图像加密】基于线性正则变换与菲涅尔变换实现图像加密解密,MSE PSNR附Matlab代码
     ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,代码获取、论文复现及科研仿真合作可私信。......
  • Games101-3 triangle
    rasterize==drawingontothescreencolor=(red,green,blue)pixelindicesarefrom(0,0)to(width-1,height-1)pixel(x,y)iscenteredat(x+0.5,y+0.5)光栅化判断一个像素的中心点是否需要draw采样的方法--将函数离散化如果中心再三角形内。如何判断......
  • Games101-5 shadering
    shader对不同物体应用不同的材质定义:shading!=shadowdiffusereflection漫反射光照角度不同,则反射程度也不同于此同时物体离光源越远,反射程度越低高光项镜面反射和视线比较接近的时候使用半程向量计算高光注:半程向量比较好算,反射向量比较难算指数p:cos......