zoukankan      html  css  js  c++  java
  • OpenGL10-骨骼动画原理篇(2)

    接上一篇的内容,上一篇,简单的介绍了,骨骼动画的原理,给出来一个

    简单的例程,这一例程将给展示一个最初级的人物动画,具备多细节内容

    以人走路为例子,当人走路的从一个站立开始,到迈出一步,这个过程是

    一个连续的过程,在这个一个过程中,人身体的骨头在位置在发生变化,

    骨头发生变化以后,人的皮肤,肌肉就随着变化,上一个例程中我们计算

    (OpenGL10-骨骼动画原理篇(1))计算了根据骨头的位置计算皮肤的位置

    只是计算量一刻的动作,走路的过程是连续的,就意味着我们要记录下来

    骨头在运动过程中所以位置变化数据,这样才可以根据不同时刻的骨骼的

    位置计算出来皮肤的位置。

    现在问题出来了,如果美术做了一个动画有5秒钟,每一秒播放60帧来

    计算,我们要记录非常多的骨头的信息,小下面这样:

    假设人有100个骨头

    Bone person[100]

    一秒钟60帧 × 5秒  × 100,这个就是我们要记录的数据量,由此可见

    数据量是非常大的,实际上大可不必这样做,想一,是否可以记录一个

    关键帧的,其他的数据又关键帧来计算呢 ?假设我们记录了10个关键点

    其他的数据根据时间按照一定的插值算法进行插值,那么数据量就骤然

    降低非常多呢。出于这样的想法,我们增加了一个新的概念,关键帧。

    骨骼动画系统的流程如下:

      下面我们使用程序的角度来描述下该问题:

    1.  获取到所有的骨骼数据(可使用矩阵存储)

    Bone   bones[n];

    2.  获取到关键帧数据

    Bone  arKeyFrame[n][KeyNumber];

    3  获取到皮肤(顶点数据)

    Vertex  verts[vNumber];

    4  通过插值计算出来新的骨骼位置

    Bone   timeBone[n];

    5  根据计算出来骨骼来计算顶点数据

    Vert  temp[vNumber];

    一个定点的声明如下:

    struct Vertex

    //! 颜色 
    float r, g, b, a; 
    //! 位置
    float x, y, z; 
    //! 影响度 
    float weights[2]; 
    //! 矩阵的索引 
    short matrixIndices[2]; 
    //! 影响整个定点的骨头个数 
    short numBones;
    };

      

    声明一个类,保存骨头的信息.类如下所示,该类保存动画的所有骨格信息:

    struct Vertex
    {
        //! 颜色
        float r, g, b, a;
        //! 位置
        float x, y, z;
        //! 影响度
        float weights[2];
        //! 矩阵的索引
        short matrixIndices[2];
        //! 影响整个定点的骨头个数
        short numBones;
    };

      接下来,声明一动画类,动画类中维护关键帧数据

    class   Frame
    {
    public:
        tmat4x4<float> _bone[2];
    };

     一个动画类,用来保存所有的关键帧数据,提供计算骨头插值算法,

    并输出一帧的骨骼数据,类如下所示。

    class   SkinAnimation
    {
    public:
        //! 根据给定的时间,输出一帧骨骼的数据
        void    calcFrame(float t,Frame& frame)
        {
           
            frame._bone[0]  =   interpolate(_keyFrame[0]._bone[0],_keyFrame[1]._bone[0],t);
            frame._bone[1]  =   interpolate(_keyFrame[0]._bone[1],_keyFrame[1]._bone[1],t);
            
        }
        //!  该动画有两个关键帧
        Frame   _keyFrame[2];
    };

      调用方式如下:

                    /**
                    *   产生时间
                    */
                    static  float   xxx =   0;
                    
                    /**
                    *   根据关键帧计算出来新的骨骼位置
                    */
                    _skinAnima.calcFrame(xxx,frame);
                    xxx +=  0.01f;

      然后我们将定点数据与计算出来的骨骼数据计算,得出最后的皮肤数据:

    /**
    *   绘制表皮,保存临时点数据
    *   这里根据新的骨头的(就是插值计算出来以后的骨头来计算皮肤的位置了)
    */
    Vertex  calQuadVertices[12];
    memcpy(calQuadVertices,g_quadVertices,sizeof(g_quadVertices));
    for (int i = 0 ;i < 12 ; ++ i )
    {
        tvec3<float>    vec(0,0,0);
        tvec3<float>    vecSrc(g_quadVertices[i].x,g_quadVertices[i].y,g_quadVertices[i].z);
        for (int x = 0 ; x < calQuadVertices[i].numBones ; ++ x)
        {
            //! 计算位置
            tvec3<float>    temp    =   vecSrc* frame._bone[g_quadVertices[i].matrixIndices[x]];
            //! 计算权重位置
            vec  += temp * g_quadVertices[i].weights[x];
        }
        calQuadVertices[i].x    =   vec.x;
        calQuadVertices[i].y    =   vec.y;
        calQuadVertices[i].z    =   vec.z;
    }

      最后将计算出来的数据给OpenGL,进行绘制了:

    glColorPointer(4,GL_FLOAT,sizeof(Vertex),calQuadVertices);
    glVertexPointer(3,GL_FLOAT,sizeof(Vertex),((float*)calQuadVertices) + 4);
    for (int i = 0 ;i < 3 ; ++ i )
    {
        glDrawArrays(GL_LINE_LOOP,i * 4,4);
    }

      

    可执行文件以及代码

  • 相关阅读:
    lucene .NET 搜索图片 功能实现
    (转)权威支持: 选择正确的 WebSphere 诊断工具
    (转)WebSphere 中池资源调优
    (转)使用 DB2 HADR 选择用于灾难恢复的 SUPERASYNC 模式
    (转) DB2 HADR
    (转)DB2 HADR 监控详解
    (转)python高级FTP
    (转)Python的web服务器
    (转)python通过paramiko实现,ssh功能
    (转)request模拟知乎登录(无验证码机制
  • 原文地址:https://www.cnblogs.com/zhanglitong/p/3201972.html
Copyright © 2011-2022 走看看