书中340页,开始讲到层次模型(关节模型),也就是整个物体,可以自由控制其各部位单独运动,就像关节一样,互不干扰或者有一定关联。
就像图中,左右键控制整个物体(arm1和arm2)的Y轴旋转,上下键控制arm2的X轴旋转。
如果你只是扣教程上的字眼的话,会指出上面这句话是错的,但是如果你理解了教程中的代码之后,你会说我是对的。
一、教程中的相关代码
对于两段手臂,分别是这样画的,首先,传入一个位于(0,0,0)立方体cube的顶点和其他数据(处理颜色的相关数据,如基色、环境色、向量等,这里不做讨论)
arm1:cube沿着Y轴向下移动12个单位距离;
设置Y轴旋转矩阵;
绘制。
arm2:cube沿着Y轴向下移动12个单位距离;
设置Y轴旋转矩阵;
沿着Y轴向上移动10个单位距离;
设置Z轴旋转矩阵;
设置缩放矩阵(矩形变大);
绘制。
我们看到,绘制第二个物体的前两步和第一个是一样的,这是因为在绘制这两个立方体的时候,公用了一个矩阵对象(减少内存开销);
绘制完第一个立方体之后利用平移矩阵将cube移动回原点位置(差2个单位是为了使两个图形有贴合感);
为了使arm2实现按下↑↓的时候实现X轴旋转,因为前面已经有一个Y轴旋转矩阵了,所以要实现最终的X轴旋转,需要加一个Z周旋转矩阵,这就就是代码的189行。
如上图所示A点绕Y轴旋转180度之后到达B点,
那么要实现A点绕X轴旋转180度到达C点,有两种方式:
①直接A点乘以 X轴旋转矩阵到达C点;
②A点乘以 Y轴旋转矩阵 到达B,再乘以 Z轴旋转矩阵到达C点。
第二种也是教程中案例所使用的方法,这种方法减少了内存开销,但是工作量却大了,因为始终都是基于一个矩阵变量做的先后转换,并且对绘制的先后顺序也有一定要求。
二、数个部件下的处理
在上面的例子中,只有两个立方体,它们都是基于一个立方体cube的顶点数据来绘制的,当部件很多并且形状相差很大的时候(不方便用简单的缩放来实现);
那么就需要为每个部件单独提供顶点数据了(用多个缓冲区对象来存储各自的顶点数据),此时他们的绘制过程差不多是这样的(还是使用一个模型矩阵对象):
①所有的部件都是在圆点
②放置第一个部件于最中间(头),并且绘制
③放置身体与最下面,并绘制
④放置嘴巴,并绘制
⑤放置鼻子,并绘制
⑥放置眼睛,并绘制,
这里需要注意,绘制眼睛都是基于上图中蓝色圈往左上方移动一次,绘制一次,然后往右上方移动一次绘制一次;
在这里,为了避免移到左上方再移回来再移到右上方,这里使用了矩阵栈;
对于从蓝色圆位置到左上角的位移矩阵,我们存到一个数组中(模拟入栈),然后画左边眼睛的时候,将蓝色位置的矩阵乘以数组中的位移矩阵从而实现左上方移动;
接下来,我们对数组进行出栈操作(pop),并且push一个右上方移动的矩阵,这样画右边眼睛就可以直接再次将蓝色位置的矩阵乘以数组中的位移矩阵从而实现右上方移动。
就这样,我们用一个矩阵对象完成了对所有部件的绘制工作。