图形渲染(5)光线追踪

1,466 阅读5分钟

实现效果

下图中所有的元素都是代码生成的,题目源于《现代图形学作业5-闫令琪》,这个图在很多地方都看到,不知道是哪位大咖最先提出来的模型。 光线追踪demo

完整代码: github.com/summer-go/g…

欢迎关注公众号:sumsmile /专注图像处理的移动开发老兵~~

什么是光线追踪

回顾下光栅化

将立体空间中的物体映射到2D屏幕上,本质上是一个采样的流程

三角形的光栅化

上图举了最简单的例子-三角形光栅化,实际上光栅化的方式也可以渲染比较复杂的场景。

但是要实现更真实的效果,得用到光线追踪

光线追踪

光线追踪-光线弹射一次

要逼近真实感,需从能量守恒的角度,模拟光线传播的路径。从屏幕上每一个像素点射出一条光线,撞到第一个物体,再反弹出去,反向模拟光线传输(镜面反射、漫反射、折射)的效果,上图中,圆球上的一个点的颜色实际由多个光源、其他物体反射的光线叠加而成。

光线多次弹射

折射的场景

Whitted-style光线追踪实现

光线追踪最基本的原理很简单,实现有许多细节需要注意。下文实现whitted-style风格的光线追踪。

John Turner Whitted既是一位电子工程师,也是一位计算机科学家,1979年在论文《一种改进阴影显示的光照模型》中,将递归式的光线追踪引入到计算机图形学领域

whitted-style方式实现的ray tracing,从"人眼"出发,反向追踪打在物体表面光线的来源,继而基于光线和物体材质的属性计算颜色。

实现逻辑

光线追踪demo

下面用代码实现whitted-style的光追,场景中有以下元素:

  • 格子形状的地板
  • 一个漫反射材质的球
  • 一个镜面反射 & 折射材质的球
  • 两个点光源

场景非常简单,再加上一些辅助的工具类就齐活儿了

场景构造

关键代码说明

代码中有详细的注释,本文对关键的技术点做说明。

代码中用到不少c++11以上的语法特性,遇到陌生的语法,建议读者查一查

概述

  • main.cpp:实现逻辑的调度,创建scene,并在scene中添加了shpere、mesh
  • 物体:sphere、Triangle(地板是两个三角形)继承自Object,Object定义了抽象方法 intersect(判断相交)、getSurfaceProperties(获取表面属性)
  • Render:最核心的类,实现了反射、折射、光线投射、路径追踪的逻辑
  • Light:光照只有两个属性,定义位置、强度
  • 其他类:Vector(向量操作)、global(工具方法、状态显示等)

Rrender实现

空间变换

如上图,需要对屏幕的每一个像素点计算光线追踪,像素点的坐标由下面式子定义:

ImageAspectRatio=ImageWidthImageHeight{ImageAspectRatio = \dfrac{ImageWidth}{ImageHeight}}

PixelCamerax=(2PixelScreenx1)ImageAspectRatiotan(α2){PixelCamera_x = (2 * {PixelScreen_x } - 1) * ImageAspectRatio * tan(\dfrac{\alpha}{2})}

PixelCameray=(12PixelScreeny)tan(α2).{PixelCamera_y = (1 - 2 * {PixelScreen_y }) * tan(\dfrac{\alpha}{2}).}

ImageAspectRatio:渲染窗口宽高比

tan(α2)tan(\dfrac{\alpha}{2}) 是计算视锥的大小,试想,你睁大眼睛看,能看到的场景更大,但是单一物体在场景中的比重就减小了,即视角增大,物体缩小,原来能采样物体的坐标现在采样到外面空白地方去了。

详细参考: www.scratchapixel.com/lessons/3d-…

castRay

castRay是最核心的逻辑,递归式的探索光线的传播路径,经过了哪些物体的弹射,找到光源,如果最后没有与任何物体相交,则取默认的环境光,其中弹射的方式可以是"反射"、"折射"、"漫反射",弹射的方式取决于物体的材质,材质在global中定义了

enum MaterialType
{
    // 漫反射材质
    DIFFUSE_AND_GLOSSY,
    // 反射 + 折射材质(玻璃)
    REFLECTION_AND_REFRACTION,
    // 反射(镜子)
    REFLECTION
};

像素缓存,生成图片文件

像素的颜色存放到一个framebuffer中,用vector实现

图像最后以ppm格式存储,ppm是一个矢量图,参考: blog.csdn.net/kinghzkingk…

Render中,折射的实现初次接触也有点复杂,涉及到光学的理论,需要耐心的推导,不知道你的中学物理都忘光了没

反射折射参考: www.scratchapixel.com/lessons/3d-…

Sphere、Triangle

判断相交 intersect

球体和三角形判断相交的方法不同

球体相交判断:

光线与球体相交 Ray:r(t)=o+td{Ray:r(t)=o + td}

sphere:(pc)2R2=0{sphere:(p - c)^2 - R^2 =0}

方程有解t >= 0 则相交,求方程解并不是我们熟悉的方式,目的是为了减少浮点数运算产生的误差,参考说明:www.zhihu.com/people/cowi…

代码如下:

/**
 * 解一元二次方程,实现说明:https://www.zhihu.com/people/cowill/posts
*/
inline bool solvecQuadratic(const float& a, const float& b, const float& c, float& x0, float& x1)
{
    float discr = b * b - 4 * a * c;
    if (discr < 0)
        return false;
    else if (discr == 0)
        x0 = x1 = -0.5 * b / a;
    else
    {
        float q = (b > 0) ? -0.5 * (b + sqrt(discr)) : -0.5 * (b - sqrt(discr));
        x0 = q / a;
        x1 = c / q;
    }
    if (x0 > x1)
        std::swap(x0, x1);
    return true;
}

三角形相交判断: 本质也是解方程,用Möller Trumbore Algorith做优化

Möller Trumbore Algorith

颜色采样

球体的颜色好定义,一个漫反射定义为灰色,一个透明的无色。格子形状的地板使用算法实现的,是一种“procedural-texturing”,程序纹理,自己实现真不太好想,参考文章说明: www.scratchapixel.com/lessons/3d-…

  /**
     * 
     * 计算地板网格状的纹理颜色,原理参考:
     * https://www.scratchapixel.com/lessons/3d-basic-rendering/introduction-to-shading/procedural-texturing
    */
    Vector3f evalDiffuseColor(const Vector2f &st) const override
    {
        float scale = 5;
        float pattern = (fmodf(st.x * scale, 1) > 0.5) ^ (fmodf(st.y * scale, 1) > 0.5);
        return lerp(Vector3f(0.815, 0.235, 0.031), Vector3f(0.937, 0.937, 0.231), pattern);
    }

掌握了算法原理,也可以实现其他的地板图案

pattern = (cos(st.y * 2 * M_PI * scale) * sin(st.x * 2 * M_PI * scale) + 1) * 0.5; // compute sine wave pattern 

欢迎关注公众号:sumsmile /专注图像处理的移动开发老兵~~

参考资料

[1] wikipedia-J.Turner Whitted: en.wikipedia.org/wiki/J._Tur…

[2] Generating Camera Rays: www.scratchapixel.com/lessons/3d-…

[3] 反射折射: www.scratchapixel.com/lessons/3d-…

[4] procedural-texturing: www.scratchapixel.com/lessons/3d-…

[5] GAMES-101HW代码归档: alexandrite.top/2020/07/13/…

[6] games101作业问题整理: zhuanlan.zhihu.com/p/375391720