由于套暑研要准备一个简单的简历,我打算总结一下之前做的一些项目,发博客并上传Github。虽然我能明确地知道,做这些事情对看我简历的人来说毫无影响,但写博客记录自己人生是我自己想做的一件事。
做之前这些项目的时候我都没有去写博客,当时我还没有想好博客该怎么用。以后应该不会出现这些情况了。只要是有一些规模的项目,我都会把从技能学习到编程实现的整个过程发到博客上。
写这个项目是因为我图形学的导师在写一本图形学教程书,其中有一些习题要附上源代码。他让我帮忙实现真实感渲染章节的习题,顺便学习一下这一章的内容。
由于是项目总结,内容会十分简略。
CPU光线追踪C++OpenGL实现
Github地址
https://github.com/SingleZombie/Ray-Tracing-OpenGL
编译项目需要包含一些额外的文件,具体的要求见Github里的readme。
任务定义
实现一个使用光线追踪技术渲染的场景:一个带反射的球放在黑白相间的棋盘格地面上。
知识背景
光线追踪的思想比较简单:以摄像机为端点,向屏幕上每一个像素的处发射一条光线。光线接触到第一个物体后,既会接收物体自身的颜色,还会进行反射和折射,产生更多的光线。这些后续的反射、折射以及物体本身的颜色都会对最开始的这条光线产生贡献。这条光线的强度就能转化成产生光线的像素的颜色值。
从实现的角度来看,光线追踪就是一个递归的过程。为了计算一条光线的强度,还要计算它反射光和折射光的强度。
由于光每次都可以反射和折射,光线与物体的碰撞次数与递归层数成指数级增长,并且客观上光线的反射和折射是无穷无尽的,光线追踪算法需要一些停止递归的规则。递归层数过多、光没碰到物体都能让算法中止。不过即使有了一些限制规则,不经过优化的光线追踪算法运行得依然很慢。
设计
当时我写的伪代码如下:(不过是写完了程序再写的)
1 | // plane是一个平面结构,分量有平面上任意一点、平面法向量、材质 |
实现方法
从软件工程的角度来看,根据光线追踪的描述,很快可以得到编程所涉及的对象:射线(光线)、物体、光源、场景。物体、光源属于场景,每帧从视点向所有像素发出光线与物体判断相交,计算颜色时要用到光源、物体参数。再具体来说,光源包含颜色等参数,物体包含自身的几何信息及材质信息。有了类和类间关系,代码结构很容易写出来。
从算法实现的角度来看,只要理解了光线追踪算法,看懂了上面的伪代码,很容易写出对应的代码。
由于光线追踪算法的像素值完全来自射线和物体的交,物体可以以解析式的形式定义。比如球只需要定义一个中心点位置,一个半径。在判断射线和物体的交时,求解一个射线的参数方程即可。