[从零构建光栅渲染器] 6. 顶点和片元着色器的工作原理

本文通过从零构建光栅渲染器的过程,详细介绍了顶点和片元着色器的工作原理。从Sokolov的教程出发,通过500行C++代码实现,逐步深入讲解三维变换、投影、着色器等内容。通过具体代码示例,解释了着色器如何处理顶点坐标转换和片段颜色计算,展示了Gouraud着色、纹理、法线贴图和镜面贴图的应用。

[从零构建光栅渲染器] 6. 顶点和片元着色器的工作原理

非常感谢和推荐Sokolov的教程,Sokolov使用500行C++代码实现一个光栅渲染器。教程学习过程非常平滑,从画点、线和三角形开始教学,在逐步深入三维变换,投影,再到顶点着色器,片段着色器等等。教程地址:https://github.com/ssloy/tinyrenderer。Sokolov的教程为英文,我翻译了其文章。

在学习过程中,有些内容可能您可能云里雾里,这时就需要查阅《计算机图形学》的书籍了,这里面的算法和公式可以帮助您理解代码。

作者:尹豆(憨豆酒),联系我yindou97@163.com,熟悉图形学,图像处理领域,本章代码: https://github.com/douysu/computer-graphics-notes

本章运行结果

图片

开始

请记住,我的代码只是帮你进行参考,不要用我的代码,写你自己的代码。我是个糟糕的程序员。请你做最疯狂的着色器,并把图片发给我,我会把它们贴在这里。

有趣的时间,首先让我们检查一下我们现在的代码。source code

  • geometry.cpp+.h — 218 行
  • model.cpp+.h — 139 行
  • our_gl.cpp+.h — 102 行
  • main.cpp — 66 行

总共525行,正是我们想要的。请注意,只有our_gl.*和main.cpp两个文件负责实际渲染,总共168行。

图片

重构代码

main.cpp中的代码太多了,让我们分割成两部分:

  • our_gl.h+cpp——这部分开发者接触不到,说白了是OpenGL的library。
  • main.cpp——这是我们想要的重构的。

现在我们应该放什么到our_gl中?ModelView,Viewport 和Projection矩阵初始化函数和三角光栅化。就这些。

下面是文件our_gl.h的内容(我稍后会介绍IShader结构)。

#include "tgaimage.h"
#include "geometry.h"
extern Matrix ModelView;
extern Matrix Viewport;
extern Matrix Projection;
void viewport(int x, int y, int w, int h);
void projection(float coeff=0.f); // coeff = -1/c
void lookat(Vec3f eye, Vec3f center, Vec3f up);
struct IShader {
    virtual ~IShader();
    virtual Vec3i vertex(int iface, int nthvert) = 0;
    virtual bool fragment(Vec3f bar, TGAColor &color) = 0;
};
void triangle(Vec4f *pts, IShader &shader, TGAImage &image, TGAImage &zbuffer);

翻译作者内容:从上面的代码可以看到vertex()方法和fragment()方法,这里就是我们常用的顶点着色器和片元着色器,从这两个函数中,我们可以明白着色器的工作原理。

文件main.cpp现在只有66行,因此我把它完整的列出来(很抱歉代码太长,但我仍然把他完整的列出来,因为我很喜欢它)。

#include <vector>
#include <iostream>
#include "tgaimage.h"
#include "model.h"
#include "geometry.h"
#include "our_gl.h"
Model *model     = NULL;
const int width  = 800;
const int height = 800;
Vec3f light_dir(1,1,1);
Vec3f       eye(1,1,3);
Vec3f    center(0,0,0);
Vec3f        up(0,1,0);
struct GouraudShader : public IShader {
    Vec3f varying_intensity; // written by vertex shader, read by fragment shader
    virtual Vec4f vertex(int iface, int nthvert) {
        varying_intensity[nthvert] = std::max(0.f, model->normal(iface, nthvert)*light_dir); // get diffuse lighting intensity
        Vec4f gl_V
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值