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

栏目: IOS · 发布时间: 7年前

内容简介:Cocos2d-x 3.x 图形学渲染系列二十八

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

CSDN视频网址: http://edu.csdn.net/lecturer/144

昨天,刚从丈母娘家回来,继续博客的更新,接着 Cocos2d-x 3.x图形学渲染系列二十七 继续系列二十八的编写。

接下来读取FBX模型文件信息,首先要做的是把读取的模型信息进行归类并且序列化,在前面系列中介绍的c3t模型文件中关于模型的信息包括:attributes属性信息,顶点信息,子网格信息,索引信息,骨骼动画信息,材质信息等等,读取FBX模型文件信息类的完整代码实现如下所示:

#include "Node.h"
#include "NodePart.h"
#include "Animation.h"
#include "NodeAnimation.h"
#include "Keyframe.h"
#include "Material.h"
#include "Attributes.h"
#include "MeshPart.h"
#include "Mesh.h"
#include "Model.h"

namespace fbxconv {
namespace modeldata {

staticconstchar* getPrimitiveTypeString(constint&primitiveTypeId) {
	switch(primitiveTypeId){
	case0:
		return"POINTS";
	case1:
		return"LINES";
	case3:
		return"LINE_STRIP";
	case4:
		return"TRIANGLES";
	case5:
		return"TRIANGLE_STRIP";
	default:
		return"UNKNOWN";
	}
}
staticconstchar* getWrapModeUseString(constFbxFileTexture::EWrapMode&textureUse)
{
switch(textureUse){
	caseFbxFileTexture::eRepeat:
		return"REPEAT";
	caseFbxFileTexture::eClamp:
		return"CLAMP";
	default:
		return"UNKNOWN";
	}
}
staticconstchar* getTextureUseString(constMaterial::Texture::Usage&textureUse) {
	switch(textureUse){
		caseMaterial::Texture::Ambient:
			return"AMBIENT";
		caseMaterial::Texture::Bump:
			return"BUMP";
		caseMaterial::Texture::Diffuse:
			return"DIFFUSE";
		caseMaterial::Texture::Emissive:
			return"EMISSIVE";
		caseMaterial::Texture::None:
			return"NONE";
		caseMaterial::Texture::Normal:
			return"NORMAL";
		caseMaterial::Texture::Reflection:
			return"REFLECTION";
		caseMaterial::Texture::Shininess:
			return"SHININESS";
		caseMaterial::Texture::Specular:
			return"SPECULAR";
		caseMaterial::Texture::Transparency:
			return"TRANSPARENCY";
		default:
			return"UNKNOWN";
	}
}

voidModel::serialize(json::BaseJSONWriter&writer) const {

std::list<std::string> _bonenames;
for (std::vector<Node *>::const_iterator itr = nodes.begin(); itr != nodes.end(); ++itr)
    {
        (*itr)->loadBoneNames(_bonenames);
    }
	for (std::vector<Node *>::const_iterator itr = nodes.begin(); itr != nodes.end(); ++itr)
    {
		bool skeleton=false;
        (*itr)->checkIsSkeleton(skeleton,_bonenames);
        (*itr)->setSkeleton(skeleton);
    }
	writer.obj(6);
	char szVersion[64] = {0};
	sprintf(szVersion, "%d.%d", VERSION_HI, VERSION_LO);
	writer <<"version" = szVersion;
	if(exportPart == EXPORT_PART_ALL || exportPart == EXPORT_PART_MODEL)
    {
        writer <<"id" = id;
        writer <<"meshes" = meshes;
        writer <<"materials" = materials;
        writer <<"nodes" = nodes;
    }

	if(exportPart == EXPORT_PART_ALL || exportPart == EXPORT_PART_ANIMATION)
    {
        writer <<"animations" = animations;
    }
	writer.end();
}

