Games101,作业7(模板分析)

2023-11-05

该博客只分析较难理解的函数和用途,以及程序运行方式,简单的函数不再赘述。

  • 首先,我们将从程序运行的流程来理解代码框架。
  • 之后再按照代码文件来分析整个框架的构造思路。

程序流程(main函数进入)

构造Scene类(构造场景)

Scene scene(784, 784);

Scene

参数:
    int width = 1280;
    int height = 960;
    double fov = 40;
    Vector3f backgroundColor = Vector3f(0.235294, 0.67451, 0.843137);
    int maxDepth = 1;
    float RussianRoulette = 0.8;

	BVHAccel *bvh;
	std::vector<Object* > objects;					//模型指针集合
    std::vector<std::unique_ptr<Light> > lights;	//光源指针集合
构造函数:
    Scene(int w, int h) : width(w), height(h)
    {}

设置材质(Material类)

Material* red = new Material(DIFFUSE, Vector3f(0.0f));
red->Kd = Vector3f(0.63f, 0.065f, 0.05f);

参数:

MaterialType m_type;//只有diffuse材质(漫反射材质)
Vector3f m_emission;//辐射量
float ior;
Vector3f Kd, Ks;//Kd漫反射系数,Ks高光镜面反射系数
float specularExponent;

构造函数

Material::Material(MaterialType t, Vector3f e){
    m_type = t;//材质类型
    m_emission = e;//不知道是什么,构造时都为0.0f
}

使用:在main函数中构造了red,green,white,light 四种材质,设置了材质的漫反射系数。

加载模型(MeshTriangle类,三角形网格类)

 MeshTriangle floor("../models/cornellbox/floor.obj", white);
参数
Bounds3 bounding_box;					//包围盒
std::unique_ptr<Vector3f[]> vertices;	//顶点集合的指针
uint32_t numTriangles;					//三角形数量
std::unique_ptr<uint32_t[]> vertexIndex;//顶点集合下标的指针
std::unique_ptr<Vector2f[]> stCoordinates;//纹理坐标集合的指针

std::vector<Triangle> triangles;//三角形集合

BVHAccel* bvh;							//bvh树的根指针
float area;								//表面积之和

Material* m;							//材质指针
构造函数
  1. 调用obj1::Loader载入模型(Loader类这里便不再介绍,这个类主要用于读取obj格式的文件)
objl::Loader loader;
loader.LoadFile(filename);
  1. 将模型中的所有三角形保存到三角形集合中,并且计算出整个模型的包围盒保存到bounding_box中
  2. 创建三角形指针集合ptrs,用三角形指针集合构建BVH树
std::vector<Object*> ptrs;
for (auto& tri : triangles){
      ptrs.push_back(&tri);
      area += tri.area;
}
bvh = new BVHAccel(ptrs);

对模型构建BVH树

BVHAccel 类(BVH加速器)
参数:

    BVHBuildNode* root;				//BVH树根节点。
    // BVHAccel Private Data
    const int maxPrimsInNode;       //默认值为1,在代码中没有被使用
    const SplitMethod splitMethod;	//拆分方法,默认为SplitMethod::NAIVE(原始的)
    std::vector<Object*> primitives;//三角形指针集合

构造函数:
调用recursiveBuild(递归构造)

root = recursiveBuild(primitives);

BVHBuildNode结构体

struct BVHBuildNode {
    Bounds3 bounds;			//包围盒
    BVHBuildNode *left;		//左指针
    BVHBuildNode *right;	//右指针
    Object* object;			//物体指针
    float area;				//面积
    
    ...
}
recursiveBuild函数

构建BVH树:

  1. 对于每一个结点都有该结点包含三角形的包围盒左右指针指向子结点
  2. 每次对包围盒的最长边进行分隔。
  3. 求每个三角形的重心,以重心坐标包围盒最长的方向进行排序,再二分递归建立子节点。
  4. 直到结点中只剩下1个三角形,结束递归(两个三角形建立左右结点递归)。
  5. 返回根结点

