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

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

3572次

笔者介绍:姜雪伟,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;
}

loadFromFile函数提供了加载Cocos2d-x引擎支持的3类模型:obj模型,c3t模型,c3b模型,以c3b或c3t为例,模型文件是2进制和json文件,数据的加载是在Bundle3D类实现的,调用的接口是load函数,函数接口实现以下:

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);
}

在Sprite3DForceDepthTest函数中首先调用Sprite3D类的接口create函数创建出模型,创建出的模型在场景中是没法显示出来的,接下来设置它的大小、位置、旋转角度和设置它的Z深度值,目的是设置场景中的模型层次关系或说是遮挡关系,这样多个模型显示时才有会有前后关系。这些参数设置好了后,最后的工作是将模型在场景中显示出来,显示模型需要将模型挂接到场景中作为场景的孩子结点,换句话说就是将模型结点加入到场景树中,调用函数addchild既可实现。在场景中实现的效果以下图:

在Cocos2D-x引擎中凡是触及到创建模型对象都会与Sprite3D精灵有关系。

以上就是Cocos2d-x 3.x 图形学渲染系列十的相关内容分享,字数约5820字,希望这对大家有所帮助!屹东网往后会继续推荐Cocos2d-x 3.x 图形学渲染系列十相关内容。