OpenGL关键帧动画 - 最好的方法

时间:2009-12-29 18:07:57

标签: android opengl-es

我正在尝试动画对象。我使用关键帧动画:我有两个顶点缓冲区(两个帧),我的对象的顶点 - 第一个缓冲区用于对象开始状态,第二个缓冲区用于结束状态。要转换对象,我只需使用线性插值。
为了使其更清晰,请查看代码段:



FloatBuffer vertexBuffer_motion;
FloatBuffer  vertexBuffer_source, vertexBuffer_destination;
...
int indicesCount = mSphereFrame1.getVertexBuffer().capacity()
...
public void onDrawFrame(GL10 gl) {

   float percentDone = (float)timeSinceStartKeyFrame / (float)animationDuration;   
   //Calculate the new position of each vertex - this is done for each frame
   for (int i = 0; i < indicesCount; i++) {
      float diffIndice = vertexBuffer_destination.get(i) - vertexBuffer_source.get(i);          
      vertexBuffer_motion.put( vertexBuffer_source.get(i) + (percentDone * diffIndice) );           
   }
   ...
   //draw the object
   gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer_motion);
   gl.glDrawElements(GL10.GL_TRIANGLES, mSphereFrame1.getElementsCount(),
                     GL10.GL_UNSIGNED_SHORT, mSphereFrame1.getIndexBuffer());
}

正如您所看到的,我实际上使用了一个缓冲区。 vertexBuffer_motion是我用来在中间状态下绘制对象的那个。

我的问题的时间。
在Android上这种关键帧动画的最佳方法是什么?我可以以某种方式避免(非常耗时)计算并将所有顶点的新状态复制到vertexBuffer_motion的操作吗? 我知道我可以使用VBO但是仍然需要准备这个vertexBuffer_motion并使用glBufferData来设置这个VBO的数据(或者不是?)。 有人能为我提供一些代码示例,展示Android上关键帧动画的最佳方法吗?

谢谢你的阅读。

1 个答案:

答案 0 :(得分:3)

我假设你正在制作一个游戏,如果你不理会速度和位置,其他一切都适用。

你将不得不计算绘制所有内容的位置,并没有真正的捷径。

然而,就复制状态而言,你需要稍微改变一下这个问题。

每个可见的游戏对象(Actor,Doodad等)必须保持它自己的状态,它的位置,要显示的动画帧。我在这里向您展示的方式也会阻止temporal aliasing

作为游戏循环的一部分,您应该首先通过循环更新每个对象,向它们传递自上次更新以来的增量时间,然后每个对象应保持先前和当前状态。当被要求用dt绘制时,那个时间在两个状态之间进行线性插值,以创建一个可绘制的状态。

在计算适当的时间时,您应遵循指南here。是的,这篇文章是关于集成引擎的,但所使用的方法适用于没有它们的游戏,并且允许游戏在没有足够的能力跟上以及永远不会跑得太快的环境中优雅地缩小规模。你脚下的硬件变化。

伪代码:

Abstract Class GameObject {
     private State previous_state;
     private State current_state;
     private State draw_state;

     void Update(float dt) {
          previous_state = current_state.copy();
          current_state = current_state + dt;
     }
     void Draw(float dt) {
          draw_state = interpolate(previous_state, current_state, dt);
          //Do opengl commands to draw draw_state
     }
}

然后你的游戏循环应该如下:

void GameLoop() {
     while(1) {
          //Calculate dt here
          process_inputs();
          for {game_object in object_list} {
               game_object.Update(dt)
          }
          //...
          for {game_object in object_list} {
               game_object.Draw(dt)
          }
 }

每个状态包含描述对象位置,速度和动画帧所需的所有信息。一个简单的State类可能如下所示:

Class State {
     public float position_x;
     public float position_y;
     public float velocity_x;
     public float velocity_y;
     public int frame_number;
     public int max_frame;
     public float animation_duration;  //milliseconds
}

减去两个状态应该产生一个中间状态。向状态添加时间应根据速度计算下一个位置,并确定下一帧动画。