	voidMesh::serialize(json::BaseJSONWriter&writer) const {
	writer.obj(3);
	writer <<"attributes" = attributes;
	writer.val("vertices").is().data(vertices, vertexSize);
	writer <<"parts" = parts;
	writer.end();
}

voidAttributes::serialize(json::BaseJSONWriter&writer) const {
	constunsignedint len = length();
	writer.arr(len, 8);
	for (unsignedint i = 0; i < len; i++)
	{
		writer <<json::obj;

		MeshVertexAttrib v;
		std::string key = name(i);
		v = attributemap.find(key)->second;

		writer <<"size"<< v.size;
		writer <<"type"<< v.type;
		writer <<"attribute"<< v.name;
		writer <<json::end;
		if(key == "VERTEX_ATTRIB_BLEND_INDEX")
        {
			break;
        }
	}
	writer.end();
}
voidMeshPart::serialize(json::BaseJSONWriter&writer) const {
	writer.obj(4);
	writer <<"id" = id;
	writer <<"type" = getPrimitiveTypeString(primitiveType);
	writer.val("indices").is().data(indices, 12);
	writer <<"aabb" = aabb;
	writer <<json::end;
}

voidMaterial::serialize(json::BaseJSONWriter&writer) const {
	writer <<json::obj;
	writer <<"id" = id;
	if (ambient.valid)
		writer <<"ambient" = ambient.value;
	if (diffuse.valid)
		writer <<"diffuse" = diffuse.value;
	if (emissive.valid)
		writer <<"emissive" = emissive.value;
	if (opacity.valid)
		writer <<"opacity" = opacity.value;
	if (specular.valid)
		writer <<"specular" = specular.value;
	if (shininess.valid)
		writer <<"shininess" = shininess.value;
	if (!textures.empty())
		writer <<"textures" = textures;
	writer <<json::end;
}

voidMaterial::Texture::serialize(json::BaseJSONWriter&writer) const {
	writer <<json::obj;
	writer <<"id" = id;
	writer <<"filename" = path;
	if (uvTranslation[0] != 0.f || uvTranslation[1] != 0.f)
		writer <<"uvtranslation" = uvTranslation;
	if (uvScale[0] != 1.f || uvScale[1] != 1.f)
		writer <<"uvscaling" = uvScale;
	writer <<"type" = getTextureUseString(usage);
    writer <<"wrapModeU" = getWrapModeUseString(wrapModeU);
    writer <<"wrapModeV"  =getWrapModeUseString(wrapModeV);
	writer <<json::end;
}

voidNode::serialize(json::BaseJSONWriter&writer) const {
	writer <<json::obj;
	writer <<"id" = id;
    writer <<"skeleton" = _skeleton;
    writer <<"transform"<<transforms; 
	if (!parts.empty())
		writer <<"parts" = parts;
	if (!children.empty())
		writer <<"children" = children;
	writer <<json::end;
}

template<class T, size_t n>void writeAsFloat(json::BaseJSONWriter&writer, constchar *k, const T(&v)[n]) {
	staticfloat tmp[n];
	for (int i = 0; i < n; ++i)
		tmp[i] = (float)v[i];
	writer << k << tmp;
}

voidNodePart::serialize(json::BaseJSONWriter&writer) const {
	writer <<json::obj;
	writer <<"meshpartid" = meshPart->id;
	writer <<"materialid" = material->id;
	if (!bones.empty()) {
		writer.val("bones").is().arr();
		for (std::vector<std::pair<Node *, FbxAMatrix>>::const_iterator it = bones.begin(); it != bones.end(); ++it) {
			writer <<json::obj;
			writer <<"node" = it->first->id;
	float tmp[16];
			for(int i = 0; i <4; i++)
            {
				for(int j = 0; j <4; j++)
                {
                    tmp[i*4 + j] = it->second.Double44()[i][j];
                }
            }
            writer <<"transform"<< tmp; 
			writer <<json::end;
		}
		writer.end();
	}
	if (!uvMapping.empty()) {
		writer.val("uvMapping").is().arr(uvMapping.size(), 16);
		for (std::vector<std::vector<Material::Texture *>>::const_iterator it = uvMapping.begin(); it != uvMapping.end(); ++it) {
			writer.arr((*it).size(), 16);
			for (std::vector<Material::Texture *>::const_iterator tt = (*it).begin(); tt != (*it).end(); ++tt)
				writer <<material->getTextureIndex(*tt);
			writer.end();
		}
		writer.end();
	}
	writer <<json::end;
}

voidAnimation::serialize(json::BaseJSONWriter&writer) const {
	writer.obj(2);
	writer <<"id" = id;
    writer <<"length" = length;
	writer <<"bones" = nodeAnimations;
	writer.end();
}

voidNodeAnimation::serialize(json::BaseJSONWriter&writer) const {
	writer.obj(2);
	writer <<"boneId" = node->id;
	writer <<"keyframes" = keyframes;
	writer.end();
}

voidKeyframe::serialize(json::BaseJSONWriter&writer) const {
	writer <<json::obj;
	writer <<"keytime" = time;
	if (hasRotation)
	writer <<"rotation" = rotation;
	if (hasScale)
	writer <<"scale" = scale;
	if (hasTranslation)
	writer <<"translation" = translation;
	writer <<json::end;
}

} 
}

