Spine Slot 增加 绑定 节点且能保持 与slot的zoder一致
2016-07-04 10:28
751 查看
前言:
在写本文之前曾在网上找过 cocos2dx spine 动画给 动画slot 增加 node 的方法:http://blog.csdn.net/xzben/article/details/50614335 通过这个方法能够基本能实现我们简单的需求,但是有个缺点就是
增加的slot node 都必然在整个动画上面,不能保持原先动画的 slot zorder,于是有了这篇文章的产生。
注意:
本文内容本人还只做了简单的测试,如果还有其它问题欢迎留言。谢谢。
1、spine 的渲染的解析
重回正题,如果我们需要将插入动画slot上的node能够保持原有的zorder必然就只需要在 slot 上插入了node的地方先把之前的渲染好在渲染node在继续渲染就能达到目的。下面就开始动手改代码。
2、实现代码:
1、给对象增加实现接口
2、接口实现
3、修改spine的渲染函数
在写本文之前曾在网上找过 cocos2dx spine 动画给 动画slot 增加 node 的方法:http://blog.csdn.net/xzben/article/details/50614335 通过这个方法能够基本能实现我们简单的需求,但是有个缺点就是
增加的slot node 都必然在整个动画上面,不能保持原先动画的 slot zorder,于是有了这篇文章的产生。
注意:
本文内容本人还只做了简单的测试,如果还有其它问题欢迎留言。谢谢。
1、spine 的渲染的解析
void SkeletonRenderer::drawSkeleton (const Mat4 &transform, uint32_t transformFlags) { getGLProgramState()->apply(transform); // 使用 shader,并指定渲染的 转换矩阵 Color3B nodeColor = getColor(); _skeleton->r = nodeColor.r / (float)255; _skeleton->g = nodeColor.g / (float)255; _skeleton->b = nodeColor.b / (float)255; _skeleton->a = getDisplayedOpacity() / (float)255; int blendMode = -1; Color4B color; const float* uvs = nullptr; int verticesCount = 0; const int* triangles = nullptr; int trianglesCount = 0; float r = 0, g = 0, b = 0, a = 0; for (int i = 0, n = _skeleton->slotsCount; i < n; i++) { //循环所有的 slot spSlot* slot = _skeleton->drawOrder[i]; // 按 slot 的 zorder 逐个遍历渲染 if (!slot->attachment) continue; Texture2D *texture = nullptr; switch (slot->attachment->type) { // 根据 slot 上 附件的类型生成渲染的 各个参数 case SP_ATTACHMENT_REGION: { spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices); texture = getTexture(attachment); uvs = attachment->uvs; verticesCount = 8; triangles = quadTriangles; trianglesCount = 6; 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; } default: ; } if (texture) //有渲染图片才需要渲染 { if (slot->data->blendMode != blendMode) // 对比当前slot 的渲染 blendMode 是否有所变化,如果有所变化就将之前的渲染命令先执行 { _batch->flush(); blendMode = slot->data->blendMode; switch (slot->data->blendMode) { case SP_BLEND_MODE_ADDITIVE: GL::blendFunc(_premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE); break; case SP_BLEND_MODE_MULTIPLY: GL::blendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); break; case SP_BLEND_MODE_SCREEN: GL::blendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); break; default: GL::blendFunc(_blendFunc.src, _blendFunc.dst); } } color.a = _skeleton->a * slot->a * a * 255; float multiplier = _premultipliedAlpha ? color.a : 255; 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(); // debug 相关的绘制 if (_debugSlots || _debugBones) { Director* director = Director::getInstance(); director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, transform); if (_debugSlots) { // Slots. DrawPrimitives::setDrawColor4B(0, 0, 255, 255); glLineWidth(1); Vec2 points[4]; V3F_C4B_T2F_Quad quad; for (int i = 0, n = _skeleton->slotsCount; i < n; i++) { spSlot* slot = _skeleton->drawOrder[i]; if (!slot->attachment || slot->attachment->type != SP_ATTACHMENT_REGION) continue; spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices); points[0] = Vec2(_worldVertices[0], _worldVertices[1]); points[1] = Vec2(_worldVertices[2], _worldVertices[3]); points[2] = Vec2(_worldVertices[4], _worldVertices[5]); points[3] = Vec2(_worldVertices[6], _worldVertices[7]); DrawPrimitives::drawPoly(points, 4, true); } } if (_debugBones) { // Bone lengths. glLineWidth(2); DrawPrimitives::setDrawColor4B(255, 0, 0, 255); for (int i = 0, n = _skeleton->bonesCount; i < n; i++) { spBone *bone = _skeleton->bones[i]; float x = bone->data->length * bone->m00 + bone->worldX; float y = bone->data->length * bone->m10 + bone->worldY; DrawPrimitives::drawLine(Vec2(bone->worldX, bone->worldY), Vec2(x, y)); } // Bone origins. DrawPrimitives::setPointSize(4); DrawPrimitives::setDrawColor4B(0, 0, 255, 255); // Root bone is blue. for (int i = 0, n = _skeleton->bonesCount; i < n; i++) { spBone *bone = _skeleton->bones[i]; DrawPrimitives::drawPoint(Vec2(bone->worldX, bone->worldY)); if (i == 0) DrawPrimitives::setDrawColor4B(0, 255, 0, 255); } } director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); } } void PolygonBatch::add (const Texture2D* addTexture, const float* addVertices, const float* uvs, int addVerticesCount, const int* addTriangles, int addTrianglesCount, Color4B* color) { if ( addTexture != _texture || _verticesCount + (addVerticesCount >> 1) > _capacity || _trianglesCount + addTrianglesCount > _capacity * 3) { this->flush(); _texture = addTexture; } for (int i = 0; i < addTrianglesCount; ++i, ++_trianglesCount) _triangles[_trianglesCount] = addTriangles[i] + _verticesCount; for (int i = 0; i < addVerticesCount; i += 2, ++_verticesCount) { V2F_C4B_T2F* vertex = _vertices + _verticesCount; vertex->vertices.x = addVertices[i]; vertex->vertices.y = addVertices[i + 1]; vertex->colors = *color; vertex->texCoords.u = uvs[i]; vertex->texCoords.v = uvs[i + 1]; } } void PolygonBatch::flush () { if (!_verticesCount) return; GL::bindTexture2D(_texture->getName()); GL::bindVAO(0); glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_POSITION); glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_COLOR); glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_TEX_COORDS); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(V2F_C4B_T2F), &_vertices[0].vertices); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(V2F_C4B_T2F), &_vertices[0].colors); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORDS, 2, GL_FLOAT, GL_FALSE, sizeof(V2F_C4B_T2F), &_vertices[0].texCoords); glDrawElements(GL_TRIANGLES, _trianglesCount, GL_UNSIGNED_SHORT, _triangles); CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, _verticesCount); _verticesCount = 0; _trianglesCount = 0; CHECK_GL_ERROR_DEBUG(); }从上面的代码,可以看出spine的渲染过程其实很简单,就是按照 slot 的zorder 将渲染的 数据加入一个批处理对象 PolygonBatch 中统一执行,只有遇到渲染的图片不在一张纹理上,或者渲染的BlendModel 不同才会分批渲染。从这份代码可以看出spine 的渲染效率是相当的高的。在极限情况下(所有资源都在一张合图上,所有slot的 blendModel都一样的情况下)spine的渲染只需要一次。
重回正题,如果我们需要将插入动画slot上的node能够保持原有的zorder必然就只需要在 slot 上插入了node的地方先把之前的渲染好在渲染node在继续渲染就能达到目的。下面就开始动手改代码。
2、实现代码:
1、给对象增加实现接口
/** Draws a skeleton. */ class SkeletonRenderer: public cocos2d::Node, public cocos2d::BlendProtocol { private: <span style="white-space:pre"> </span>std::vector<cocos2d::Node*><span style="white-space:pre"> </span>m_slotNodes; public: <span style="white-space:pre"> </span>cocos2d::Node* getNodeForSlot(const char* slotName); private: <span style="white-space:pre"> </span>void<span style="white-space:pre"> </span>freeSlotNodes(); <span style="white-space:pre"> </span>void<span style="white-space:pre"> </span>drawSlotNode(const cocos2d::Mat4& transform, uint32_t transformFlags, spSlot* slot);
2、接口实现
void SkeletonRenderer::freeSlotNodes() { for (auto node : m_slotNodes) { node->release(); } } cocos2d::Node* SkeletonRenderer::getNodeForSlot(const char* slotName) { spSlot* slot = findSlot(slotName); if (slot != NULL) { cocos2d::Node* node = cocos2d::Node::create(); if (node != nullptr) { node->setPosition(0, 0); slot->node = node; node->retain(); m_slotNodes.push_back(node); } return node; } return nullptr; } void SkeletonRenderer::drawSlotNode(const cocos2d::Mat4& transform, uint32_t transformFlags, spSlot* slot) { if (slot->node == NULL) return; _batch->flush(); int blendMode = -1; cocos2d::Node* pNode = (cocos2d::Node*)slot->node; blendMode = slot->data->blendMode; cocos2d::BlendFunc func; switch (slot->data->blendMode) { case SP_BLEND_MODE_ADDITIVE: func.src = _premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; func.dst = GL_ONE; break; case SP_BLEND_MODE_MULTIPLY: func.src = GL_DST_COLOR; func.dst = GL_ONE_MINUS_SRC_ALPHA; break; case SP_BLEND_MODE_SCREEN: func.src = GL_ONE; func.dst = GL_ONE_MINUS_SRC_COLOR; break; default: func = _blendFunc; } setNodeBlendFunc(pNode, func); setEnableRecursiveCascadingRGBA(pNode, true); spBone* bone = slot->bone; if (bone != NULL){ pNode->setPosition(ccp(bone->worldX, bone->worldY)); pNode->setRotation(-bone->worldRotation); pNode->setScaleX(bone->worldScaleX); pNode->setScaleY(bone->worldScaleY); } pNode->setOpacity(255 * slot->a); pNode->setColor(ccc3(255 * slot->r, 255 * slot->g, 255 * slot->b)); m_drawRender->clean(); m_drawRender->clearDrawStats(); pNode->visit(m_drawRender, transform, transformFlags); m_drawRender->render(); getGLProgramState()->apply(transform); //最重要的一步,由于渲染node的时候会改变当前的shader,所以最后需要重新恢复。 }
static void setNodeBlendFunc(cocos2d::Node* node, cocos2d::BlendFunc func) { BlendProtocol *ptr = dynamic_cast<BlendProtocol*>(node); if (ptr != nullptr) { ptr->setBlendFunc(func); } for (auto child : node->getChildren()) { setNodeBlendFunc(child, func); } } static void setEnableRecursiveCascadingRGBA(Node* node, bool enable) { CCRGBAProtocol* rgba = dynamic_cast<CCRGBAProtocol*>(node); if (rgba) { rgba->setCascadeColorEnabled(enable); rgba->setCascadeOpacityEnabled(enable); } CCObject* obj; Vector<Node*> children = node->getChildren(); Vector<Node*>::iterator it; for (it = children.begin(); it != children.end(); it++) { Node* child = *it; setEnableRecursiveCascadingRGBA(child, enable); } }
3、修改spine的渲染函数
void SkeletonRenderer::drawSkeleton (const Mat4 &transform, uint32_t transformFlags) { getGLProgramState()->apply(transform); Color3B nodeColor = getColor(); _skeleton->r = nodeColor.r / (float)255; _skeleton->g = nodeColor.g / (float)255; _skeleton->b = nodeColor.b / (float)255; _skeleton->a = getDisplayedOpacity() / (float)255; int blendMode = -1; Color4B color; const float* uvs = nullptr; int verticesCount = 0; const int* triangles = nullptr; int trianglesCount = 0; float r = 0, g = 0, b = 0, a = 0; for (int i = 0, n = _skeleton->slotsCount; i < n; i++) { spSlot* slot = _skeleton->drawOrder[i]; if (!slot->attachment) continue; Texture2D *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 = 8; triangles = quadTriangles; trianglesCount = 6; 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; } default: ; } if (texture) { if (slot->data->blendMode != blendMode) { _batch->flush(); blendMode = slot->data->blendMode; switch (slot->data->blendMode) { case SP_BLEND_MODE_ADDITIVE: GL::blendFunc(_premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE); break; case SP_BLEND_MODE_MULTIPLY: GL::blendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); break; case SP_BLEND_MODE_SCREEN: GL::blendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); break; default: GL::blendFunc(_blendFunc.src, _blendFunc.dst); } } color.a = _skeleton->a * slot->a * a * 255; float multiplier = _premultipliedAlpha ? color.a : 255; 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); } <span style="color:#ff0000;"> drawSlotNode(transform, transformFlags, slot);</span> } _batch->flush(); if (_debugSlots || _debugBones) { Director* director = Director::getInstance(); director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, transform); if (_debugSlots) { // Slots. DrawPrimitives::setDrawColor4B(0, 0, 255, 255); glLineWidth(1); Vec2 points[4]; V3F_C4B_T2F_Quad quad; for (int i = 0, n = _skeleton->slotsCount; i < n; i++) { spSlot* slot = _skeleton->drawOrder[i]; if (!slot->attachment || slot->attachment->type != SP_ATTACHMENT_REGION) continue; spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices); points[0] = Vec2(_worldVertices[0], _worldVertices[1]); points[1] = Vec2(_worldVertices[2], _worldVertices[3]); points[2] = Vec2(_worldVertices[4], _worldVertices[5]); points[3] = Vec2(_worldVertices[6], _worldVertices[7]); DrawPrimitives::drawPoly(points, 4, true); } } if (_debugBones) { // Bone lengths. glLineWidth(2); DrawPrimitives::setDrawColor4B(255, 0, 0, 255); for (int i = 0, n = _skeleton->bonesCount; i < n; i++) { spBone *bone = _skeleton->bones[i]; float x = bone->data->length * bone->m00 + bone->worldX; float y = bone->data->length * bone->m10 + bone->worldY; DrawPrimitives::drawLine(Vec2(bone->worldX, bone->worldY), Vec2(x, y)); } // Bone origins. DrawPrimitives::setPointSize(4); DrawPrimitives::setDrawColor4B(0, 0, 255, 255); // Root bone is blue. for (int i = 0, n = _skeleton->bonesCount; i < n; i++) { spBone *bone = _skeleton->bones[i]; DrawPrimitives::drawPoint(Vec2(bone->worldX, bone->worldY)); if (i == 0) DrawPrimitives::setDrawColor4B(0, 255, 0, 255); } } director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); } }
相关文章推荐
- Android View系统源码分析(十一)—— View.setVisibility(int visibility)
- BCGSoft Demo示例展示:菜单示例集合(2/2)
- Caused by: java.net.UnknownHostException
- 邮件收发POP3/IMAP/SMTP常用端口
- 面试题10:二进制中1的个数
- 查看Linux系统架构类型的5条常用命令
- 在Python中用小波分析图像的哈希值
- rsync启动异常
- studio多渠道打包
- NYOJ 221 Tree (二叉树遍历)
- 解决Odoo 8 PDF报表中文字体乱码问题
- linux命令 cp
- Texture Addressing Modes
- 团体程序设计天梯赛-练习集L1-013. 计算阶乘和
- web前端简单布局
- Android View系统源码分析(十)—— View.setVisibility(int visibility)
- Ruby: attr_reader &attr_accessor用法
- idea 15.0.2下载及破解
- 关于跨域获取cookie问题的解决
- 沉浸式