将模型添加到场景

scene.Add(&floor);

将模型指针添加到<object*>容器中。

void Add(Object *object) { objects.push_back(object); }

对场景构建BVH树

scene.buildBVH();

对object容器构建BVH树,将结果保存在Scene的bvh中。

this->bvh = new BVHAccel(objects, 1, BVHAccel::SplitMethod::NAIVE);

每一个模型看作一个整体进行树的构建。

整个BVH树的构建

先以模型为基本元素进行树的构建,再对每一个模型内部进行树的构建。

渲染

Renderer r;
r.Render(scene);

对场景中的每一个像素生成一道从视点发出的光线

framebuffer[m++] = scene.castRay(Ray(eye_pos, dir), 0);

调用castRay函数进行光线追踪。

这块内容详见 作业7,作业代码分析

存储到文件

存储为ppm文件格式。

// 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] = (unsigned char)(255 * std::pow(clamp(0, 1, framebuffer[i].x), 0.6f));
        color[1] = (unsigned char)(255 * std::pow(clamp(0, 1, framebuffer[i].y), 0.6f));
        color[2] = (unsigned char)(255 * std::pow(clamp(0, 1, framebuffer[i].z), 0.6f));
        fwrite(color, 1, 3, fp);
    }
    fclose(fp);   

到此为止,程序便完成了最终图像的生成
下面我们对文件中各功能进行分析

对代码文件分析

代码文件中有较多并未使用的函数和许多冗杂参数,使得阅读代码时“杂音”太多。下面将只介绍光线追踪中使用到的函数。

Main.cpp

进行场景的构建,模型的添加,参数的设置,渲染的调用。

Scene类

参数
	int width = 1280;
    int height = 960;
    double fov = 40;
    Vector3f backgroundColor = Vector3f(0.235294, 0.67451, 0.843137);
    int maxDepth = 1;
    float RussianRoulette = 0.8;//俄罗斯轮盘赌
    std::vector<Object* > objects;//模型的容器(存储的是模型指针,不是三角形)
    std::vector<std::unique_ptr<Light> > lights;
    BVHAccel *bvh;
函数

向场景中添加物体

    void Add(Object *object) { objects.push_back(object); }
    void Add(std::unique_ptr<Light> light) { lights.push_back(std::move(light)); }

获取object和light的引用

    const std::vector<Object*>& get_objects() const { return objects; }
    const std::vector<std::unique_ptr<Light> >&  get_lights() const { return lights; }

光线与场景求交

Intersection intersect(const Ray& ray) const;

对object容器构造BVH树

void buildBVH();

光线追踪

Vector3f castRay(const Ray &ray, int depth) const;

光源采样,在光源中按面积均匀采样,返回pos(采样点信息)和pfd(采样点密度)

void sampleLight(Intersection &pos, float &pdf) const;

未使用的函数

    bool trace(const Ray &ray, const std::vector<Object*> &objects, float &tNear, uint32_t &index, Object **hitObject);
    std::tuple<Vector3f, Vector3f> HandleAreaLight(const AreaLight &light, const Vector3f &hitPoint, const Vector3f &N,
                                                   const Vector3f &shadowPointOrig,
                                                   const std::vector<Object *> &objects, uint32_t &index,
                                                   const Vector3f &dir, float specularExponent);
    Vector3f reflect(const Vector3f &I, const Vector3f &N) const;
    Vector3f refract(const Vector3f &I, const Vector3f &N, const float &ior) const;
    void fresnel(const Vector3f &I, const Vector3f &N, const float &ior, float &kr) const
    //由菲涅耳公式可以求出一定入射角下反射和透射的振幅、强度等

Triangle类

class Triangle : public Object

