spine怎么做旋转60帧游戏

在游戏动画中使用spine制作柔性骨骼动画
在游戏动画中使用spine制作柔性骨骼动画
  以下将介绍一些游戏动画里骨骼动画的基础概念,便于对骨骼动画不甚了解的童鞋(比如技术)进行扫盲。已经熟悉骨骼动画的童鞋可以直接跳过。
  动画的基本原理:动画,顾名思义,即是能动的画,画能随着时间的推移进行变换,从而给人产生一种连续在动的感觉。
  在游戏动画里大体有两种制作方式:逐帧动画和补间动画。
  逐帧动画即为每一帧画出一张图,然后通过按照一定速度(帧率,每秒多少帧)来播放这些画好的图,从而达到动画的效果。
  补间动画则比较偷懒,它不为每一帧绘制一张图,而是对一个「动」的形体设置关键帧,而关键帧之间则通过不同的插值算法进行自动补全中间帧的形体的变化轨迹。
相比于逐帧动画,补间动画更加节省图片,使动画运行时的内存更少和最终包的大小更小,同时也减少了原画的工作量,但其画面的表现可能会略逊于逐帧动画。其中的利弊需要开发者进行平衡取舍。
关键帧(key frame)
  关键帧其实就是要动的形体发生「变化」且我们手动记录这些变化的帧,剩余的其他帧则称为补间帧。
  关键帧称为「关键」的原因就是每个补间帧上形体的形变参数都是程序根据其前后两个关键帧自动推导出来的。
  假设形体在第A帧的位置为PA,我们将这帧标记为关键帧,这个动作一般称为“K帧”。然后在第A+N帧,形体的位置我们设置为PN,我们在A+N帧进行K帧。这样我们就有两个关键帧,当我们播放从A到A+N帧的动画时,我们会发现形体会有从PA到PN的一个位移动画。
骨骼动画(skeleton animation)
  想象一个你坐在电脑前打字,你的手指在移动,同时你的手腕也在移动,但是你的躯干却保持不动,你的肘部也固定在桌面上。这一切都是因为你的骨骼驱动了你的肌肉和皮肤,从而使你完成了一系列打字的动作。
  骨骼动画即是利用了这个原理,它是一种补间动画。它由两部分组成:骨骼(bone)和蒙皮(skin/mesh)。
  蒙皮是素材,可以认为是一张贴图,它显示了动画的外在表现。骨骼本身是不可见的,但对其进行形变会带动蒙皮进行各种形变,从而产生出各种看起来比较真实的动画。
蒙皮动画(skinned animation)
  一般情况下,一根骨骼通常跟一个贴图进行绑定,这根骨骼完全控制这张贴图的形变。但是因为是刚性的绑定,在关节移动的时候,容易出现裂缝,如下图。
  随着硬件的能力提升,骨骼动画能对贴图的每个顶点做出形变。称为蒙皮(skin)的圆滑三角形网格会绑定到骨骼上,其三角形的顶点会追踪骨骼的移动而产生相应的移动。蒙皮上的每个顶点可以按照权重绑定到多个骨骼上,从而产生自然的拉伸效果。
  本文最开始提到的腿部柔性弯曲效果就可以利用蒙皮动画来实现。
权重(weights)
  权重是蒙皮上的顶点受到不同骨骼的一个影响因子。其总和为1。想象一下你弯曲你的肘部,试想你肘部靠前臂上的皮肤的一个点,它主要受到前臂骨骼的影响,但是它也受到上臂骨骼的一些影响。假设其受到前臂骨骼的影响占到它总形变的80%,则它的前臂骨骼的权重为0.8,相应的上臂骨骼对它的权重为1 & 0.8 =