下面开始c3b或者c3t模型文件的写入操作,写入类主要工作实现了c3b或者c3t模型的信息写入操作,类的完整代码实现如下所示:

#include "Node.h"
#include "NodePart.h"
#include "Animation.h"
#include "NodeAnimation.h"
#include "Keyframe.h"
#include "Material.h"
#include "Attributes.h"
#include "MeshPart.h"
#include "Mesh.h"
#include "Model.h"
#include "Reference.h"
#include "FileIO.h"
 #include "Reference.h"
namespace fbxconv {
namespace modeldata {
static const char* getTextureUseString(const Material::Texture::Usage& textureUse) {
	switch(textureUse){
		case Material::Texture::Ambient:
			return"AMBIENT";
		case Material::Texture::Bump:
			return"BUMP";
		case Material::Texture::Diffuse:
			return"DIFFUSE";
		case Material::Texture::Emissive:
			return"EMISSIVE";
		case Material::Texture::None:
			return"NONE";
		case Material::Texture::Normal:
			return"NORMAL";
		case Material::Texture::Reflection:
			return"REFLECTION";
		case Material::Texture::Shininess:
			return"SHININESS";
		case Material::Texture::Specular:
			return"SPECULAR";
		case Material::Texture::Transparency:
			return"TRANSPARENCY";
	default:
		return"UNKNOWN";
	}
}
static const char* getWrapModeUseString(const FbxFileTexture::EWrapMode& textureUse)
    {
		switch(textureUse){
			case FbxFileTexture::eRepeat:
				return"REPEAT";
			case FbxFileTexture::eClamp:
				return"CLAMP";
			default:
				return"UNKNOWN";
        }
    }
	void Model::writeBinary(FILE* file)
	{
		if(exportPart == EXPORT_PART_ALL || exportPart == EXPORT_PART_MODEL)
        {
	std::list<std::string> _bonenames;
			for (std::vector<Node *>::const_iterator itr = nodes.begin(); itr != nodes.end(); ++itr)
            {
                (*itr)->loadBoneNames(_bonenames);
            }
			for (std::vector<Node *>::const_iterator itr = nodes.begin(); itr != nodes.end(); ++itr)
            {
				bool skeleton=false;
                (*itr)->checkIsSkeleton(skeleton,_bonenames);
                (*itr)->setSkeleton(skeleton);
            }
	unsigned int size = meshes.size();
	    if(size>0)
            {
		meshes[0]->object.fPosition = ftell(file);	
            }
		write(size, file);
		// 写入网格
	    for(auto itr = meshes.begin(); itr != meshes.end(); itr++)
            {
                (*itr)->writeBinary(file);
            }

		//写入材质
            size = materials.size();
		if(size>0)
            {
		materials[0]->object.fPosition = ftell(file);	
            }
		write(size, file);
	    for(auto itr = materials.begin(); itr != materials.end(); itr++)
            {
                (*itr)->writeBinary(file);
            }
			// 结点数量
            size = nodes.size();
	    if(size>0)
            {
		nodes[0]->object.fPosition = ftell(file);	
            }
			write(size, file);
	    for(auto itr = nodes.begin(); itr != nodes.end(); itr++)
            {
                (*itr)->writeBinary(file);
            }
        }

		// 骨骼信息
	if (exportPart == EXPORT_PART_ALL || exportPart == EXPORT_PART_ANIMATION)
        {
	   for(auto itr : animations)
            {
                itr->object.fPosition = ftell(file);
                itr->writeBinary(file);
            }
        }
	}

	void Mesh::writeBinary(FILE* file)
	{
		// 属性
		attributes.writeBinary(file);
		
		// 写入顶点
		if(vertices.size() >0)
		{
			unsignedint size = vertices.size();
			write(size, file);
			write(&vertices[0],size,file);
		}
		else
		{
			write((unsignedint)0, file);
		}

		// 写入模型部分
		unsignedint size = parts.size();
		write(size, file);
		for(auto itr = parts.begin(); itr != parts.end(); itr++)
		{
                    (*itr)->writeBinary(file);
		}
	}
	void MeshPart::writeBinary(FILE* file)
    {
		write(id, file);
		// 索引大小
		unsignedint size = indices.size();
		write(size, file);
		// 索引
		for(auto itr1 = indices.begin(); itr1 != indices.end(); itr1++)
		write(*itr1,file);
		//aabb碰撞体
		write(aabb, 6, file);
    }
	void Attributes::writeBinary(FILE* file)
	{

		std::vector<MeshVertexAttrib> attribs;
		MeshVertexAttrib attrib;
		for (unsignedint i = 0; i <length(); i++)
        {
			std::string key = name(i);
            attrib = attributemap.find(key)->second;
            attribs.push_back(attrib);
	    if(key == "VERTEX_ATTRIB_BLEND_INDEX")
            {
		break;
            }
        }
		unsigned int size = attribs.size();
		write(size, file);
		for( int i = 0 ; i < size ; i++ )
        {
			write(attribs[i].size, file);
			write(attribs[i].type, file);
			write(attribs[i].name, file);
        }
	}
	
