内容简介: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 图形学渲染系列二十八》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- CubeEngine v0.3B 更新,图形渲染引擎
- TensorFlow也可以做图形渲染了:当神经网络遇上计算机图形学
- Basemark推出Rocksolid图形渲染解决方案
- Ogre 1.12.3 发布,三维图形渲染引擎
- Rust 移动端跨平台复杂图形渲染项目开发系列总结(目录)
- Cocos2d-x 3.x 图形学渲染系列总结
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
深度解析淘宝运营
刘涛 / 电子工业出版社 / 2015-9-1 / 49.00元
淘宝运营,仅有知识是不够的,还需要有系统的运营思路。为帮助广大电商从业者以及众多中小卖家更好地运营店铺,《深度解析淘宝运营》全面阐述了整个店铺运营的重点环节,包括淘宝搜索规则、打造爆款、店铺规划、客户服务、直通车、钻石展位、数据分析等内容。具体操作步骤翔实,并且结合笔者的实际操作经验,将各个环节最本质的一面透彻展现给读者,结合理论与实战,尽可能向读者展示一个最真实的运营核心。《深度解析淘宝运营》没......一起来看看 《深度解析淘宝运营》 这本书的介绍吧!