0.2,因为其他骨骼对它的影响可以忽略不计。
以上即是权重的直观概括,权重表示了蒙皮受到不同骨骼的对其形变影响占比,合理分配好每个蒙皮顶点的权重至关重要。
在游戏动画中如何利用Spine制作蒙皮动画?(我们以一个男孩的手为例,来讲述如何在Spine中制作这种柔性的蒙皮动画)
确保为SETUP模式,确保选中右边视图中的根骨骼,创建骨骼时必须要选中父骨骼,单击Create按钮,开始依次创建出5根骨骼
创建蒙皮网格
首先,单击创建骨骼的Create按钮,退出骨骼创建模式,选中手部贴(Attachment)勾选其底部的Mesh选项,单击Edit按钮,呼出Edit
Mesh菜单,勾选Edit
Mesh菜单中的Deformed选项,单击Edit Mesh菜单中的Create按钮,开始在手部创建网格顶点,可以单击Edit Mesh菜单中的Modify按钮对顶点进行位移
设置网格点权重
首先,关闭Edit Mesh菜单:,确认勾选的还是手部的贴图,单击Weights按钮,呼出Weights菜单,单击Weights菜单底部的Bind按钮,来绑定骨骼,选择手部的五根骨骼,直到它们都出现Weights菜单里,注意不同的骨骼颜色是不一样的,单击Weights菜单的Auto按钮或者按esc键,来触发Spine的自动权重计算,勾选Weights菜单的Overlay,我们可以看到绑定后的权重热力图
现在我们要让手动起来了,首先,我们需要设置关键帧,让我们在第1帧和第30帧设置好关键帧,这两个关键帧对应的手臂位置是完全一样的,因为我们需要循环播放动画。在这期间,确保左上角的模式处于ANIMATE模式,选中手部的五根骨骼(按住cmd键或control键依次点选),选中第0帧,单击Rotate下的钥匙按钮,我们对手臂的旋转属性设置关键帧,选择第30帧,重复第4步的操作,使第30帧的关键帧与第0帧完全相同,接下来我们只需轻轻旋转手臂,并在0-30帧中间找一个帧当做关键帧即可: 我们选择第15帧作为中间的关键帧。选择第15帧,确保Rotate按钮被选中,向上旋转5根骨骼到一个角度,按下K帧按钮进行关键帧设置,按下播放按钮来预览动画。
好了,以上就是如何在游戏动画中使用spine制作柔性骨骼动画的全部内容啦,有问题的小伙伴可以在下方留言哦!(ps:持续关注,你会有意想不到的收获)
了解更多行业技术干货请关注小编哦~!或咨询QQ:
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。posts - 7,&
comments - 2,&
trackbacks - 0
SPine数据组织
spAtlas:这个是从.atlas文件中解出来的结构,其中包含了纹理
struct spAtlas {
spAtlasPage*
spAtlasRegion*
void* rendererO
先不要管,看它的数据组织,spAtlasPage,spAtlasRegion,rendererObject都是什么东西?往下看
struct spAtlasPage {
const spAtlas*
const char*
spAtlasFilter minFilter, magF
spAtlasWrap uWrap, vW
void* rendererO
int width,
spAtlasPage*
spAtalsPage看它的成员,可以很简单看出,哇哦,这个就是纹理,给你看看真相,哈哈
void _spAtlasPage_createTexture (spAtlasPage* self, const char* path) {
CCTexture2D* texture = CCTextureCache::sharedTextureCache()-&addImage(path);
texture-&retain();
self-&rendererObject =
self-&width = texture-&getPixelsWide();
self-&height = texture-&getPixelsHigh();
看见没有,真相在这里,里面有了纹理的宽,高。奇葩的是他竟然还有(spAtlasPage* next),很明显这是一个链表结构啊,如果你的一个动作文件,用到了多张纹理,那么这个指针就派上用场了。其他暂时忽略,看上面(_spAtlasPage_createTexture)发现没有,这里把纹理给持有了。所以纹理不会释放哦。
struct spAtlasRegion {
const char*
int x, y, width,
float u, v, u2, v2;
int offsetX, offsetY;
int originalWidth, originalH
int/*bool*/
int/*bool*/
spAtlasPage*
spAtlasRegion*
这货一看,就是纹理当中包含的元素,一块,一块的描述信息。
看见这张纹理了吗,它的每一块都应该对应一个(spAtlasRegion)它。
这就是.atlas文件包含的信息啊!就是这样图片怎么怎么分割的,分隔成多少部分。每个部分的坐标是什么。
那个 renderobject是什么东西?我也不清楚,继续看。
spAtlas* spAtlas_create (const char* begin, int length, const char* dir, void* rendererObject) {
const char* end = begin +
int dirLength = strlen(dir);
int needsSlash = dirLength & 0 && dir[dirLength - 1] != '/' && dir[dirLength - 1] != '\\';
spAtlasPage *page = 0;
spAtlasPage *lastPage = 0;
spAtlasRegion *lastRegion = 0;
Str tuple[4];
self = NEW(spAtlas);
self-&rendererObject = rendererO
................
看见没有,亮点在最后一句。创建这个对象的时候,需要传进来一个东西void* rendererObject,然后,这个东西又赋予给了自己 spAtlas*
&&& .......&&& self = NEW(spAtlas);&&& self-&rendererObject = rendererO
然后在外面我的调用是
atlas = spAtlas_createFromFile(atlasFile, 0);& 我竟然传了一个0,哈哈,没有用,暂时到这里。
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
.JSON文件放的就是上面这些spAtlasRegion的树形结构的组织信息,也就是骨架信息,和每个动作信息,每个动作当中每个关键帧中各个Region的数据。哈哈。
先看看,创建的代码
SkeletonRenderer::SkeletonRenderer (const char* skeletonDataFile, const char* atlasFile, float scale) {
initialize();
CTimeMgr::GetInst()-&time_begin("spAtlas_createFromFile");
atlas = spAtlas_createFromFile(atlasFile, 0);
CCAssert(atlas, "Error reading atlas file.");
CTimeMgr::GetInst()-&time_end();
CTimeMgr::GetInst()-&time_begin("spSkeletonJson_create");
spSkeletonJson* json = spSkeletonJson_create(atlas);
CTimeMgr::GetInst()-&time_end();
json-&scale =
CTimeMgr::GetInst()-&time_begin("spSkeletonJson_readSkeletonDataFile");
spSkeletonData* skeletonData = spSkeletonJson_readSkeletonDataFile(json, skeletonDataFile);
CTimeMgr::GetInst()-&time_end();
CCAssert(skeletonData, json-&error ? json-&error : "Error reading skeleton data file.");
spSkeletonJson_dispose(json);
setSkeletonData(skeletonData, true);
atlas = spAtlas_createFromFile(atlasFile, 0);
CCAssert(atlas, "Error reading atlas file.");
spSkeletonJson* json = spSkeletonJson_create(atlas);
json-&scale =
spSkeletonData* skeletonData = spSkeletonJson_readSkeletonDataFile(json, skeletonDataFile);
CCAssert(skeletonData, json-&error ? json-&error : "Error reading skeleton data file.");
spSkeletonJson_dispose(json);
setSkeletonData(skeletonData, true);
if(1)中的内容,是我改的,else里面的内容是原有的。我改的目的,是为了1次加载多次使用,当然别的地方响应的有引用计数的析构了。还是老实的看else中的内容吧。&&&&&&
&&&&& atlas = spAtlas_createFromFile(atlasFile, 0); 这个不用说了吧,我们暂且叫创建纹理图集吧&&&&&&&spSkeletonJson* json = spSkeletonJson_create(atlas); 根据纹理图集,创建一个JSON对象,它就像一个漏斗一样,纹理解析JSON文件准备的,用完就析构了。&&&&&&&json-&scale =&&&&&& spSkeletonData* skeletonData = spSkeletonJson_readSkeletonDataFile(json, skeletonDataFile);解析骨架文件&&&&&&&spSkeletonJson_dispose(json); 漏斗析构了吧&&&&&& setSkeletonData(skeletonData, true); (以上代码在SkeletonRenderer类的构造函数中,所以,看清楚没有,解析出来的spSkeletonData被SkeletonRenderer持有了吧)
spSkeletonData* spSkeletonJson_readSkeletonDataFile (spSkeletonJson* self, const char* path) {
spSkeletonData* skeletonD
const char* json = _spUtil_readFile(path, &length);
if (!json) {
_spSkeletonJson_setError(self, 0, "Unable to read skeleton file: ", path);
skeletonData = spSkeletonJson_readSkeletonData(self, json);
FREE(json);
return skeletonD
这里干啥了,亮点在这句 skeletonData = spSkeletonJson_readSkeletonData(self, json); 反正大家知道这里面解析了JSON文件就可以了!
行了。我们只要知道JSON文件是要给包含骨架组织和动画运动的数据就可以了。而ATLAS文件才是与纹理相关就OK了。我们要做的是让它不持有纹理,想用的时候加载,不想用的时候,把纹理都卸掉就可以了!
假如加载纹理需要40ms,纹理占有内存512*512*4 = 1M,如果我们按照这个目标更改的话。其实是用了40ms换去了1M内存。
速度和内存是需要平衡的。哈哈,我们下面要开始做微创手术了。
阅读(...) 评论()&鍔犺浇涓

我要回帖

更多关于 spine如何做旋转 的文章

 

随机推荐