使用这段代码,可以对我们将使用的任何矩阵求逆。
关于Matrix类的内容就是这些,现在这个类对于2D和3D应用程序都适用。接下来就实际使用这个类。
8.5.7 对精灵执行矩阵操作
创建一个新的游戏状态MatrixTestState。这个状态将绘制一个精灵,并对该精灵应用各种矩阵。下面是绘制精灵的代码,你应该已经很熟悉这段代码了。
class MatrixTestState : IGameObject
{
Sprite _faceSprite = new Sprite();
Renderer _renderer = new Renderer();
public MatrixTestState(TextureManager textureManager)
{
_faceSprite.Texture = textureManager.Get("face");
Gl.glEnable(Gl.GL_TEXTURE_2D);
}
public void Render()
{
Gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);
_renderer.DrawSprite(_faceSprite);
_renderer.Render();
}
public void Update(double elapsedTime)
{
}
}
代码中使用了前面章节中用到的脸部精灵。矩阵将在MatrixTestState构造函数中应用到精灵上。
Matrix m = new Matrix();
m.SetRotate(new Vector(0, 0, 1), Math.PI/5);
for (int i = 0; i < _faceSprite.VertexPositions.Length; i++ )
{
_faceSprite.VertexPositions[i] *= m;
}
运行代码,可以注意到脸部已经被旋转过了。旋转是沿着Z轴(0,0,1)执行的,这是从屏幕内部指向外部的轴。把脸部精灵想象成屏幕上的一张纸。为了进行旋转,你在纸上按了一个图钉,使其附着到屏幕上了。图钉就代表Z轴。旋转纸精灵就是在沿着该轴旋转。对于正射投影中的2D对象,Y轴和Z轴对于旋转来说没有什么用处,但是在3D游戏中就不一样了。任何一个归一化的轴都可以用于旋转对象,不只是X、Y和Z这3个主轴。
在代码示例中,旋转量以弧度Math.PI/5给出,这个值等于36°。旋转矩阵将被应用到组成精灵的每个顶点。我们现在已经使用了一个稍微旋转了精灵的矩阵。接下来就添加一个缩放精灵的矩阵。通过使用矩阵乘法,缩放矩阵将与旋转矩阵结合起来。修改构造函数中的已有代码,使其如下所示。
Matrix m = new Matrix();
m.SetRotate(new Vector(0, 0, 1),Math.PI/5);
Matrix mScale = new Matrix();
mScale.SetScale(new Vector(2.0, 2.0, 0.0));
m *= mScale;
for (int i = 0; i < _faceSprite.VertexPositions.Length; i++ )
{
_faceSprite.VertexPositions[i] *= m;
}
这段代码创建的缩放矩阵将对象在X轴和Y轴上放大一倍。这个矩阵和旋转矩阵通过矩阵乘法结合到一起,然后把结果赋值给矩阵m。然后这个合并后的矩阵m被应用到脸部精灵,以缩放和旋转该精灵。矩阵乘法的顺序很重要:将矩阵a和矩阵b相乘的结果不一定与将矩阵b和矩阵a相乘的结果相同。尝试采用不同的矩阵,以熟悉它们之间相互组合后可以得到什么样的结果。
最后的代码段将演示逆矩阵。逆矩阵会逆转一个矩阵操作。如果将旋转-缩放矩阵乘以其逆矩阵,结果将是一个单位矩阵。对精灵应用单位矩阵时,不会产生任何效果。
Matrix m = new Matrix();
m.SetRotate(new Vector(0, 0, 1),Math.PI/5);
Matrix mScale = new Matrix();
mScale.SetScale(new Vector(2.0, 2.0, 2.0));
m *= mScale;
Vector scale = m.GetScale();
m *= m.Inverse();
for (int i = 0; i < _faceSprite.VertexPositions.Length; i++ )
{
_faceSprite.VertexPositions[i] *= m;
}
你还可以尝试平移矩阵,并试着以不同的顺序组合矩阵,看看会得到什么效果。