筆者介紹:姜雪偉,IT公司技術(shù)合伙人,IT高級講師,CSDN社區(qū)專家,特邀編輯,暢銷書作者,國家專利發(fā)明人;已出版書籍:《手把手教你架構(gòu)3D游戲引擎》電子工業(yè)出版社和《Unity3D實戰(zhàn)核心技術(shù)詳解》電子工業(yè)出版社等。
每一個3D引擎都有對外提供的接口類,這個類主要是用于創(chuàng)建掛接場景中的所有物體,構(gòu)成場景的樹狀結(jié)構(gòu)。在Cocos2D-x引擎中,2d使用的是Sprite類,在3D模塊中為了辨別2D的Sprite類,新增加了Sprite3D類。該類是用于掛接場景中的3D物體,3D游戲場景中物體組織是樹狀結(jié)構(gòu),在邏輯編寫中使用的非常多。首先開發(fā)者要用Sprite3D類對象創(chuàng)建場景中的物體,3D場景中的物體都是Sprite3D精靈,引擎要做的第1件事情是創(chuàng)建精靈,實現(xiàn)的函數(shù)內(nèi)容以下所示:
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函數(shù)在創(chuàng)建模型時常常用到,創(chuàng)建出可顯示的模型,第1個函數(shù)的參數(shù)是模型的加載路徑,第2個函數(shù)是模型的加載路徑和紋理貼圖名字,可更換模型貼圖材質(zhì)。后面會用案例給讀者介紹,在上面的函數(shù)中提供了初始化模型文件信息函數(shù)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函數(shù)是引擎提供的加載模型對外接口,函數(shù)功能是實現(xiàn)了加載模型信息比如:材質(zhì)信息,模型數(shù)據(jù)信息等。在加載模型之前需要先申請寄存模型頂點數(shù)據(jù)信息,材質(zhì)信息,模型的結(jié)點信息,這些信息具體實現(xiàn)是在loadFromFile函數(shù)中實現(xiàn)的,函數(shù)以下所示:
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函數(shù)實現(xiàn)的是利用Bundle3D類提供的加載函數(shù)讀取模型文件內(nèi)容,這樣利用Sprite3D類提供的接口就能夠把模型加載顯示出來。
以上展現(xiàn)的函數(shù),開發(fā)者在編寫邏輯時常常調(diào)用到,固然Sprite3D類不但只是提供這幾個函數(shù)接口。在后面的章節(jié)中會詳細給讀者講授。下面通過案例給讀者展示如何使用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引擎中凡是觸及到創(chuàng)建模型對象都會與Sprite3D精靈有關(guān)系。