cocos2d下,优秀骨骼spine的换装思路
语文老师说,文章要有个好开头!!!
最近正在引入spine骨骼代替dragon bone骨骼,既然要替代,那么原先在dragon bone上的一些额外需求,不管dragon bone上能不能实现,都应该在spine上尝试一番.
说带换装,spine自带的皮肤可以实现整体换装,这个应该不用介绍,setSkin一下就ok了.但是,策划往往会需要用到局部换装,一种情况下是该部件本身存在于皮肤下,这种情况下,只要能得到目标skin,目标slot,拿到目标相应的attachment , 替换一下即可 。
///////////////////////
//替换另一个皮肤下的某个部件
//for (int i = 0; i < skeleton->data->skinsCount; i++)
//{
// if(! strcmp(skins[i]->name,"goblingirl"))
// {
// int index = spSkeleton_findSlotIndex(skeleton,"head");
// attachment = spSkin_getAttachment(skins[i],index,"head");
// spSlot_setAttachment(goblin->findSlot("head"),attachment);
// }
//}
//////////////////////
方法不止一种,但思路都是一样的,这样就解决了皮肤间单独换装的问题。
最后一种最坑爹的需求就是希望能把一个自己的纹理放到骨骼中的某个部位。这个需求当时去网上找并没有找到什么有效的方法。自己摸索了一下大致是做出来了。
首先顺藤摸瓜,看看SkeletonRenderer是怎么渲染出整个骨骼动画的。在draw()方法下出现了某段代码:
for (int i = , n = skeleton->slotsCount; i < n; i++) {
spSlot* slot = skeleton->drawOrder[i];
if (!slot->attachment) continue;
CCTexture2D *texture = nullptr;
switch (slot->attachment->type) {
case SP_ATTACHMENT_REGION: {
spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment;
spRegionAttachment_computeWorldVertices(attachment, slot->bone, worldVertices);
texture = getTexture(attachment);
uvs = attachment->uvs;
verticesCount = ;
triangles = quadTriangles;
trianglesCount = ;
r = attachment->r;
g = attachment->g;
b = attachment->b;
a = attachment->a;
break;
}
case SP_ATTACHMENT_MESH: {
spMeshAttachment* attachment = (spMeshAttachment*)slot->attachment;
spMeshAttachment_computeWorldVertices(attachment, slot, worldVertices);
texture = getTexture(attachment);
uvs = attachment->uvs;
verticesCount = attachment->verticesCount;
triangles = attachment->triangles;
trianglesCount = attachment->trianglesCount;
r = attachment->r;
g = attachment->g;
b = attachment->b;
a = attachment->a;
break;
}
case SP_ATTACHMENT_SKINNED_MESH: {
spSkinnedMeshAttachment* attachment = (spSkinnedMeshAttachment*)slot->attachment;
spSkinnedMeshAttachment_computeWorldVertices(attachment, slot, worldVertices);
texture = getTexture(attachment);
uvs = attachment->uvs;
verticesCount = attachment->uvsCount;
triangles = attachment->triangles;
trianglesCount = attachment->trianglesCount;
r = attachment->r;
g = attachment->g;
b = attachment->b;
a = attachment->a;
break;
}
}
if (texture) {
if (slot->data->blendMode != blendMode) {
batch->flush();
blendMode = slot->data->blendMode;
switch (slot->data->blendMode) {
case SP_BLEND_MODE_ADDITIVE:
ccGLBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE);
break;
case SP_BLEND_MODE_MULTIPLY:
ccGLBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
break;
case SP_BLEND_MODE_SCREEN:
ccGLBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
break;
default:
ccGLBlendFunc(blendFunc.src, blendFunc.dst);
}
}
color.a = skeleton->a * slot->a * a * ;
float multiplier = premultipliedAlpha ? color.a : ;
color.r = skeleton->r * slot->r * r * multiplier;
color.g = skeleton->g * slot->g * g * multiplier;
color.b = skeleton->b * slot->b * b * multiplier;
batch->add(texture, worldVertices, uvs, verticesCount, triangles, trianglesCount, &color);
}
}
batch->flush();
代码比较长,其实是遍历了所有slot,取出其下的attachment,根据type属性强转成对应类型的attachment计算或取出不同类型attachment渲染所需要的数据然后取出纹理根据数据进行渲染。
比较关键的一步是取出纹理,看到这步仿佛看到了春天,于是我写代码 把这个纹理取出来,创建成精灵显示在场景下时才发现,attachment->rendererObject->page->rendererObject 这个东西根本不是一个部位的纹理,所有部位的纹理取出来都是纹理集整个纹理,也就是像下面这样的大纹理。
其他平台的情况本人并不是很清楚,但是在cocos2d-x下,spine的骨骼动画是一个node读取了大量的数据,一个纹理渲染出来,所以并不存在可以获得单个纹理的接口。spine并没有专门对cocos2d-x做处理,而是从一大堆C语言写的代码上加了一个Node就完成了。
在此坑爹的情况下,此时的我是崩溃的。
我去spine详细地读了那篇用English写的简单文档.结合底层坑爹C语言代码后发现attachment->rendererObject实际上存放的是区域信息AtlasRegion,而Atlas Region下page则是页信息,page再向上一级就是最大的atlas,一个骨骼有一个atlas(暂时的想法是这样子的)而一个atlas有多个page,上图纹理集就是一个page,所以理论上而言可以用代码定义一个并不存在的page 将图片信息写入page->region->rendererObject,再将region定义出一个attachment放入slot中,渲染时就会顺着attachment->rendererObject->page->rendererObject一条线路读取到我们所放入的纹理。而其中复杂的数据如果顺序错误或遗漏则会引起渲染的结果畸形。
CCTexture2D* pTexture = CCTextureCache::sharedTextureCache()->addImage("CloseSelected.png");
int attachmentType = slot->attachment->type;;
switch (attachmentType)
{
case SP_ATTACHMENT_REGION:{ break;}
case SP_ATTACHMENT_MESH:{
spMeshAttachment* attachment = (spMeshAttachment*)slot->attachment;
spAtlas* atlas = goblin->getAtlas();
spAtlasPage* page = atlas->pages;
spAtlasPage* newPage = spAtlasPage_create(atlas , "goblins-test.png");
spAtlasRegion* region = ((spAtlasRegion*)attachment->rendererObject);
spAtlasRegion* newRegion = spAtlasRegion_create();
CCTexture2D* newTexture = CCTextureCache::sharedTextureCache()->addImage("goblin-test4.png");
newPage->format = page->format;
newPage->magFilter = page->magFilter;
newPage->minFilter = page->minFilter;
newPage->name = page->name;
newPage->rendererObject = newTexture;
//newPage->rendererObject = NULL;
newPage->width = ;
newPage->height = ;
newPage->uWrap = page->uWrap;
newPage->vWrap = page->vWrap;
newRegion->height= newPage->height;
newRegion->width = newRegion->width;
newRegion->offsetX = ;
newRegion->offsetY = ;
newRegion->originalHeight = newRegion->height;
newRegion->originalWidth = newRegion->width;
newRegion->name = region->name;
newRegion->u = ;
newRegion->v = ;
newRegion->u2 = ;
newRegion->v2 = ;
newRegion->page = newPage;
attachment->rendererObject = newRegion;
attachment->regionU = newRegion->u;
attachment->regionV = newRegion->v;
attachment->regionU2 = newRegion->u2;
attachment->regionV2 = newRegion->v2;
attachment->regionRotate = newRegion->rotate;
attachment->regionOffsetX = newRegion->offsetX;
attachment->regionOffsetY = newRegion->offsetY;
attachment->regionWidth = newRegion->width;
attachment->regionHeight = newRegion->height;
attachment->regionOriginalWidth = newRegion->originalWidth;
attachment->regionOriginalHeight = newRegion->originalHeight;
attachment->regionHeight = newRegion->height; spMeshAttachment_updateUVs(attachment); break;}
case SP_ATTACHMENT_SKINNED_MESH:{
spSkinnedMeshAttachment* attachment = (spSkinnedMeshAttachment*)slot->attachment;
((spAtlasRegion*)attachment->rendererObject)->page->rendererObject = pTexture; break;}
default:{
CCLog("%s" , "undisposed attachment type !~~~~ ");
break;}
}
以上是其中一种类型的attachment,经过上述实验后,我自己做的纹理成功地被替换到骨骼中 并且一切动作都正常,蒙皮效果也是正常的,但是可能由于数据并不够完整,新加入的纹理必须和原来的骨骼中相应部位的纹理一样大小,其实这也是可以理解的,如果大小不一样,原来的蒙皮会扭曲新纹理,从而出现畸形,可能其他类型的attachment如region类型可以实现替换的图像大于原大小,但是这种类型没有蒙皮效果也就是没有Mesh网格渲染效果,不够柔软,这样就失去了spine的特色。
--MT.Team
--MT.Lambda
cocos2d下,优秀骨骼spine的换装思路的更多相关文章
- Unity 带骨骼的人体模型换装
直入主题: 1.实验材料 两个模型,虽然缺胳膊少腿的,但是能用!!! 2.条件 两个模型在制作时是基于同一套骨骼,导出模型部位时连着该部位的骨骼一起导出,这样导入到Unity的模型就带有Skinned ...
- Unity动态换装之Spine换装
注:转载请注明转载,并附原链接 http://www.cnblogs.com/liaoguipeng/p/5867510.html 燕双飞情侣 一.动态换装原理 换装,无非就是对模型的网格,或者贴图进 ...
- Unity3d 3d角色换装实现原理及步骤
http://www.cnblogs.com/dosomething/archive/2012/04/15/2450526.html 1.角色模型制作 unity3d支持Skin动画 但是不支持Ph ...
- 【Unity3d】3d角色换装实现原理及步骤
http://www.cnblogs.com/dosomething/archive/2012/04/15/2450526.html 1.角色模型制作 unity3d支持Skin动画 但是不支持Ph ...
- Unity 之 人物换装
http://www.cnblogs.com/mcwind/archive/2011/02/18/1957453.html 原理 一. SkinedMeshRender:该对象负责网格绘制.主要数据 ...
- 浅谈角色换装功能--Unity简单例子实现
在前置篇中,基本上梳理了一下换装功能背后涉及到的美术工作流.但程序员嘛,功能终归是要落到代码上的.本文中会结合Unity提供的API及之前提到的内容来实现一个简单的换装功能.效果如下: (图1:最终效 ...
- 【Unity3D】3D角色换装++ Advance
http://www.cnblogs.com/dosomething/archive/2012/12/15/2818897.html 本文在之前的文章Unity3D角色换装的原理 基础上做一个补充 给 ...
- Blender建模与游戏换装(转载文)
本文转载自https://my.oschina.net/huliqing/blog/880113?hmsr=toutiao.io 如果本文涉及侵权行为,请原作者联系博主邮箱,我将及时进行删除处理 博主 ...
- unity 角色换装
unity角色换装的关键是更改角色部位上的物体的SkinnedMeshRenderer组件的属性: 更改mesh:mesh决定了部位的物体的外形,是主要的数据. 刷新骨骼:同一个部位下,不同的mesh ...
随机推荐
- css3 text-transform变形动画
详细内容请点击 版本:CSS1 兼容性:IE4+ NS4+ 继承性:有 语法: text-transform : none | capitalize| uppercase| lowercase 参数: ...
- 【CSS3】---结构性伪类选择器-root+not+empty+target
结构性伪类选择器—root :root选择器,从字面上我们就可以很清楚的理解是根选择器,他的意思就是匹配元素E所在文档的根元素.在HTML文档中,根元素始终是<html>. 示例演示: 通 ...
- 计算日期时间 自动加1天 PHP计算闰年 java与PHP时间戳对比区别
昨天写一个同步数据库的模块 从一个数据库同步到另外一个数据库,因为数据较多,不可能一次性全部搬迁过去,所以就按照每天搬迁! 写了一个 模块,点击加1,只要点击一次,自动从A数据库取出1天的数据, 并 ...
- NAT
WRITE BY YANGWJ 一. 配置静态Nat 实验图如下: 1. 将网络基本条件配置好,包括路由要可达,即pc1可以ping到server1 2. ...
- WCF学习笔记(2)——使用IIS承载WCF服务
通过前面的笔记我们知道WCF服务是不能独立存在,必须“寄宿”于其他的应用程序中,承载WCF服务的应用程序我们称之为“宿主”.WCF的多种可选宿主,其中比较常见的就是承载于IIS服务中,在这里我们来学习 ...
- Cocos2d-JS中的文本菜单
文本菜单是菜单项只能显示文本,文本菜单类包括了cc.MenuItemLabel.cc.MenuItemFont和cc.MenuItemAtlasFont.cc.MenuItemLabel是个抽象类,具 ...
- c#扩展方法-摘自msdn
扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型. 扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用. 对于用 C# 和 Vis ...
- (转)RabbitMQ消息队列(三):任务分发机制
在上篇文章中,我们解决了从发送端(Producer)向接收端(Consumer)发送“Hello World”的问题.在实际的应用场景中,这是远远不够的.从本篇文章开始,我们将结合更加实际的应用场景来 ...
- vlan知识
为什么需要VLAN 1. 什么是VLAN? VLAN(Virtual LAN),翻译成中文是“虚拟局域网”.LAN可以是由少数几台家用计算机构成的网络,也可以是数以百计的计算机构成的企业网络.VLAN ...
- Bootstrap轮播获取当前活动的焦点对象
在项目中使用了Bootstrap的轮播,需求是轮播下方有一个已读按钮,当点击已读按钮时,隐藏掉当前的焦点的轮播内容: 如图所示: 所以要获取当前的焦点是哪一条: 下方代码是在网络上找到的一个方 ...