	void Material::writeBinary(FILE* file)
	{
		write(id, file);
		write(diffuse.value, 3, file);
		write(ambient.value, 3, file);
		write(emissive.value, 3, file);
		write(opacity.value,file);
		write(specular.value, 3, file);
		write(shininess.value,file);
		unsigned int size = textures.size();
		write(size, file);
		for(auto itr = textures.begin(); itr != textures.end(); itr++)
               {
			write((*itr)->id, file);
			write((*itr)->path, file);
			write((*itr)->uvTranslation, 2, file);
			write((*itr)->uvScale, 2, file);
		      std::string	wrapModeU=getWrapModeUseString((*itr)->wrapModeU);
			std::string  wrapModeV=getWrapModeUseString((*itr)->wrapModeV);
			std::string  type= getTextureUseString((*itr)->usage);
			write(type,file);
			write(wrapModeU,file);
			write(wrapModeV,file);
        }
	}
	
	void Node::writeBinary(FILE* file)
	{
		write(id, file);
		write(_skeleton, file);
		// 旋转,缩放,变换
		write(transforms, 16, file);
		// 结点部分
		unsigned int partsSize = parts.size();
		write(partsSize,file);
		if(parts.size()>0)
		{
			for(int i = 0 ; i <parts.size() ; i++ )
            {
				NodePart* nodepart = parts[i];
				if(nodepart)
                {
					if(nodepart->meshPart)
                    {
						//网格部分id
						write(nodepart->meshPart->id, file);
                    }
				else
                    {
						write("null", file);
                    }
					//材质id
					if(nodepart->material)
                    {
						write(nodepart->material->id, file);
                    }
					else
                    {
						write("null", file);
                    }
					// 骨骼数量
					unsigned int size = nodepart->bones.size();
					write(size, file);
			for(auto itr = nodepart->bones.begin(); itr != nodepart->bones.end(); itr++)
                    {
						// 写入名字
						write(itr->first->id, file);
						// 写入转换
						float tmp[16];
						for(int i = 0; i <4; i++)
                        {
							for(int j = 0; j <4; j++)
                            {
                          tmp[i*4 + j] = itr->second.Double44()[i][j];
                            }
                        }
						write(tmp, 16, file);
                    }

                    size = nodepart->uvMapping.size();
						write(size, file);
			for(auto itr = nodepart->uvMapping.begin(); itr != nodepart->uvMapping.end(); itr++)
                    {
						unsigned int size = itr->size();
						write(size, file);
						//纹理索引
				for (auto tt = (*itr).begin(); tt != (*itr).end(); ++tt)
                        {
					unsigned int index = nodepart->material->getTextureIndex(*tt);
					write(index, file);
                        }
                    }
                }
            }
		}
			// 孩子结点
			unsigned int childrenSize = children.size();
			write(childrenSize,file);
		for(auto itr = children.begin(); itr != children.end(); itr++)
		{
			Node* node = *itr;
			if(node)
            {
                node->writeBinary(file);
            }
		}
	}
	void Animation::writeBinary(FILE* file)
	{
		write(id, file);
		write(length, file);
		write(static_cast<unsignedint>(nodeAnimations.size()), file);

		for(auto itr = nodeAnimations.begin(); itr != nodeAnimations.end(); itr++)
		{
			NodeAnimation* nodeanim = *itr;
			write(nodeanim->node->id, file);
			
			write(static_cast<unsigned int>(nodeanim->keyframes.size()), file);
			
			for(auto itr1 = nodeanim->keyframes.begin(); itr1 != nodeanim->keyframes.end(); itr1++)
			{
				Keyframe* keyframe = *itr1;

				// 写入帧动画时间
				write(keyframe->time, file);

			// 写入转换标记
			unsigned char transformflag(0);
			if (keyframe->hasRotation)
                    transformflag |= 0x01;
			if (keyframe->hasScale)
                    transformflag |= (0x01<<1);
				if (keyframe->hasTranslation)
                    transformflag |= (0x01<<2);

		write(transformflag, file);

		// 写入旋转数值
		if (keyframe->hasRotation)
			write(keyframe->rotation, 4, file);

		// 写入缩放数值
		if (keyframe->hasScale)
			write(keyframe->scale, 3, file);

		// 写入转换数值
		if (keyframe->hasTranslation)
				write(keyframe->translation, 3, file);
			}
		}
    }
} 
}

