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

news2024/9/19 19:53:21

任务 

        需要修改的函数是:
         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),使用菲涅尔反射系数,可以真实地分配反射与折射光的强度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2055183.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

测试八股文(自总版)(更新中...)

测试八股文---从网上各处搜罗滴 软件测试的一些基础知识1. 什么是软件&#xff1f;1. 什么是软件测试?2. 软件测试分类?3. 软件生命周期的各阶段4. 几个模型---瀑布模型 , V模型 , 敏捷开发模型5. 软件测试基本流程&#xff08;1&#xff09;需求分析测试需求分析具体怎么来进…

力扣爆刷第174天之TOP200五连刷136=140(最小k数、字典序、跳跃游戏)

力扣爆刷第174天之TOP200五连刷136140&#xff08;最小k数、字典序、跳跃游戏&#xff09; 文章目录 力扣爆刷第174天之TOP200五连刷136140&#xff08;最小k数、字典序、跳跃游戏&#xff09;一、LCR 159. 库存管理 III二、450. 删除二叉搜索树中的节点三、440. 字典序的第K小…

【C语言】进程和线程详解

目录 C语言进程和线程详解1. 进程和线程的对比2. 进程的基本概念2.1 进程的定义2.2 进程的特点2.3 进程的生命周期 3. 进程管理3.1 进程创建3.2 进程间通信&#xff08;IPC&#xff09;3.2.1 管道&#xff08;Pipe&#xff09; 4. 线程的基本概念4.1 线程的定义4.2 线程的特点 …

Halcon灰度图像的形态学运算

Halcon灰度图像的形态学运算 本文介绍的算子的输入类型是灰度的Image图像。 1. 灰度图像与区域的区别 基于区域的形态学运算与基于灰度图像的形态学运算的根本区别在于&#xff0c;二者输入的对象不同。前者输入的是一些区域&#xff0c;并且这些区域是经过闽值处理的二值图…

微信小程序在线客服源码系统全端通吃 带完整的安装代码包以及搭建部署教程

系统概述 “微信小程序在线客服源码系统全端通吃”是一款集智能客服、人工客服、消息管理、数据分析等功能于一体的综合性解决方案。该系统基于微信小程序平台开发&#xff0c;支持全端接入&#xff08;包括Web、App、小程序等&#xff09;&#xff0c;实现多渠道客户服务的无…

英国海外媒体通稿宣发:顶级媒体宣发

1.伦敦日报londonjournal 作为英国首都的权威日报&#xff0c;伦敦日报一直是英国新闻界的佼佼者。它详尽报道伦敦及英国各地的政治、经济、社会、文化、体育等各方面的新闻&#xff0c;深受读者喜爱。 2.英国先驱报ukherald 英国先驱报是一份全国性日报&#xff0c;以深度分…

源码构建LAMP

目录 一、安装Apache 二、安装Mysql 三、安装PHP 四、安装论坛 一、安装Apache 1.cd 到opt目录下面&#xff0c;将压缩包拉进Xhell 2.解压缩apr和httpd压缩包 tar xf apr-1.6.2.tar.gz tar xf apr-util-1.6.0.tar.gz tar xf httpd-2.4.29.tar.bz2 3.将apr-1.6.2 移动到ht…

playbook(剧本)基本应用、playbook常见语法、playbook和ansible操作的编排

playbook(剧本): 是ansible⽤于配置,部署,和管理被控节点的剧本。⽤ 于ansible操作的编排。 使⽤的格式为yaml格式 一、YMAL格式 以.yaml或.yml结尾 ⽂件的第⼀⾏以 "---"开始&#xff0c;表明YMAL⽂件的开始(可选的) 以#号开头为注释 列表中的所有成员都开始于…

开放式耳机原理是什么?它通过不入耳的方式带来动感音乐

开放式耳机的原理主要分为两种类型&#xff1a;气传导和骨传导。 气传导耳机&#xff1a;这种耳机的工作原理依赖于空气作为声音传播的介质。具体来说&#xff0c;音频设备通过耳机线将电信号传递到耳机&#xff0c;耳机内部的驱动单元&#xff08;通常是动圈式或平衡电枢式&am…

未开启语音助手时,远程控制功能助你快速在家找回手机!