参数
    Vector3f v0, v1, v2; // vertices A, B ,C , counter-clockwise order
    Vector3f e1, e2;     // 2 edges v1-v0, v2-v0;
    Vector3f t0, t1, t2; // texture coords
    Vector3f normal;
    float area;
    Material* m;
函数

返回光线ray与该三角形的交点信息

Intersection Triangle::getIntersection(Ray ray)

随机得到三角形内一点,并得到该点pdf(该点的概率密度)为1/三角形面积。

void Sample(Intersection &pos, float &pdf)

得到三角形面积

float getArea();

判断该物体是否为光源

bool hasEmit();

class MeshTriangle : public Object

参数
	Bounds3 bounding_box;
    std::unique_ptr<Vector3f[]> vertices;
    uint32_t numTriangles;
    std::unique_ptr<uint32_t[]> vertexIndex;
    std::unique_ptr<Vector2f[]> stCoordinates;

    std::vector<Triangle> triangles;
    BVHAccel* bvh;
    float area;

    Material* m;
函数

构造函数:加载模型,并将模型中的三角形加载入std::vector<Triangle> triangles中,并对该模型构造BVH树

MeshTriangle(const std::string& filename, Material *mt = new Material())

光线与该模型求交

Intersection getIntersection(Ray ray)

下面函数功能与Triangle 类相同

void Sample(Intersection &pos, float &pdf)
float getArea()
bool hasEmit()

其他未提及的函数都是没有被使用的。

BVHAccel类

struct BVHBuildNode

	Bounds3 bounds;
    BVHBuildNode *left;
    BVHBuildNode *right;
    Object* object;
    float area;
参数
    enum class SplitMethod { NAIVE, SAH };//分隔方法
    BVHBuildNode* root;
    const int maxPrimsInNode;
    const SplitMethod splitMethod;
    std::vector<Object*> primitives;
函数

构造函数
对容器p构造BVH树,返回根节点。

BVHAccel(std::vector<Object*> p, int maxPrimsInNode = 1, SplitMethod splitMethod = SplitMethod::NAIVE);

内部函数:递归构造BVH树函数(设为private更好)

BVHBuildNode* BVHAccel::recursiveBuild(std::vector<Object*> objects)

光线与root根节点下的三角形求交。

Intersection Intersect(const Ray &ray) const;

内部函数:递归搜索查找光线与node根节点下的三角形求交,返回最先打到的三角形交点。(设为private更好)

Intersection getIntersection(BVHBuildNode* node, const Ray& ray)const;

获取根节点(root)下的某个点,且返回该点密度函数(1/该根节点包含的面积)

void Sample(Intersection &pos, float &pdf);

根据p值得到某个三角形上的某一点pospdf恒为1返回。

void getSample(BVHBuildNode* node, float p, Intersection &pos, float &pdf);

