用500行纯C++代码实现软件渲染:展示3D图形API工作原理,附代码与示例
在这一系列文章里,打算通过从头编写简化版克隆程序,展示OpenGL、Vulkan、Metal和DirectX的工作原理。很多人学3D图形API会卡在入门阶段,为此准备简短系列讲座,讲座后学生能做出功能不错的渲染器。
任务目标
不使用任何第三方库(尤其是图形相关库),生成一张如下所示的图像:
需要注意,这是一份教学材料,大致遵循现代3D图形库结构,是个软件渲染器,并不打算展示如何编写GPU应用程序,而是展示其工作原理。理解这一点对用3D库编写高效应用程序很重要。
起点
最终代码约500行,学生通常花10到20个小时编程才能开始制作这样的渲染器。输入是由三角网格和纹理组成的3D模型,输出是渲染后的图像,程序无图形界面,仅简单生成一张图片。
为减少外部依赖,给学生提供处理 TGA 文件的类。TGA是支持RGB、RGBA和灰度图像的简单格式之一,是图像操作的基础。一开始,除加载和保存图像外,唯一可用功能是设置单个像素颜色。
没有内置绘制线段或三角形的函数,将手动实现所有功能。虽会和学生一起编写源代码,但不建议直接使用,亲自动手实践对理解概念很重要。完整代码可在 GitHub 上找到,给学生的初始源代码可在 这里 找到。下面是起点代码:
main.cpp
#include "tgaimage.h" constexpr TGAColor white = {255, 255, 255, 255}; // 注意,BGRA 顺序 constexpr TGAColor green = { 0, 255, 0, 255}; constexpr TGAColor red = { 0, 0, 255, 255}; constexpr TGAColor blue = {255, 128, 64, 255}; constexpr TGAColor yellow = { 0, 200, 255, 255}; int main(int argc, char** argv) { constexpr int width = 64; constexpr int height = 64; TGAImage framebuffer(width, height, TGAImage::RGB); int ax = 7, ay = 3; int bx = 12, by = 37; int cx = 62, cy = 53; framebuffer.set(ax, ay, white); framebuffer.set(bx, by, white); framebuffer.set(cx, cy, white); framebuffer.write_tga_file("framebuffer.tga"); return 0; }这段代码会生成一个64x64的图像 `framebuffer.tga`,为便于阅读,对其进行了缩放:
编译
git clone https://github.com/ssloy/tinyrenderer.git && cd tinyrenderer && cmake -Bbuild && cmake --build build -j && build/tinyrenderer obj/diablo3_pose/diablo3_pose.obj obj/floor.obj渲染后的图像会保存为 `framebuffer.tga`。
预览:渲染器生成的几个示例
评论
使用 Material for MkDocs 制作
导航目录
- 主页
- tinyrenderer
- 主页
- 布雷森汉姆直线绘制算法
- 三角形光栅化
- 重心坐标
- 隐藏面消除
- 简易相机处理
- 优化相机
- 着色
- 更多数据!
- 切线空间
- 阴影映射
- 环境光遮蔽
- 额外内容:卡通着色
- 后记
- tinycompiler
- 主页
- 抽象语法树
- SLY:词法分析器和语法分析器
- 符号表
- 显示
- 汇编代码生成
- 自制词法分析器
- 自制语法分析器
- 后记
- tinyoptimizer
- 主页
- mem2reg
- tinyfloat
- 主页
- 计算机与数字
- 浮点数打印
- 加法与误差
- 除法
- 香蕉投掷项目
- 主页
- 猿猴计算秒数
- 猿猴买了块更好的手表
- 猿猴没碰到地面
- 猿猴从错误中学习
- 猿猴击中目标
- 猿猴扔得更远
- 懒惰的猿猴
- 丛林起风了
- 猿猴了解丛林法则
- 两秒之间,事情发生了
- 奇闻趣事
- 诅咒之火或 #define 黑魔法
- 门多西诺电机与恩绍定理