完成一整天的大扫除之后&#xff0c;顺手就想摸出手机刷一下短视频&#xff0c;但摸不到。干了一天活&#xff0c;手机放哪里都忘了&#xff0c;于是不得不在几个房间之间寻找。 但找过手机的都知道&#xff0c;越找越是找不到。糟糕的是前几天我嫌麻烦&#xff0c;把语音助手…

<数据集>铝型材缺陷识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;1885张 标注数量(xml文件个数)&#xff1a;1885 标注数量(txt文件个数)&#xff1a;1885 标注类别数&#xff1a;10 标注类别名称&#xff1a;[budaodian, tufen, loudi, qikeng, pengshang, tucengkailie, zangdi…

光伏模拟器的应用

太阳能光伏 (PV) 模拟器是一种可编程电源&#xff0c;用于模拟太阳能电池板。模拟器具有快速瞬态响应&#xff0c;可响应负载条件的变化并保持电压-电流特性的输出。 用户可以根据系统规格定义太阳能电池板配置&#xff0c;并通过选择环境条件来选择适当的环境条件进行模拟。用…

通风采光排烟天窗现行七本图集概览

在建筑设计与施工中&#xff0c;通风采光排烟天窗作为优化室内环境的重要设备&#xff0c;选择合适的型号及合理应用至关重要。当前市场上存在着多本标准化、规范化的通风采光排烟天窗图集&#xff0c;为设计师、工程师及施工单位、通风采光排烟天窗生产厂家提供丰富的参考资源…

如何有效找到目标客户群体?

在激烈的市场竞争中&#xff0c;找到并锁定目标客户群体是企业成功的关键。以下是几种有效的策略&#xff0c;帮助您精准定位并吸引目标客户。 1. 明确市场定位与客户画像 首先&#xff0c;企业需要明确市场定位&#xff0c;并绘制详细的客户画像&#xff0c;包括年龄、性别、…

LeetCode合并两个有序链表

题目描述&#xff1a; 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4] 示例 2&#xff1a; 输入&#xff1a;l1 [], l2…

以FLV解复用为例详解开源库FFmpeg中解复用器的源码逻辑及处理流程

目录 1、FFmpeg简介 2、FLV文件格式介绍 3、注册解复用器 4、解复用器的处理 4.1、AVFormatContext 4.1.1、AVClass 4.1.2、AVOption 4.1.3 AVDictionary—AV字典 4.1.4、AVIOContext 4.1.4.1、URLProtocol 4.1.4.2、AVIOContext的初始化及获取 4.1.5、AVInputF…

基于vue篮球联盟管理系统pf

TOC springboot476基于vue篮球联盟管理系统pf 第1章 绪论 1.1 课题背景 二十一世纪互联网的出现&#xff0c;改变了几千年以来人们的生活&#xff0c;不仅仅是生活物资的丰富&#xff0c;还有精神层次的丰富。在互联网诞生之前&#xff0c;地域位置往往是人们思想上不可跨域…

Python入门教程(超详细)

《网络安全自学教程》 Python是一种「基于C语言」实现的&#xff0c;「开源」的&#xff0c;「面向对象的」的&#xff0c;「动态数据类型」的「解释型」语言。 Python的语法「简单」且「优雅」&#xff0c;相对于其他语言学习「难度较低」&#xff0c;入门非常快。 Python的…

【C++】使用红黑树封装map与set

文章目录 1. 源码分析2. 调整红黑树的结构搭建map、set3. 红黑树的迭代器3.1 普通迭代器3.2 const迭代器3.3 map的operator[ ] 4. 完整代码4.1 RBTree4.2 MyMap4.3 MySet 对于map与set&#xff0c;它们一个是KV模型&#xff0c;一个是K模型&#xff0c;那我们要写两个红黑树吗&…

基于Springboot网上蛋糕售卖店管理系统的设计与实现--论文pf

TOC springboot504基于Springboot网上蛋糕售卖店管理系统的设计与实现--论文pf 第1章 绪论 1.1选题动因 当前的网络技术&#xff0c;软件技术等都具备成熟的理论基础&#xff0c;市场上也出现各种技术开发的软件&#xff0c;这些软件都被用于各个领域&#xff0c;包括生活和…