其他类的重要性不大,有需要时再补充

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Games101,作业7(模板分析) 的相关文章

  • 10行代码创造一个像素,图形学版本的hello world

    10行代码创造一个像素 图形学版本的hello world 任何的图片 视频 音乐其本质都是数据 当我们要生成一张图片时 只需要将数据写入文件 仅此而已 以ppm格式图片为例 上图为维基百科的ppm格式说明 按照上图格式将数据写入到文件中
  • openGL之API学习(二十七)glEnable

    开启服务器端的opengl功能 void glEnable GLenum cap GL BLEND If enabled blend the computed fragment color values with the values in
  • BRDF详解(包括:irradiance,radiance,intensity,立体角)

    BRDF BRDF是双向反射分布函数 Bidirectional Reflectance Distribution Function BRDF 用来定义给定入射方向上的辐射照度 irradiance 如何影响给定出射方向上的辐射率 radi
  • 绕坐标轴以及任意轴的旋转矩阵的推导

    概述 本文主要是针对 3D数学基础 图形与游戏开发 这本书的读书笔记 这本书前面部分还是讲得挺好的 有时间还是建议读一下 旋转矩阵的推导 旋转矩阵怎么来的我倒一直都没有概念 这本书里面对旋转矩阵的来历倒是给了我一些启发 首先从二维的旋转矩阵
  • openGL之API学习(七十)windows的opengl扩展wgl

    WGL扩展说白了是Windows操作系统和OpenGL做交互的一系列扩展 glut也好 其他框架也好 都是对这些接口进行了封装 之前的文章也提到了 Windows在对OpenGL的原生支持非常不友好 甚至差点就夭折了 在wingdi h这个
  • OpenGL 纹理数组

    参考 glTexStorage3D glTexStorage3D glTexImage3D glTexSubImage3D glTexStorage3D code example
  • 四元数 旋转 旋转矩阵 欧拉角互相转换

    四元数的作用 表达旋转 旋转的表达方式有很多种 有欧拉角 旋转矩阵 轴角 四元数 unit quaternion unit quaternion是一种表达旋转的方式 不同的旋转表达方式概览 1 欧拉角 欧拉角使用最简单的x y z值来分别表
  • 计算机图形学入门(十六)-光线追踪(渲染方程)

    本部分主要介绍了渲染方程的逐步完善和简单的推导过程 从BRDF开始 到反射公式的推导再到渲染方程的完善 最后展示了实际渲染的例子 学习视频 GAMES101 现代计算机图形学入门 闫令琪 哔哩哔哩 bilibilihttps www bil
  • GAMES101-现代计算机图形学学习笔记(4)作业3

    前言 上篇作业2 本篇将更新作业3相关内容 作业3相关链接 games的作业3链接 我的源码 作业3简述 插值计算 各种shader实现 作业3相关知识笔记 Barycentric Coordinates Blinn Phong Lambe
  • 图形学光照

    图形学光照 一 概述 二 环境光照 三 漫反射光照 四 镜面光照 五 光照公式 六 Demo 一 概述 现实世界的光照是极其复杂的 而且会受到诸多因素的影响 这是我们有限的计算能力所无法模拟的 因此OpenGL的光照使用的是简化的模型 对现
  • 19、计算机图形学——蒙特卡洛路径追踪

    一 蒙特卡洛积分 蒙特卡洛积分主要解决的问题是当被积函数很难被以函数的形式表示时 需要对该被积函数指定概率密度函数并进行多次采样 然后用采样得到的局部面积除以局部采样点的概率来近似得到整体的面积 积分 当采样次数足够多时 将这些整体近似值除
  • openGL之API学习(六十二)glBufferData

    往gpu缓冲区写入数据 void glBufferData GLenum target GLsizeiptr size const GLvoid data GLenum usage target Specifies the target t
  • 计算机图形学【GAMES-101】13、光场、颜色与感知

    快速跳转 1 矩阵变换原理Transform 旋转 位移 缩放 正交投影 透视投影 2 光栅化 反走样 傅里叶变换 卷积 3 着色计算 深度缓存 着色模型 着色频率 4 纹理映射 重心坐标插值 透视投影矫正 双线性插值MipMap 环境光遮
  • 计算机图形学入门(一)-线性代数部分知识1

    本部分主要介绍了向量的点乘与叉乘在图形学中的基本应用 介绍了图形学中常用的2D矩阵变换 例如缩放 对称 切变换 旋转 平移 逆变换 组合变换和分解变换 还有在图形学中为了简化操作而采取的添加维度的方法 主要的学习过程来自下面的视频 本文只会
  • openGL之API学习(十六)glViewport

    确定要绘制的区域 如果你打算把整个屏幕渲染到一个或大或小的纹理上 你需要用新的纹理的尺寸作为参数再次调用glViewport 要在渲染到你的帧缓冲之前做好 否则只有一小部分纹理或屏幕能够绘制到纹理上 void glViewport GLin
  • games101,作业1

    正交变换 左边是缩放变换 右边是平移变换 对图形进行正交变换需要 先平移 再缩放 但是做矩阵乘法时 先相乘的矩阵放在右边 后相乘的矩阵放在左边 视口平移 Translate M ortho trans lt lt 1 0 0 r l 2 0
  • openGL之API学习(三十三)查看opengl、显卡的信息

    const GLubyte name glGetString GL VENDOR 返回负责当前OpenGL实现厂商的名字 const GLubyte biaoshifu glGetString GL RENDERER 返回一个渲染器标识符
  • BRDF详解

    光照模型主要分为三类 测量模型 经验模型和基于物理的分析模型 在计算机图形学中介绍的光照模型为经验模型中的Phong模型 也就是本人理解的 根据点距光源的位置 入射角度等信息计算的 反射强度 包括漫反射强度 镜面反射强度 但是Phong模型
  • 游戏开发unity 3d知识系列:(一)用mesh绘制一个三角形网格

    国内讲解这些基础的感觉比较少 在youtube上看到一个比较好的视频 https www youtube com watch v eJEpeUH1EMg
  • openGL之API学习(六十三)GL_RASTERIZER_DISCARD

    glEnable GL RASTERIZER DISCARD 使用GL RASTERIZER DISCARD标志作为参数调用glEnable 函数 告诉渲染管线在transform feedback可选阶段之后和到达光栅器前抛弃所有的图元

