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 图形学渲染系列二十八》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Ordering Disorder

Ordering Disorder

Khoi Vinh / New Riders Press / 2010-12-03 / USD 29.99

The grid has long been an invaluable tool for creating order out of chaos for designers of all kinds—from city planners to architects to typesetters and graphic artists. In recent years, web designers......一起来看看 《Ordering Disorder》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具