免费网站排名优化软件,宁波网站的优化,创建一个网址需要多少钱,口碑最好的网站建设今天你想用最新的 D3D12 画一个三角形#xff0c;少说也要上千行代码了#xff0c;对于初学者来讲#xff0c;这个门槛是非常高的#xff0c;太多干扰了#xff0c;而一千多行代码#xff0c;已经足够你重头实现一个简易版 D3D 了#xff0c;为什么不呢#xff1f;比起…今天你想用最新的 D3D12 画一个三角形少说也要上千行代码了对于初学者来讲这个门槛是非常高的太多干扰了而一千多行代码已经足够你重头实现一个简易版 D3D 了为什么不呢比起从图形 API 入门不如从画点开始同样一千行代码却能让你对 GPU 的工作原理有一个直观的了解。因此为了让希望学习渲染的人更快入门我开源了一个 C 实现可编程渲染管线的教程skywind3000/RenderHelp 那么网上软件渲染器其实不少这个 RenderHelp 和他们有什么区别么区别有三实现精简没依赖就是一个 RenderHelp.h 文件单独 include 它就能编译了不用复杂的工程导入一堆源文件vim/vscode 里设置个 gcc 命令行F9 编译单文件即可。模型标准计算精确网上很多软渲染器实现有很多大大小小的问题比如纹理不是透视正确的比如邻接三角形的边没有处理正确比如 Edge Equation 其实没用对比如完全没有裁剪比如到屏幕坐标的计算有误差应该以像素点方框的中心对齐结果他们对齐到左上角去了导致模型动起来三角形边缘会有跳变的感觉太多问题了对于强迫症画错个点都是难接受的RenderHelp 采用标准模型不画错一个点不算错一处坐标。可读性高全中文注释一千多行代码 1/3 是注释网上很多同类项目属于作者自己的习作重在实现做完了事注释量不足 5%一串矩阵套矩阵的操作过去连行说明都没有你想搜索下相关概念连个关键字都不知道。RenderHelp.h 是面向可读性编写的虽然也比较小巧但重点计算全部展开每一处计算都有解释。某些代码其实可以提到外层运行更快些但为了可读性还是写到了相关位置上便于理解。 渲染效果图片使用很简单include 项目内的 RenderHelp.h 即可VS 和 PS 之间传参主要使用一个 ShaderContext 的结构体里面都是一堆各种类型的 varying。// 着色器上下文由 VS 设置再由渲染器按像素逐点插值后供 PS 读取
struct ShaderContext {std::mapint, float varying_float; // 浮点数 varying 列表std::mapint, Vec2f varying_vec2f; // 二维矢量 varying 列表std::mapint, Vec3f varying_vec3f; // 三维矢量 varying 列表std::mapint, Vec4f varying_vec4f; // 四维矢量 varying 列表
};
外层需要提供给渲染器 VS 的函数指针并在渲染器的 DrawPrimitive 函数进行顶点初始化时对三角形的三个顶点依次调用// 顶点着色器因为是 C 编写无需传递 attribute传个 0-2 的顶点序号
// 着色器函数直接在外层根据序号读取响应数据即可最后需要返回一个坐标 pos
// 各项 varying 设置到 output 里由渲染器插值后传递给 PS
typedef std::functionVec4f(int index, ShaderContext output) VertexShader;
每次调用时渲染器会依次将三个顶点的编号 0, 1, 2 通过 index 字段传递给 VS 程序方便从外部读取顶点数据。渲染器对三角形内每个需要填充的点调用像素着色器// 像素着色器输入 ShaderContext需要返回 Vec4f 类型的颜色
// 三角形内每个点的 input 具体值会根据前面三个顶点的 output 插值得到
typedef std::functionVec4f(ShaderContext input) PixelShader;
像素着色程序返回的颜色会被绘制到 Frame Buffer 的对应位置。完整例子很简单只需要下面几行代码就能工作了#include RenderHelp.hint main(void)
{// 初始化渲染器和帧缓存大小RenderHelp rh(800, 600);const int VARYING_COLOR 0; // 定义一个 varying 的 key// 顶点数据由 VS 读取如有多个三角形可每次更新 vs_input 再绘制struct { Vec4f pos; Vec4f color; } vs_input[3] {{ { 0.0, 0.7, 0.90, 1}, {1, 0, 0, 1} },{ { -0.6, -0.2, 0.01, 1}, {0, 1, 0, 1} },{ { 0.6, -0.2, 0.01, 1}, {0, 0, 1, 1} },};// 顶点着色器初始化 varying 并返回坐标// 参数 index 是渲染器传入的顶点序号范围 [0, 2] 用于读取顶点数据rh.SetVertexShader([] (int index, ShaderContext output) - Vec4f {output.varying_vec4f[VARYING_COLOR] vs_input[index].color;return vs_input[index].pos; // 直接返回坐标});// 像素着色器返回颜色rh.SetPixelShader([] (ShaderContext input) - Vec4f {return input.varying_vec4f[VARYING_COLOR];});// 渲染并保存rh.DrawPrimitive();rh.SaveFile(output.bmp);return 0;
}
运行后生成一张 output.bmp 图片由于 VS/PS 全部 C 编写因此开发和调试都较方便无需分开单独编译能直接访问各种全局变量能 printf 信息还能断点观察问题。如果 Windows 的话最后你可以加一行system(mspaint output.bmp);
这样每次运行后就能打开画板程序查看最新的渲染效果。有了上面绘制三角形的代码我们可以继续改写载入个模型绘制下直接显示模型纹理光秃秃的太丑加个高洛德着色稍微能看一点像十多年前的网游再加个法向贴图让细节更丰富些看着还行再加层高光看起来不错主要用于验证渲染器有兴趣你可以继续折腾 PBR/BRDF 等高级渲染技巧。渲染器的主要实现原理很简单我在下面这篇文章介绍过OpenGL 和 DirectX 是如何在只知道顶点的情况下得出像素位置的www.zhihu.com两种光栅化的实现方式基于 Edge Walking 和扫描线绘制的适合 CPU 的传统实时软渲染方法和现在这个基于 Edge Equation 的适合 GPU 的方法。前者复杂但是速度快适合 CPU 实时渲染后者简单但是运算量大适合 GPU 并行处理。欢迎参考我十多年前做的另外一个软件渲染器mini3d700 行 C 语言实现实时软件渲染走的是传统 CPU 实时渲染方法其他参考计算机底层是如何访问显卡的 256字节3D程序是如何实现3D引擎的呢 如何进行三角形在齐次空间内的裁剪 --收藏比点赞多一倍怎么回事点个赞那么难么