随机推荐

  • 你必须要记住的动态内存管理函数

    问题引入 首先我们要明白为什么要动态内存分配 这是因为我们所熟知的内存开辟方式通常有两个特点 1 空间开辟大小是固定的 2 数组在声明时 必须指定数组的长度 他所需要的内存在编译的时候分配 但是由于我们对空间的需求多种多样 有时候我们需要的
  • 服务器虚拟机ping不通百度,未知的名称或服务,解决方法

    ping不通百度 未知的名称或服务 解决方法 route添加一条路由 需要先安装net tools工具包 root localhost yum install net tools y root localhost route n Kerne
  • 拉格朗日函数与广义拉格朗日函数

    拉格朗日函数用来求解等式约束的最优化问题 广义拉格朗日函数用来求解不等式约束的最优化问题 无约束优化问题 关于优化问题包括无约束优化问题 等式约束优化问题 不等式约束优化问题 这里简略地介绍一下无约束优化问题 以后再来填坑 考虑无约束优化问
  • TypeError: ‘tuple‘ object does not support item assignment

    TypeError tuple object does not support item assignment 原因 修改了tuple 而tuple是不支持修改的 或者说tuple不支持直接修改 解决方法 定义一个临时变量temp temp
  • Docker日志查看命令

    docker容器列表查看 docker ps 日志查看语法 docker logs OPTIONS CONTAINER OPTIONS说明 f 跟踪日志输出 since 显示某个开始时间的所有日志 t 显示时间戳 tail 仅列出最新N条容
  • 2022十三届蓝桥杯国赛题解

    特此声明 本文仅为参考文档 标准答案请参考官方文档 试题A 该题是一道背包dp题 我的思路是定义三维dp 第一维表示第i个数 第二维表示前i个数的总和为j 第三维表示前i个数 总和为j 第i个数为z的方案数 首先观察这个题的性质 要求互不相
  • 十五、使用Selector(多路复用器)实现Netty中Reactor主从模型

    导论 前面几篇文章我们分别从 一 C10K问题经典问答 二 java nio ByteBuffer用法小结 三 Channel 通道 四 Selector选择器 五 Centos Linux安装nc 六 windows环境下netcat的安
  • 医疗场景下CV应用的总结与思考

    目录 背景 项目总体思路与框架 技术难题及解决思路 Data模块 Modeling模块 Deployment模块 可优化方向 标注流程 基于GAN的眼底图像生成模型 隐私计算 联邦学习 即时标注平台 自动化机器学习 背景 随着新生儿眼底筛查
  • 【Flask】Flask 会话

    Flask Sessions 会话 由于HTTP是无状态的 因此无法纪录客户一连串的动作 必须有一种机制使服务器能认得客户 这就引入了 会话 概念 服务器发给客户一个会话ID 当客户再访问服务器时就带着这个ID 服务器就凭着这个唯一的ID来
  • 毕业实习:Vue+Springboot+MySQL实现的订餐系统

    为期4天的毕业实习的收获 第一部分 vue框架的准备工作 测试vue cli创建工程 要以管理员身份运行cmd 1 在F盘下新建一个F shixuntestvue code文件 2 cd F 3 cd shixuntestvue code
  • python爬虫+数据分析完整流程--豆瓣电影分类排行榜

    整体思路 利用requests BeautifulSoup爬虫豆瓣电影分类排行榜数据 数据输出到本地csv文件 构建mongodb数据库 将数据存放入mongodb 利用pandas matplotlib画图分析数据 1 利用Beautif
  • Nginx安全性配置

    隐藏版本号 http server location http server tokens off 访问黑白名单设置 http server location limit except 白名单 只允许192 168 1 0 24网段的主机访
  • POJO/DTO/DO/EO/VO/BO/PO/AO的含义和使用

    关于POJO DTO DO EO VO BO PO AO 本文讨论 POJO DTO DO EO VO BO PO AO 的定义 另外讨论了这些xO在controller service dao mapper层里的使用规范 另外还稍微讨论了
  • 2023年第十四届蓝桥杯第一题阶乘求和的python另类解法

    蓝桥杯2023 求和 1 2 3 202320232023 的后9位数字 模除 乘方 n 202320232023 s s1 0 temp 10 9 for i in range 1 n 1 m 1 for k in range 1 i 1
  • 【Git系列】IDEA集成Git

    IDEA集成Git 1 idea配置git 2 idea添加暂存区和提交 创建文件 将整个项目添加到暂存区 提交到本地仓库 查看控制台 显示提交的信息 修改文件 再次提交 3 idea拉取和推送 拉取远程仓库 推送远程仓库 4 idea克隆
  • Qt出现“undefined reference to vtable for”原因总结 (转my gallery)

    由于Qt本身实现的机制所限 我们在使用Qt制作某些软件程序的时候 会遇到各种各样这样那样的问题 而且很多是很难 或者根本找不到原因的 即使解决了问题 如果有人问你为什么 你只能回答 不知道 今天我在这里列举的问题也是再编写Qt程序时 总是遇
  • 中文文本分类-朴素贝叶斯

    原创作品 出自 晓风残月xj 博客 欢迎转载 转载时请务必注明出处 http blog csdn net xiaofengcanyuexj 由于各种原因 可能存在诸多不足 欢迎斧正 最近在想怎么利用数据挖掘的方法进行评论自动审核 分类为垃圾
  • linux下启动tomcat服务

    目前有个java mysql项目需部署到 麒麟系统 一番折腾后总算成功部署上去了 其操作和windows有本质区别 需要使用终端命令行 现将常用运维操作整理如下 Linux下tomcat服务的启动 关闭与错误跟踪 使用PuTTy远程连接到服
  • VSCode 连不上远程服务器问题及解决办法集合

    楼主由于突然 VSCode 连不上服务器 因此从网上搜到了很多解决办法 楼主觉得可以将这些方法集中起来 为遇到这种连接问题的人们作为参考 该资料将持续更新 也欢迎各位大神留言提供更多解决办法 目录 1 Error Establishing
  • Games101,作业7(模板分析)

    该博客只分析较难理解的函数和用途 以及程序运行方式 简单的函数不再赘述 首先 我们将从程序运行的流程来理解代码框架 之后再按照代码文件来分析整个框架的构造思路 程序流程 main函数进入 构造Scene类 构造场景 Scene scene