程序员人生 网站导航

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

栏目:综合技术时间:2017-02-20 10:39:32

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

Avatar换装系统又称为纸娃娃系统,在游戏开发中是使用非常广泛的技术,特别是在MMOARPG或是MMORPG等网络游戏中,玩家创建的3D角色都具有Avatar换装功能,在游戏开发中常常需要对角色更换设备,比如角色在战役进程中获得到新的盔甲要穿着在身上或新的武器要更换等等。要实现该技术所使用的引擎都必须具有支持Avatar换装系统的骨骼挂节点,比如市面上的Unity引擎,UE4引擎等都提供了这类挂接骨骼方法,获得到骨骼挂节点后,可以直接将武器挂接到需要绑定的骨骼上。实现的效果以下图:



场景中的3个角色彩用了Avatar换装技术,它们采取的是同1套骨架,将需要更换的各个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函数的实现原理是把模型挂接到骨骼上,该骨骼是需要挂接模型的父结点,父结点运动会带动所绑的模型运动,从而保证挂接到骨骼结点的武器能够与骨骼动画1致。这个实现进程是与矩阵相干的,通过案例把实现的代码片断给读者展现以下:

//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⑹0) );  
		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] = "";  

上面的代码片断是针对1个模型进行换装操作,首先实现的是对换装的部位进行初始化操作。下面开始遍历获得到骨骼动画挂接的数量,对挂接的模型,如果是多个通过显示和隐藏将其显示出来。下面的代码片断函数是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函数就能够完成换装的要求,实现效果以下图:




场景中的角色裤子、头发、鞋子都产生了改变,完成换装。关于换装,笔者在CSDN学院出版1个免费的视频讲座《游戏Avatar换装系统》,供开发者参考。


------分隔线----------------------------
------分隔线----------------------------

最新技术推荐