aurora-rendering-engine/experiments/Request.md

8.0 KiB
Raw Blame History

C++实现一个简易的康奈尔盒子渲染器,但是不基于传统的光线追踪算法,而是一种类似的基于面片及纹理的步进式变换渲染算法(也就是说它的渲染是以面片而非射线作为处理单位的),其描述如下: 将实际渲染画面抽象至场景中然后遍历所有面片对于所有面片将其渲染出的纹理变换粘贴至viewport的指定像素中如果需要计算反射、AO等信息则以遍历到的面片为第一人称viewport渲染该viewport下的所有面片并将相交到的面片变换拉伸其实只需要按图片像素直接拉伸即可至当前面片的current纹理上最后递归总结出整体画面。概括地说就是递归地遍历所有面片并将当前正在处理的面片作为current viewport然后将相机原点关于当前这个面片进行对称模拟光线的反射行为将可能会映射到当前面片上的所有面片的纹理进行变换扭曲附加到当前面片的纹理上返回给上一级递归函数栈进行继续的变换从而实现金属的反射效果对于漫反射效果不进行递归而是直接返回当前纹理。当前实现版本要求只使用三角形面片方便实现和扩展因此算法将Camera viewport作为场景中的两个三角形面片进行渲染然后将这两个三角形的纹理直接输出到图片中。 对于这个算法,有几点需要注意的地方:

  1. 在遍历物体的时候需要考虑到物体渲染的覆盖关系。对于覆盖关系我有一个临时解决方案即遍历获取到可能会投射在viewport上的所有物体的列表后由远到近进行渲染则这部分的时间复杂度为O(nlogn)遍历所有投射的物体为n可以考虑使用优先队列维护由远到近的关系为logn整合时间复杂度为nlogn
  2. AO等特性、漫反射等内容可能需要特化计算但是你可以先忽略这些内容专注于实现基本的面片纹理变换和渲染功能 给出单个可以编译执行的C++文件不考虑文件大小和代码行数优先实现如上所说的所有功能生成的图片写入PPM即可 对于当前这轮对话AO等特性可能涉及到采样内容因此你无需实现我将会后续进行编写。 对于康奈尔盒子你需要实现一个拥有四壁的Cornell Box和两个具有金属材质特性镜面反射的一蓝一黄的盒子的场景并渲染。另外有一个必须要注意的事情就是在代码实现中对于Camera的渲染不应该按Ray发射计算颜色否则会和传统光线追踪思路雷同而是根据相机原点和viewport生成当前viewport的视锥体并遍历面片进行相交检测之后对遍历到的面片进行反射对称相机原点之后调用该面片的当前函数进行递归然后直接把它返回的纹理贴到当前面片的当前纹理中。 我接下来会给你一个实现思路,请你按照如下思路实现代码:
  3. 你需要实现Vec3等基本数据结构。
  4. 实现Triangle类及相关运算如triangle与triangle的相交等运算
  5. 实现Camera类及相关运算Camera存储相机原点及两个Viewport三角形这个类的render函数不实现逻辑仅调用两次渲染函数并将两个三角形的纹理转储至PPM
  6. 实现渲染函数renderTriangleWithTriangle传入三角形面片列表及相机原点和当前面片(以当前面片作为viewport)该函数首先检查材质类型假如是Diffuse漫反射类型则直接返回材质纹理如果是Reflective镜面反射类型的话则需要根据物体纹理进行计算首先初始化当前面片在指定相机原点下将会显示出的纹理图片根据传入的viewport原点和当前面片的三个点计算出视锥体注意这个视锥体顶部是被削平的然后遍历所有物体检测它们跟当前视锥体是否相交或包围并将是的面片存储进一个列表建议存指针速度快然后对这个列表根据距离进行排序由远到近之后遍历这个列表对于列表中的每个面片递归调用它们的renderTriangleWithTriangle函数获取它们应该显示出的纹理之后根据目标面片的三个点和原点的连线与当前面片viewport的交点计算出目标面片将会映射到当前面片上的三个点之后根据这三个点直接对材质进行拉伸变形然后写入函数最开始定义的纹理图片中可以考虑加入反走样遍历完列表中的所有面片之后就可以返回当前的纹理图片了关于函数的终止条件可以定为当当前纹理投影在最终幕布上的面积大小小于某个阈值时停止递归比如1~5个像素点大小关于当前面片纹理图片初始化的时候设定的像素大小你可以给renderTriangleWithTriangle这个函数加个表示预估长宽的参数

V2: C++实现一个康奈尔盒子渲染器,采用基于三角形面片的投影纹理映射递归算法。该算法的核心思想是:将每个面片视为一个微型视口,通过递归投影变换组合纹理,模拟光线传播效果。

算法原理

  1. 基础概念

    • 场景由三角形面片构成,每个面片包含:几何信息、纹理、材质属性
    • 相机由原点位置和两个三角形面片(左、右视口)定义
    • 渲染过程从相机视口面片开始,递归处理可能影响最终图像的场景面片
  2. 递归投影流程 对于当前处理的面片(称为"当前视口面片" a. 确定从相机原点通过当前视口面片可见的空间区域(一个平截头体) b. 找出与该区域相交的所有场景面片 c. 对每个相交面片,根据其材质执行相应投影操作 d. 将投影结果累积到输出图像

  3. 材质处理逻辑

    • 相机视口材质:作为递归起点,不直接贡献颜色,只组织后续渲染
    • 漫反射材质:单次投影,将面片纹理变换到最终图像平面
    • 金属反射材质:两次投影,先投影到图像平面,再递归处理反射内容

关键实现细节

  1. 投影变换计算 对于面片A投影到面片B需要计算从A纹理坐标到B纹理坐标的投影矩阵。 这涉及:

    • 计算A到相机原点的透视投影
    • 计算从该投影到B平面的投影变换
    • 组合变换得到最终纹理映射
  2. 视锥体相交检测 对于三角形T和相机原点O定义视锥体为O与T形成的三棱锥。 另一个三角形与之相交的判断标准:至少一个顶点在视锥体内或与视锥体边界相交。

  3. 递归反射处理 对于金属面片M a. 计算相机原点O关于M平面的镜像点O' b. 以O'为新原点M为新视口面片 c. 递归渲染O'通过M可见的场景内容 d. 将结果与M的纹理混合后投影到上一级

  4. 覆盖关系处理 采用画家算法:在每个递归层级,按面片到视口平面的距离从远到近处理。 实现时可在收集到相交面片后排序处理。

  5. 终止条件 当被投影面片在目标图像上的覆盖区域小于阈值如4个像素时停止递归。 避免无限递归和性能问题。

具体实现要求

  1. 数据结构

    • Vec3三维向量支持点积、叉积、归一化等运算
    • Triangle三角形包含三个顶点、纹理坐标、材质信息
    • Material材质定义包含类型漫反射/金属)、纹理颜色、反射率等
    • Image图像类支持像素读写输出PPM格式
  2. 核心函数

    // 主渲染函数
    void renderTriangle(
        const Triangle& viewportTri,    // 当前视口三角形
        const Vec3& cameraOrigin,       // 当前相机原点
        const Triangle& targetTri,      // 目标纹理三角形(最终图像平面)
        Image& outputImage,             // 输出图像
        int recursionDepth = 0          // 递归深度控制
    );