代码之家  ›  专栏  ›  技术社区  ›  Ramps

OpenGL关键帧动画-最佳方法

  •  1
  • Ramps  · 技术社区  · 16 年前

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

    
    
    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运动的操作?
    我知道我可以使用vbo,但我仍然需要准备这个VertexBuffer_动作,并使用glBufferData将数据设置为vbo(或不?). 有人能给我提供一些代码示例,展示Android上关键帧动画的最佳方法吗?

    谢谢你的阅读。

    1 回复  |  直到 16 年前
        1
  •  3
  •   Dinedal    16 年前

    我假设你在做一个游戏,如果你不忽略速度和位置,其他一切都适用。

    你得计算出在哪里画出所有的东西,其实没有捷径可走。

    但是,就复制状态而言,您需要以稍微不同的方式处理问题。

    每个可见的游戏对象(演员、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)
              }
     }
    

    每个状态都包含描述对象位置、速度和动画帧所需的所有信息。一个简单的状态类可能看起来像:

    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
    }
    

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