zoukankan      html  css  js  c++  java
  • OpenGL10-骨骼动画原理篇(3)-Shader版本代码已经上传

    视频教程请关注 http://edu.csdn.net/lecturer/lecturer_detail?lecturer_id=440

    接上一个例程OpenGL10-骨骼动画原理篇(2),对骨骼动画的基本原理做了介绍,接下来

    要对之前做的工作做一个分析和优化,骨骼动画要做大量的数学计算,当一个模型的顶点

    与骨骼的数量都很多的情况下,会消耗大量的cpu时间,接下来要做的事情就是对程序进行

    优化,从上面的计算过程,可以得出,有两个地方的计算量比较大,首先是矩阵和顶点相乘

    ,其次是每一帧要插值新的骨骼出来,相对定点计算来讲,骨骼的插值计算量应该算是较小

    的,一个人物模型少则1000个顶点,多则几千个顶点。因此我们优化就从定点的计算开始

      当然,我们有三种方案,甚至更多(我只用其中的两个)。

      一:使用CPU优化

      二:使用Shader(glsl)优化

      三:使用cuda或者OpenCL进行优化

      先来看第一种,说道cpu优化,大家可能想到两件事情,一是从算法角度出发去优化算法,

    二是使用使用更好的CPU指令进行优化,没错,我们就是要这样做,矩阵相乘的算法优化的空

    间可能已经不大,但是我们采用SIMD指令集和对浮点运算做优化空间还是很大的。

      SIMD:

        (Single Instruction Multiple Data,单指令多数据流)能够复制多个操作数,并把它们打包

    在大型寄存器的一组指令集,例:3DNow!、SSE。以同步方式,在同一时间内执行同一条指令。以

    浮点计算来说,基本上可以到达四倍的加速比。因此采用SIMD可以大幅度的提高性能。cup上使用SIMD

    指令:

      

    __m128 sse_mul_ps(__m128 v, __m128 const m[4])
    {
        __m128 i0 = m[0];
        __m128 i1 = m[1];
        __m128 i2 = m[2];
        __m128 i3 = m[3];
    
        __m128 m0 = _mm_mul_ps(v, i0);
        __m128 m1 = _mm_mul_ps(v, i1);
        __m128 m2 = _mm_mul_ps(v, i2);
        __m128 m3 = _mm_mul_ps(v, i3);
    
        __m128 u0 = _mm_unpacklo_ps(m0, m1);
        __m128 u1 = _mm_unpackhi_ps(m0, m1);
        __m128 a0 = _mm_add_ps(u0, u1);
    
        __m128 u2 = _mm_unpacklo_ps(m2, m3);
        __m128 u3 = _mm_unpackhi_ps(m2, m3);
        __m128 a1 = _mm_add_ps(u2, u3);
    
        __m128 f0 = _mm_movelh_ps(a0, a1);
        __m128 f1 = _mm_movehl_ps(a1, a0);
        __m128 f2 = _mm_add_ps(f0, f1);
    
        return f2;
    }

      采用Shader优化,将矩阵与顶点的计算工作放到丁点Shader中完成,这样做以后,cpu机会完全

    的解放出来,计算量可以忽略不计。然而这种方案也有些弊端,我们知道shader中,不能像cpu中编写

    c++代码那种去动态的申请空间,所有的工作必须提前分配好。看下面的shader实现代码:

    //!    必须提前分配足够大的空间
    uniform mat4 boneMatrices[2];
    
    attribute vec4 weights;
    attribute vec4 matrixIndices;
    attribute vec4 numBones;
    
    
    void main( void )
    {
        vec4 index  = matrixIndices;
        vec4 weight = weights;
    
        vec4 position    = vec4( 0.0, 0.0, 0.0, 0.0 );
    
        for( float i = 0.0; i < numBones.x; i += 1.0 )
        {
            position = position + weight.x * (boneMatrices[int(index.x)] * gl_Vertex);
            index  = index.yzwx;
            weight = weight.yzwx;
        }
        gl_Position = gl_ModelViewProjectionMatrix * position;
    }

      这里不再针对shader做特别介绍,后面将补冲shader相关的例程

      将矩阵数据传递给shader

    //! 使用shader计算顶点的位置
    glUseProgramObjectARB( _programObj );
    glUniformMatrix4fvARB( _boneMatrices_0, 1, false, frame._bone[0].data());
    glUniformMatrix4fvARB( _boneMatrices_1, 1, false, frame._bone[1].data());

    将每一个定点的权重,矩阵的索引,以及矩阵的个数给shader:

                       //! 传递权重
                        fWeights[0] =   g_quadVertices[i * 4 + x].weights[0];
                        fWeights[1] =   g_quadVertices[i * 4 + x].weights[1];
                        glVertexAttrib4fvARB(_weights, fWeights );
    
                        //! 传递索引
                        fMatrixIndices[0]   =   g_quadVertices[i * 4 + x].matrixIndices[0];
                        fMatrixIndices[1]   =   g_quadVertices[i * 4 + x].matrixIndices[1];
                        glVertexAttrib4fvARB(_matrixIndices, fMatrixIndices );
    
                        //! 传递数量
                        fNumBones[0]        =   g_quadVertices[i * 4 + x].numBones; 
                        glVertexAttrib4fvARB(_numBones, fNumBones );

      虽然有这样的缺点,但我们是可以避免的,采用的方式就是:根据动画的骨骼的数量,权重的数量去动态的

    产生shader代码然后进行编译执行,这是一个解决方案,当然我们还有另外一个解决方式,就是首先预先分配

    一些方案,例如当骨头数量小于32个的时候,我们调用一个shader,当在64一下的时候调用另外一个,在多一

    点就调用128的 shader,....

      第三种方案,对你的显卡有很高的要求,必须支持OpenCL或者cuda,才可以去使用他,当然OpenCL或者

    cuda可以直接的访问OpenGL的数据,效率上来说与shader相当(我还没有进行这样的实现),有兴趣的可以进行

    尝试。

      CPU优化版本代码下载(稍后上传,敬请关注)

      Shader优化版本代码下载(稍后上传,敬请关注)

     
  • 相关阅读:
    用VBS脚本查询纯真IP库QQWry.dat(转)
    微软的进程监视器监视进程注册表,文件系统和线程等活动process monitor
    纯真IP库详解(转)
    VBS的开发利器WMI信息绑定参考地址
    VBS去除指定的字符串中的重复项返回重复后的字符串
    WMI中相关的操作说明execquery 或者是instancesof
    VBS字符编码的说明
    VBS中的Asc/AscB/AscW和Chr/ChrB/ChrW函数之间的区别(转)
    随笔我的想法
    关于ANSI字符编码的BUG问题(转)
  • 原文地址:https://www.cnblogs.com/zhanglitong/p/3203178.html
Copyright © 2011-2022 走看看