6.4、动画化纹理

随着时间变换model-view坐标系会让渲染对象看起来像是相对于视点移动,反之亦然。随着时间改变纹理坐标系可以动画化几何体的纹理映射过程。示例OpenGLES_Ch6_4会加载并 映射一个半透明纹理到例子OpenGLES_Ch6_3的飘扬旗帜上。这个例子会基于逝去的时间旋转纹理坐标系来产生图6-8中的屏幕截图。

图 6-8

6.4.1 OpenGLES_Ch6_4示例

OpenGLES_Ch6_4ViewController 的“-view- DidLoad”方法会利用下面的代码加载并配置几乎与例子OpenGLES_Ch3_1中的纹理相同的纹理。


CGImageRef imageRef0 = [(UIImage imageNamed:@"RadiusSelectionTool. png" ] CGImage];
GLKTextureInfo *textureInfo0 = [GLKTextureLoader textureWithCGImage: imageRef0 options:nil error:NULL];
self.baseEffect.texture2d0.name = textureInfo0.name;
self.baseEffect.texture2d0.target = textureInfo0.target;

添加到OpenGLES_Ch6_4ViewController 的新方法“-update TextureTransform”会旋转纹理坐标系。回顾一下第3章,纹理坐标系会分别沿着S轴和T轴从0.0跨度到1.0。下面的代码会围绕纹理的中心旋转,具体过程是先平移到{0.5, 0.5}, 然后旋转,最后再平移回{ -0.5, -0.5}。第5章已经讲到过纹理矩阵以及围绕一个点旋转的技巧。


- (void)updateTextureTransform {

    self.baseEffect.textureMatrix2d0 = GLKMatrix4MakeTranslation( 0.5,0.5,0.0);

    self.baseEffect.textureMatrix2d0 = GLKMatrix4Rotate( self.baseEffect.textureMatrix2d0 , self.timeSinceLastResume,1),


    self.baseEffect.textureMatrix2d0 = GLKMatrix4Translate(self.baseEffect.textureMatrix2d0,-0.5,-0.5,0);

}

OpenGLES_Ch6_4ViewController 的“ -update”方法会更新纹理矩阵以及聚光灯的方向,参见下面的代码。


- (void)update
{
    [self updateSpotLightDirections];
    [self updateTextureTransform];
}

这些就是实现纹理旋转需要做的。飘扬旗帜的网格,上的顶点位置的变化和纹理矩阵的变化结合起来产生了一个形象的复杂动画。在例子OpenGLES_Ch6_4 中需要使用AGLKTextureTransformBaseEffect类,这是因为在写作本书时,GLKit内置的GLKBaseEffect类还没有实现纹理矩阵。

6.4.2 OpenGLES_Ch6_5示例

例子OpenGLES_Ch6_5会容纳在纹理贴图集(textureatlas)的单一OpenGLES纹理中的多个2D图像。每个图像都与其他的图像稍有不同,并充当了短片中的一个 帧。当这些帧快速连续地显示时,会呈现出运动的错觉。例子OpenGLES_Ch6_5使用了与OpenGLES_Ch6_4 相同的基本技术来加载和映射一个纹 理到几何图形上,只不过OpenGLES_Ch6_5使用了一个纹理贴图集。

OpenGLES_Ch6_5 的纹理贴图集图像有1024像素宽,1024像素长。它被分为8行,每行128像素高; 8列,每列128像素宽,参见图6-9。在这个纹理贴图集里有64个子图像空间,但在这个例子中只需要51个子图像空间。结果,在图6-9中的最后一行以及倒数第二行的一部分一直没有用到。

图 6-9

下面的常量用来辅助计算每帧动画在纹理贴图集内的位置。


static const int numberofMovieFrames = 51;
static const int numberOfMovieFramesPerRow = 8
static const int numberOfMovieFramesPerColumn = 8;
static const int numberOfFramesPerSecond = 15 ;

和例子OpenGLES_Ch6_4一样,例子OpenGLES_Ch6_5会分配在0.0到1.0范围内的S和T纹理坐标到网格顶点之间。不用对纹理矩阵做任何修改,整个贴图集会被映射到网格几何图形上。但是,这个例子每次只需要渲染一个动画帧覆盖的网格。下面的代码首先平移纹理坐标系,以使原点{0.0, 0.0}对应于当前动画帧的左下角,然后缩放纹理坐标系以使当前帧能够覆盖网格几何体:


- (void)updateTextureTransform {
    int movieFrameNumber = (int)floor (self .timeSinceLastResume * numberOfFr amesPerSecond) %numberOfMovieFrames ;

    GLfloat currentRowPosition = (movieFrameNumber % numberOfMovieFramesPerRow) ★ 1.0f / numberofMovieFramesPerRow;

    GLfloat currentColumnPosition = (movieFrameNumber / numberOfMovieFramesPerColumn) * 1.0f / number0fMovieF ramesPerColumn;

    self baseEffect.textureMatrix2d0 = GLKMatrix4MakeTranslation(
                currentRowPosition,
                currentColumnPosition,
                0.0f);

    self.baseEffect.textureMatrix2d0 =
        GLKMatrix4Scale(
        self.baseEffect.textureMatrix2d0,
        1.0f/numberOfMovieFr amesPerRow,
        1.0f/numberOfMovieFramesPerColumn ,
        1.0f);
}

运行例子OpenGLES_Ch6_5来观察在一个应用中动画的顶点数据、动画的灯光和动画的纹理结合起来的效果。同样,试着随着时间改变例子的视点。例如,使用类似sinf()的一个过滤器或者一个周期性函数来改变GLKMatrix4MakeLookAt()函数的参数。向例子OpenGLES_Ch6_1添加聚光灯来获得一个更加逼真的碰碰车模拟效果。

6.5 小结

除了X、Y和Z坐标系的三个维度之外,动画提供了第四个维度:时间。在本章中介绍的动画方法是多种类型的应用的基础,包括游戏、科学可视化和CocoaTouch用户界面效果等。几乎所有的动画都是通过随着时间变换坐标系来实现的,不管是在一个场景内来回移动一个对象,还是变化聚光灯的方向,或是旋转纹理,又或者以第一人称视点在一个地牢迷宫中来回走动,都是这样。改变顶点属性会产生与本章例子中的飘扬旗帜相似的动画,但是为了获得最佳性能,应该避免频繁地修改顶点数据。

第7章和第8章会扩展在本章中介绍的SceneModel和SceneAnimateMesh类。对于大部分3D应用来说模型是必不可少的,这是因为非主流的、硬编码的顶点数据会很快变得难以控制。第7章会探索比本章中用到的碰碰车、溜冰场和“能够发光”的模型更加复杂的模型。第8章会演示使用尽可能少的运行时处理,来产生逼真的可视效果的多个技术.

results matching ""

    No results matching ""