上一篇我们聊得比较偏理论,这篇我们来实际操作。
渲染管线
在实际动手之前,我们来看看图形API是如何做的。
上图是OpenGL 2的渲染管线,和新版本略有差异,但大体流程是相似的。这里我们主要关注其中的Vertex Shader和Fragment Shader。
Vertex Shader主要负责顶点变换,就是把一个顶点从模型空间变换到裁剪空间,并为后面的Fragment Shader准备相关的数据。Fragment Shader主要负责输出颜色,就是决定一个像素究竟应该输出什么样的颜色。
从Shader开始
我们先定义一个Shader类:
class SimpleShader {
public:
SimpleShader(Matrix4* m_mvp, Matrix4* m_model, TGAImage* image, Vector3 lightDir);
~SimpleShader();
Vector4 vertex(int id, const Vector4& modelPts, const Vector3& uv, const Vector4& normalDir);
TGAColor fragment(const Vector3& bar);
Matrix3 varying_uv;
Matrix4 varying_normal;
private:
SimpleShader(const SimpleShader&);
TGAImage* tgaImage;
Matrix4 uniform_M;
Matrix4 uniform_MIT;
Vector3 light_dir;
};
这个类里有两个函数vertex和fragment,分别对应vertex shader和fragment shader的操作。Shader类的构造函数里传入了四个变量。第一个变量是一个4x4的矩阵,称为MVP矩阵。为什么称为MVP呢?M对应模型变换,V对应观察变换,P对应投影变换,MVP合成一个矩阵就可以直接把顶点从模