本例中我们使用的纹理如下:
Bezier曲线大家应该都很熟悉了,Bezier曲线由4个控制点定义,Bezier曲线的数学定义为:
其中,p0~p3定义了4个控制点,b0~b3为伯恩斯坦多项式的项,s的范围为0.0~1.0从而覆盖了曲线上的所有点,如图:
伯恩斯坦多项式的形式如下:
在3D世界中,我们需要用Bezier曲面来代替Bezier曲线,由Bezier曲线扩展到Bezier曲面是十分简单的,只需将4个控制点扩展为4*4控制网格即可,Bezier曲面的数学定义如下:
其中,p0~p15代表4*4控制网格上的16个控制点,b0~b3与Bezier曲线一样,代表伯恩斯坦多项式的项,s与t代表2个方向,范围为0.0~1.0从而覆盖了曲面上的所有点。
关于Bezier曲面的知识了解这些就够了,我们就可以使用它来渲染飘动的红旗了,但是在渲染时,我们还有一个问题需要考虑,就是法线的问题,该如何求曲面上的点的法线呢?
我们知道,导数描述了任一给定点处的曲线的斜率,下图描述了
及其导数的图形表示:
所以,我们只要使用Bezier曲线的导数形式就可以求出对于Bezier曲面上的任一给定点在s和t两个方向上的曲线的斜率,然后使用向量叉积就求得了法线,如图:
有许多求导数的方法,在这里我们使用最简单的形式,我们定义:
的导数形式为
。记住,常数的导数为0。
根据如上的定义,我们就可以得到伯恩斯坦多项式的项的导数的定义:
好了,至此我们已经了解了所有所需的知识,接下来,就是用代码实现的时刻了^-^!
首先我们定义x,z方向上顶点的数量:
1 const int VERTEX_ROW_COUNT = 20;
2 const int VERTEX_COL_COUNT = 20;
接着我们定义顶点结构:
1 struct BEZIER_VERTEX
2 {
3 float x, y, z; //顶点坐标4 float u, v; //纹理坐标5 float Bs0, Bs1, Bs2, Bs3; //关于s的Bernstein多项式的4项的值6 float Bt0, Bt1, Bt2, Bt3; //关于t的Bernstein多项式的4项的值7 float dBs0, dBs1, dBs2, dBs3; //关于s的Bernstein多项式的4项的导数的值8 float dBt0, dBt1, dBt2, dBt3;