文件写入的操作也有了,后面就需要自己封装一个具体实现的类用于文件的保存,这个实现起来比较简单,头文件的完整代码如下所示:

#ifndef _GPBFILE_H_
#define _GPBFILE_H_

#include "FileIO.h"
#include "Model.h"
#include "ReferenceTable.h"

namespace fbxconv {

class C3BFile
{
public:
	// 构造函数
	C3BFile(void);

	~C3BFile(void);

	// 析构函数
	bool saveBinary(conststd::string& filepath);

	void addToRefTable(ObjRef* obj);

	void AddModel(modeldata::Model* model);

private:
	FILE* _file;
	modeldata::Model* _models;
	ReferenceTable _refTable;

};
}

#endif

对应的源文件完整代码实现如下所示:

#include "C3BFile.h"
#include "Animation.h"
#include "Model.h"
namespace fbxconv{
    using namespace modeldata;
    unsigned char GPB_VERSION[2] ={VERSION_HI, VERSION_LO};
    C3BFile::C3BFile(void)
       :_file(NULL)
    {
 
    }
 
    C3BFile::~C3BFile(void)
    {
 
    }
 
    bool C3BFile::saveBinary(const std::string& filepath)
    {
       _file = fopen(filepath.c_str(), "w+b");
 
       //文件加密标识
       char identifier[] = {'C','3','B','\0'};
 
       fwrite(identifier, 1, sizeof(identifier), _file);
 
       //版本号
       fwrite(GPB_VERSION, 1, sizeof(GPB_VERSION), _file);
 
       _refTable.writeBinary(_file);
 
       if(_models)
       {
           _models->writeBinary(_file);
       }
      
       _refTable.updateOffset(_file);
 
       fclose(_file);
       returntrue;
    }
 
    void C3BFile::addToRefTable(ObjRef* obj)
    {
       if(obj)
       {
           std::string&id = obj->id;
           if(id.length()>0)
           {
              if(_refTable.get(id)== NULL)
              {
                  _refTable.add(id, obj);
              }
           }
       }
    }
 
    void C3BFile::AddModel(modeldata::Model*model)
    {
       _models = model;
 
       //增加模型
       if(model->meshes.size()>0)
        {
           Mesh* mesh = model->meshes[0];
           addToRefTable(mesh->GetObj());
        }
       //增加材质
       if(model->materials.size()>0)
        {
           Material* mat = model->materials[0];
           addToRefTable(mat->GetObj());
        }
       //增加结点
       if(model->nodes.size()>0)
        {
           Node* node = model->nodes[0];
           addToRefTable(node->GetObj());
        }
 
       // 增加动画
       if(model->animations.size()>0)
        {
           for (int i= 0; i < model->animations.size(); i++)
            {
              Animation* anim = model->animations[i];
              addToRefTable(anim->GetObj());
            }
        }
 
    }
 
}

另外其他类的实现比如:Animation,Attribute,Keyframe,Material,Mesh,MeshPart,Model,Node等等,这里就不一一列举了。

后续讲解敬请期待。。。。。。


以上所述就是小编给大家介绍的《Cocos2d-x 3.x 图形学渲染系列二十八》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

深度解析淘宝运营

深度解析淘宝运营

刘涛 / 电子工业出版社 / 2015-9-1 / 49.00元

淘宝运营,仅有知识是不够的,还需要有系统的运营思路。为帮助广大电商从业者以及众多中小卖家更好地运营店铺,《深度解析淘宝运营》全面阐述了整个店铺运营的重点环节,包括淘宝搜索规则、打造爆款、店铺规划、客户服务、直通车、钻石展位、数据分析等内容。具体操作步骤翔实,并且结合笔者的实际操作经验,将各个环节最本质的一面透彻展现给读者,结合理论与实战,尽可能向读者展示一个最真实的运营核心。《深度解析淘宝运营》没......一起来看看 《深度解析淘宝运营》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

MD5 加密
MD5 加密

MD5 加密工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具