笔者介绍:姜雪伟。IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术具体解释》电子工业出版社等。

Avatar换装系统又称为纸娃娃系统。在游戏开发中是使用很广泛的技术。特别是在MMOARPG或者是MMORPG等网络游戏中,玩家创建的3D角色都具有Avatar换装功能,在游戏开发中常常须要对角色更换装备。比方角色在战斗过程中获取到新的盔甲要穿戴在身上或者新的武器要更换等等。

要实现该技术所使用的引擎都必须具有支持Avatar换装系统的骨骼挂节点,比方市面上的Unity引擎,UE4引擎等都提供了这样的挂接骨骼方法。获取到骨骼挂节点后,能够直接将武器挂接到须要绑定的骨骼上。实现的效果例如以下图:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvanh3MTY3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

场景中的三个角色採用了Avatar换装技术。它们採用的是同一套骨架,将须要更换的各个Mesh模型都挂接到相应的骨架上,从而形成了Avatar换装系统。而本书介绍的Cocos2d-x引擎也不例外,该引擎也提供了支持Avatar技术的功能,实现该功能的类是AttachNode。

以下介绍实现挂接结点的步骤,不论是挂接Mesh还是在角色身上挂接武器都须要依据骨骼挂接。这就要用到AttachNode类实现的功能。实现的函数例如以下所看到的:

AttachNode* AttachNode::create(Bone3D* attachBone)
{
auto attachnode = new (std::nothrow) AttachNode();
attachnode->_attachBone = attachBone;
attachnode->autorelease();
return attachnode;
}

首先是创建须要挂接的骨骼,骨骼动画是须要矩阵支撑的。骨骼动画它在世界坐标系中的变换都须要转换到世界变换矩阵,这些实现过程也须要引擎提供,以下把接口的函数给读者展演示样例如以下:

Mat4 AttachNode::getWorldToNodeTransform() const
{
static Mat4 mat;
mat.setIdentity();
auto parent = getParent();
if (parent)
{
mat=parent->getWorldToNodeTransform() * _attachBone->getWorldMat() * Node::getNodeToParentTransform();
}
else
{
mat=_attachBone->getWorldMat() * Node::getNodeToParentTransform();
}
return mat;
}

getWorldToNodeTransform函数的实现原理是把模型挂接到骨骼上,该骨骼是须要挂接模型的父结点,父结点运动会带动所绑的模型运动,从而保证挂接到骨骼结点的武器能够与骨骼动画一致。这个实现过程是与矩阵相关的,通过案例把实现的代码片段给读者展演示样例如以下:

//Girl.c3b里保存了女角色所运行动画的全部零件(姑且这么叫吧)包含衣服,鞋子等等
std::string fileName = "Sprite3DTest/Girl.c3b";
auto sprite = Sprite3D::create(fileName);
sprite->setScale(4);
sprite->setRotation3D(Vec3(0,0,0));
addChild(sprite);
sprite->setPosition( Vec2( p.x, p.y-60) );
auto animation = Animation3D::create(fileName);
if (animation)
{
auto animate = Animate3D::create(animation);
sprite->runAction(RepeatForever::create(animate));
}
_sprite = sprite; _curSkin[SkinType::UPPER_BODY] = "Girl_UpperBody01";
_curSkin[SkinType::PANTS] = "Girl_LowerBody01";
_curSkin[SkinType::SHOES] = "Girl_Shoes01";
_curSkin[SkinType::HAIR] = "Girl_Hair01";
_curSkin[SkinType::FACE] = "Girl_Face01";
_curSkin[SkinType::HAND] = "Girl_Hand01";
_curSkin[SkinType::GLASSES] = "";

上面的代码片段是针对一个模型进行换装操作,首先实现的是对换装的部位进行初始化操作。以下開始遍历获取到骨骼动画挂接的数量,对于挂接的模型,假设是多个通过显示和隐藏将其显示出来。

以下的代码片段函数是ApplySkin,函数内容片段例如以下所看到的:

//函数getMeshCount获取动画全部零件数目  
    for (ssize_t i = 0; i < _sprite->getMeshCount(); i++) {  
        auto mesh = _sprite->getMeshByIndex(static_cast<int>(i));  
        bool isVisible = false;  
        for (auto& it : _curSkin) {  
            if (mesh->getName() == it.second)  
            {  
                isVisible = true;  
                break;  
            }  
        }  
        //通过索引来获取零件并设置可见性  
        _sprite->getMeshByIndex(static_cast<int>(i))->setVisible(isVisible);  
    }  

以下给大家展示应用案例代码例如以下所看到的:

std::string str = _curSkin[SkinType::HAIR];  
    if (str == "Girl_Hair01")  
        _curSkin[SkinType::HAIR] = "Girl_Hair02";  
    else  
        _curSkin[SkinType::HAIR] = "Girl_Hair01"; 

同一时候要调用ApplySkin函数就能够完毕换装的要求。实现效果例如以下图:

Cocos2d-x 3.x 图形学渲染系列十一-LMLPHP

Cocos2d-x 3.x 图形学渲染系列十一-LMLPHP

场景中的角色裤子、头发、鞋子都发生了改变。完毕换装。

关于换装。笔者在CSDN学院出版一个免费的视频讲座《游戏Avatar换装系统》。供开发人员參考。

05-26 16:36