Spine Slot 增加 绑定 节点且能保持 与slot的zoder一致

来源:互联网 发布:安卓看本子软件 编辑:程序博客网 时间:2024/06/05 10:18

 前言:

在写本文之前曾在网上找过 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++) {  //循环所有的 slotspSlot* 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);}}



0 0
原创粉丝点击