• 骨骼动画原理与Cocos2d骨骼动画 声明:本文使用的是cocos2d-x-3.17的代码 文章中的提到的测试代码下载地址https://gitee.com/Kyle12/Cocos2dRenderStudy 蒙皮骨骼动画 蒙皮骨骼动画可以分为两部分,蒙皮Skinned ...

    骨骼动画原理与Cocos2d骨骼动画

    声明:本文使用的是cocos2d-x-3.17的代码

    文章中的提到的测试代码下载地址https://gitee.com/Kyle12/Cocos2dRenderStudy

    蒙皮骨骼动画

    蒙皮骨骼动画可以分为两部分,蒙皮Skinned Mesh和骨骼Bone。蒙皮指的是所有的点,骨骼可以控制点的位置,从而形成不同的“姿势”。如下图,图片是使用MeshViewer查看orc.c3b

     

    顶点与骨骼

    顶点会跟随骨骼的移动而移动,对于手臂上的顶点会随手臂骨骼的移动而移动,对于肩膀处的顶点会随肩部骨骼的移动而移动,但对于肩膀手臂连接出的顶点会同时受到肩部骨骼和手臂骨骼的影响。所以顶点是可以同时受到多个骨骼影响时,这种情况下骨骼对顶点的影响会有一个权重比例,骨骼变化后,对点的影响还需要乘以影响的权重。

    在*.c3t 类型3D模型文件如果有骨骼,顶点属性中会有VERTEX_ATTRIB_BLEND_WEIGHT和VERTEX_ATTRIB_BLEND_INDEX属性。VERTEX_ATTRIB_BLEND_INDEX指的是影响顶点骨骼的索引(骨骼会以数组形式存放),VERTEX_ATTRIB_BLEND_WEIGHT指的是骨骼的影响顶点权重。这两个属性size相等,一般都是4,也就是一个顶点最多同时收到4根骨骼影响,如下图:

     

    骨骼与骨架

    骨架Skeleton

    以下是一副骨架

    红点是两个骨骼的连接点,也就是关节点。骨骼有父子关系,一般有一个根骨骼然后其下面有子骨骼,子骨骼往下还有子骨骼的子骨骼,把骨骼按照父子关系连接起来就是一副骨架了。

    骨骼的父子关系作用是当父骨骼变化时其所有子骨骼都会跟着有相同的变化。如下图:

    这个类似于当手臂抬起时,整个手会抬起,和Cocos2d中场景树时一样的,当父节点移动时子节点都会跟着移动。

     

    骨骼Bone

    从骨架图上看整个骨架看上去和人的骨架很像,有手有脚有身体,很容易让我们联想其生物骨骼。骨架中画的每根骨头是为了更好理解骨骼而画的,实际的骨架只是一个骨骼的父子关系,实际的骨骼只是矩阵。在3D空间中,物体的移动缩放旋转都是可以使用矩阵进行变换,矩阵变换实际上是对模型中的各个点进行变换。骨骼的作用是控制模型中点的位置,使得模型有各种各样的姿势,这个功能完全可以用矩阵来实现,骨骼也只需要用矩阵来表示。

     

    模型坐标系和骨骼坐标系

    矩阵对顶点进行变换时,是对顶点坐标所在坐标系进行变换的。对于3D模型来说模型有一个全局坐标系,模型中顶点数据坐标都是在这个坐标系下的。因为骨骼需要控制点,对点进行变换,骨骼也有需要自己的坐标系。对于前面的骨架图,其中的红色的点实际上是骨骼坐标系的原点,绿色的线(看到的骨骼)是按照骨骼父子关系对骨骼原点进行连接。下图展示了模型的全局坐标系与骨骼坐标系:

     

    骨骼与顶点变换

    首先看一下下图,对于的代码SkeletonScene.cpp/SkeletonScene.h,对应程序菜单“Test Draw 3D->Skeleton Draw

    当没有使用骨骼绘制模型时,顶点位置是没有使用骨骼矩阵进行变换的,坐标在模型的全局坐标下。实际绘制的时候不管用不用骨骼绘制,最终绘制使用的的顶点坐标都是模型全局坐标系下的坐标。因为要得到点在全局坐标系下坐标,所以骨骼一定要提供从骨骼坐标系到全局坐标的变换矩阵。前面骨架中说过,骨骼有父子关系,父骨骼改动会影响子骨骼。这个实现的方式是,子骨骼提供一个矩阵,该矩阵可以将子骨骼坐标系下坐标转到父骨骼,父骨骼提供继续往上转换的矩阵,最终根骨骼提供转换到全局坐标系的转换矩阵。这个矩阵也是用来控制点在模型不同姿势”下的位置,变换这个矩阵可以得到不同的“姿势”

    对于模型的顶点数据,顶点坐标都是模型全局坐标系下的坐标,而我们骨骼在对顶点进行变换时要用顶点在骨骼坐标系下的坐标,所以骨骼还需要提供一个矩阵,这个矩阵可以将全局坐标系下的坐标转换到骨骼坐标系的坐标

    所以骨骼需要两个矩阵才能确定最终顶点坐标:一是顶点全局坐标系下到骨骼坐标系下的变换矩阵,二是骨骼坐标系到父骨骼坐标系下变换矩阵,对于根骨骼是根骨骼坐标系到全局坐标系下变换矩阵。实际上为了更好理解还可将第二个矩阵分成两个矩阵,分别是点在当前骨骼坐标系下变动矩阵A将点转化到父骨骼坐标系矩阵B,矩阵B*A得到第二个矩阵,动画中变动的是A矩阵,B矩阵不变动。对于模型中顶点数据绘制时不会改变,第一个顶点坐标从全局坐标系到骨骼坐标系下的变换矩阵也不会改变,只有第二个子骨骼坐标系到父骨骼坐标系变换矩阵是可变的,通过变换这个矩形来实现模型的各种姿势。

    使用骨骼绘制3D模型

    以下是模型orc.c3t(json格式文本文件)的骨骼和骨架数据:

     

    骨骼数据加载后会存放在NodeDatas中,使用Skeleton3D::create(nodeDatas.skeleton)可以创建模型的骨架,使用Skeleton3D对象和模块中的骨骼数据可创建最终MeshSkin,MeshSkin可以创建绘制时候要使用的骨骼矩阵。MeshSkin类数据结构如下:

     

    MeshSkin::_skinBones和MeshSkin::_skeleton. _bones都是Bone3D*指针数组,指向相同的对象,不过MeshSkin::_skinBones是按照模型中骨骼数组顺序排列的。

     

    由于多个矩阵对点的变换可以让矩阵相乘合并成一个变换矩阵,然后对点变换,所以实际绘制时,在Shader中每根骨骼只需要一个变换矩阵就可以了。模块中所有骨骼会以uniform数组形式传递给shader,如果使用了骨骼,shder中由如下定义:

    const int SKINNING_JOINT_COUNT = 60;//骨骼矩阵的最大个数

    uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];//使用3个vec4表示一个骨骼矩阵

    这里使用的时mat4*4的矩阵,原本需要4个vec4才表示mat4*4,但矩阵第四行是齐次空间的变换,因为骨骼不涉及齐次空间,所以省去了。

     

    u_matrixPalette的更新

    programState->setUniformVec4v("u_matrixPalette", (GLsizei)_skin->getMatrixPaletteSize(), _skin->getMatrixPalette())

     

    _skin->getMatrixPalette

    Vec4* MeshSkin::getMatrixPalette()

    {

        if (_matrixPalette == nullptr)

        {

            _matrixPalette = new (std::nothrow) Vec4[_skinBones.size() * PALETTE_ROWS];

        }

        int i = 0, paletteIndex = 0;

        static Mat4 t;

        for (auto it : _skinBones )

    {

        //先用invBindPoses转换到骨骼坐标系下,再转换到全局坐标系下

            Mat4::multiply(it->getWorldMat(), _invBindPoses[i++], &t);

            _matrixPalette[paletteIndex++].set(t.m[0], t.m[4], t.m[8], t.m[12]);

            _matrixPalette[paletteIndex++].set(t.m[1], t.m[5], t.m[9], t.m[13]);

            _matrixPalette[paletteIndex++].set(t.m[2], t.m[6], t.m[10], t.m[14]);

        }

        return _matrixPalette;

    }

     

    it->getWorldMat:

    const Mat4& Bone3D::getWorldMat()

    {

        if (_worldDirty)

        {

            updateLocalMat();

            if (_parent)

            {

                 //先转换到父坐标系下,在继续“往上转”

                _world = _parent->getWorldMat() * _local;

            }

            else

                _world = _local;

            _worldDirty = false;

        }

           return _world;

    }

    完整例子:SkeletonScene.cpp/SkeletonScene.h,对应程序菜单“Test Draw 3D->Skeleton Draw”。

    动画

    动画主要通过改变子骨骼坐标系到父骨骼坐标系矩阵来实现。在3D模型文件中会记录各个骨骼每一帧的矩阵,以下是orc.c3t(json格式文本文件)模型文件中动画

     

    骨骼动画实际也就是根据时间进行切换子骨骼坐标系到父骨骼坐标系的转换矩阵,实际可能会使用插值(线性插值,平方插值等待),使得动画更平滑。Cocos2d中代码结构如下:

     

    例子

    以下例子从动画中抽取了十帧进行显示

    完整代码:AnimationScene.cpp/AnimationScene.h,对应程序菜单“Test Draw 3D->Skeleton Animation”。

     

    附件AttachNode

    有这样一种情况,游戏中一个角色可拾取装备,拾取后要拿在手上,当角色手运动时,装备也需要跟着运动,如下图

    在带骨骼的模型中这这种需要求很容易实现,我们只需要将装备的在手臂的骨骼坐标系下绘制就行,当手臂运动,实际上也就是手臂骨骼坐标系变换,这会带动坐标系下的装备运动。

    展开全文
  • cocos2d 动画实现(帧动画) 2018-08-16 19:43:17
    Vector<SpriteFrame*> Frames; for (int i = 0; i < 7;... auto fileName = StringUtils::format("... auto frame = SpriteFrame::create(fileName, Rect(0, 0, 203, 232));...
  • cocos2d-x三种动画播放 2019-05-25 12:30:13
    #include"cocos2d.h" #include"ui/CocosGUI.h" #include"cocostudio/CocoStudio.h" #include"HelloWorldScene.h" #include"StoryScene.h" using namespace cocos2d::ui; USING_NS_CC; //动画,合图 class C...
  • cocos2d-x 3.x(实现帧动画的几种方法) 方法一(动画帧): //创建一个跑酷的精灵
 auto sprite = Sprite::create("1.png");
 //设置精灵的坐标
 sprite->setPosition(Vec2(visibleSize....
  • Cocos2d-JS动画 2015-03-30 10:49:41
    与动作密不可分的还有动画动画又可以分为场景过渡动画和帧动画。场景过渡动画我们在以往介绍过,这一个我们只介绍帧动画。...在Cocos2d-JS中播放帧动画涉及到两个类:cc.Animation和cc.Animate,类图如下图所示,cc
  • cocos2d-x 骨骼动画详解 2014-02-25 20:33:30
    骨骼动画 vs. 精灵表(sprite sheets)   创建动画又快又简单的方法是使用“精灵表”(sprite sheets).当你意识到游戏需要大量动画,内存消耗会涨上来,而且需要耗时去加载...骨骼动画cocos2d-x动画在人物渲染方面的
  • 这几天折腾我的cocos2d的工程,做了两件事 1. 应用了cocos3d v0.7.1,把几个3d动画,包括pod文件和贴图成功地跑起来了.实现了2d和3d混合的界面. 2. 升级cocos2d,从v1.0.1升级到v2.0.因为openGL的版本不同,还改动了...
  • 其实用过cocos2d-iphone的人,再去学cocos2d-x会学的非常快,我其实就是这么学的。我在用Objective-C之前对C++是一点也不懂的。在学Objective-C之前连什么是面向对象,什么是类都不知道。但是在短短的一年半时间里我...
  • cocos2d-x帧动画实现(续) 2011-11-03 20:18:45
    之前我介绍过cocos2d-x的帧动画实现,今天我把帧动画详细写一下。 帧动画就是很多张png的序列图实现轮流播放产生动画效果。 那么首先我们要一套动画的序列图,没有图的可以看引擎例子里面的图。很多张图我们可以...
  • 使用Cocos2d-x 开发3D游戏 2020-03-15 19:43:18
    由CSDN知名博客讲师火云红孩儿创建的火云开发课堂正式开始讲授新的Cocos2d-x v3.7版本中的3D引擎功能模块!
  • cocos2d中的动画编辑器 2012-12-18 10:18:33
    1.cocos2d中的动画,(10帧的动画为例,每帧长宽6*6,需要展示10个动画,RGBA8888 图片模式) 动画一般是逐帧动画,由一个帧序列构成,每一帧是一张图片 2.成本考虑 制作动画需要考虑的因素:cpu和GPU时间,内存...
  • cocos2d-x骨骼动画使用实例 2016-12-05 19:43:52
    cocos2d-x骨骼动画使用实例
  • cocos2d框架介绍 2011-09-13 10:54:29
    cocos2d引擎 2.0 cocos2d简介 Cocos2d最初的版本是用python写的,之后被改成objectiveC,应用于iphone上,之后国内某人又根据该设计理念,将其改为C++版本cocos2dX,该版本可以在iphone,widnows,andriod三个平
  • Cocos2d-android游戏引擎 2016-11-18 10:44:08
    什么是游戏引擎游戏引擎是指一些已编写好的可编辑游戏系统或者一些交互式...Cocos2d家族cocos2d是一个开源的游戏开发框架,利用它可以非常容易的开发2D游戏。 包括以下成员 Cocos2d-x Cocos2d-iphone Cocos2d-android
  • 在本篇博客中,我们将通过一个在Cocos2d-JS中使用从CocosStudio导出的帧动画资源的例子,来简要介绍以下内容:利用ActionTimeLine进行动画切割,如何使用导出的帧动画资源。关于帧动画,由于内容繁杂。我们将分为两...
  • CocoStudio 是由 Cocos2d-x 官方推出的一个专门针对 Cocos2d-x 游戏开发的免费工具集,目前正在开发阶段,且日益完善之中!既是工具集,当然集成了现有各零零散散工具的功能,并且不断扩充,包含动画编辑器,UI编辑...
  • 一、游戏开发流程。 ①准备游戏引擎 ②准备各类美术资源 ③编写demo,逻辑 ④适配手机,屏幕分辨率,以iPhone4的分辨率为经典。 内存、系统版本。 ⑤优化,性能优化,操作系统...三、Cocos2dCocos2dx Cocos2dx
  • 当前我学习把cocos2d-x应用于Android平台的游戏开发(C++版本)。目前,缺少的是动画编辑器。如果能够把FLASH用作这个平台的动画编辑器那是再理想不过的。我搜索了许多的网站,最终得出如下结论:1,读出FLASH中...
  • quick-cocos2d-x(后文简称 quick)与 cocos2d-x 的关系,用一句话概括:quick 是 cocos2d-x 针对 Lua 的豪华套装威力加强版。 项目地址:quick-cocos2d-x 项目 Wiki: wiki 那 quick 与 cocos2d-x 相比...
  • 说明:cocos2d-x版本为 3.4,CocosStudio版本为2.1.5,C++IDE版本为VC++2012 自己测试了一个下午,没有任何头绪,网络上的资料大部分都是以前的版本,看到界面上可以增加layer。现在的2.1.5都看不到了,所以看了...
1 2 3 4 5 ... 20
收藏数 16,211
精华内容 6,484