笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。
每一个3D引擎都有对外提供的接口类,这个类主要是用于创建挂接场景中的所有物体,构成场景的树状结构。在Cocos2D-x引擎中,2d使用的是Sprite类,在3D模块中为了辨别2D的Sprite类,新增加了Sprite3D类。该类是用于挂接场景中的3D物体,3D游戏场景中物体组织是树状结构,在逻辑编写中使用的非常多。首先开发者要用Sprite3D类对象创建场景中的物体,3D场景中的物体都是Sprite3D精灵,引擎要做的第1件事情是创建精灵,实现的函数内容以下所示:
Sprite3D* Sprite3D::create(const std::string& modelPath) { CCASSERT(modelPath.length() >= 4, "invalid filename for Sprite3D"); auto sprite = new (std::nothrow) Sprite3D(); if (sprite && sprite->initWithFile(modelPath)) { sprite->_contentSize = sprite->getBoundingBox().size; sprite->autorelease(); return sprite; } CC_SAFE_DELETE(sprite); return nullptr; } Sprite3D* Sprite3D::create(const std::string& modelPath, const std::string& texturePath) { auto sprite = create(modelPath); if (sprite) { sprite->setTexture(texturePath); } return sprite; }
create函数在创建模型时常常用到,创建出可显示的模型,第1个函数的参数是模型的加载路径,第2个函数是模型的加载路径和纹理贴图名字,可更换模型贴图材质。后面会用案例给读者介绍,在上面的函数中提供了初始化模型文件信息函数initWithFile以下所示:
bool Sprite3D::initWithFile(const std::string& path) { _aabbDirty = true; _meshes.clear(); _meshVertexDatas.clear(); CC_SAFE_RELEASE_NULL(_skeleton); removeAllAttachNode(); if (loadFromCache(path)) return true; MeshDatas* meshdatas = new (std::nothrow) MeshDatas(); MaterialDatas* materialdatas = new (std::nothrow) MaterialDatas(); NodeDatas* nodeDatas = new (std::nothrow) NodeDatas(); if (loadFromFile(path, nodeDatas, meshdatas, materialdatas)) { if (initFrom(*nodeDatas, *meshdatas, *materialdatas)) { //加到缓存 auto data = new (std::nothrow) Sprite3DCache::Sprite3DData(); data->materialdatas = materialdatas; data->nodedatas = nodeDatas; data->meshVertexDatas = _meshVertexDatas; for (const auto mesh :_meshes) { data->glProgramStates.pushBack(mesh->getGLProgramState()); } Sprite3DCache::getInstance()->addSprite3DData(path, data); CC_SAFE_DELETE(meshdatas); _contentSize = getBoundingBox().size; return true; } } CC_SAFE_DELETE(meshdatas); CC_SAFE_DELETE(materialdatas); CC_SAFE_DELETE(nodeDatas); return false; }
initWithFile函数是引擎提供的加载模型对外接口,函数功能是实现了加载模型信息比如:材质信息,模型数据信息等。在加载模型之前需要先申请寄存模型顶点数据信息,材质信息,模型的结点信息,这些信息具体实现是在loadFromFile函数中实现的,函数以下所示:
bool Sprite3D::loadFromFile(const std::string& path, NodeDatas* nodedatas, MeshDatas* meshdatas, MaterialDatas* materialdatas) { std::string fullPath = FileUtils::getInstance()->fullPathForFilename(path); std::string ext = FileUtils::getInstance()->getFileExtension(path); if (ext == ".obj") { return Bundle3D::loadObj(*meshdatas, *materialdatas, *nodedatas, fullPath); } else if (ext == ".c3b" || ext == ".c3t") { //加载模型文件 .c3b 或 .c3t auto bundle = Bundle3D::createBundle(); if(!bundle->load(fullPath)) { Bundle3D::destroyBundle(bundle); return false; } auto ret = bundle->loadMeshDatas(*meshdatas) && bundle->loadMaterials(*materialdatas) && bundle->loadNodes(*nodedatas); Bundle3D::destroyBundle(bundle); return ret; } return false; }
bool Bundle3D::load(const std::string& path) { if (path.empty()) return false; if (_path == path) return true; getModelRelativePath(path); bool ret = false; std::string ext = FileUtils::getInstance()->getFileExtension(path); if (ext == ".c3t") { _isBinary = false; ret = loadJson(path); } else if (ext == ".c3b") { _isBinary = true; ret = loadBinary(path); } else { CCLOG("warning: %s is invalid file formate", path.c_str()); } ret?(_path = path):(_path = ""); return ret; }
load函数实现的是利用Bundle3D类提供的加载函数读取模型文件内容,这样利用Sprite3D类提供的接口就能够把模型加载显示出来。
以上展现的函数,开发者在编写逻辑时常常调用到,固然Sprite3D类不但只是提供这几个函数接口。在后面的章节中会详细给读者讲授。下面通过案例给读者展示如何使用Sprite3D类的接口加载模型的代码片断:
Sprite3DForceDepthTest::Sprite3DForceDepthTest() { auto orc = cocos2d::Sprite3D::create("Sprite3DTest/orc.c3b"); orc->setScale(5); orc->setNormalizedPosition(Vec2(.5f,.3f)); orc->setPositionZ(40); orc->setRotation3D(Vec3(0,180,0)); orc->setGlobalZOrder(⑴); addChild(orc); auto ship = Sprite3D::create("Sprite3DTest/boss1.obj"); ship->setScale(5); ship->setTexture("Sprite3DTest/boss.png"); ship->setNormalizedPosition(Vec2(.5,.5)); ship->setRotation3D(Vec3(90,0,0)); ship->setForceDepthWrite(true); addChild(ship); }
在Cocos2D-x引擎中凡是触及到创建模型对象都会与Sprite3D精灵有关系。