ITPub博客

首页 > 应用开发 > Html/css > FBX广泛应用于游戏开发领域,目前最火的三维游戏引擎Unity

FBX广泛应用于游戏开发领域,目前最火的三维游戏引擎Unity

投稿 Html/css 作者:ecclw459 时间:2026-01-26 16:17:22 0 删除 编辑
  1. DS和MAX属于三维建模软件Autodesk 3ds Max的专属的文件数据格式。理论上来说,3DS和MAX都属于商业三维数据格式,但是Autodesk 3ds Max在三维建模上的使用非常广泛,所以这两种数据格式也很常见。不同的是,3DS现在已经基本能够各种三维软件所识别,一些开源工具也能解析识别;Max则是Autodesk 3ds Max所专用,其他三维软件或者开源工具一般都不支持。Max还有一个笔者认为不太好的特点,就是版本迭代太快,低版本的Autodesk 3ds Max无法打开高版本的Max格式数据。
  2. glTF是一种自由开放,无专利限制的,适合传输和加载3D模型和场景的文件格式。相比较前面介绍三维数据格式来说,glTF诞生的时间较晚,可以采用了更为现代的图形技术来封装和组织这个格式。Khronos Group制定和维护了glTF数据格式的标准,同时由于其也是OpenGL接口标准的指定者和维护者,因此glTF特别适合OpenGL系列(OpenGL,OpenGL ES,WebGL)的图形渲染流水线所需要进行的处理。这个特点意味着glTF足够轻量化。目前glTF有1.0和2.0两个版本,其中glTF2.0已经成为了ISO国际标准。
  3. FBX同样也是Autodesk公司开发的一种通用三维数据格式。与glTF一样,FBX也是更为现代的三维数据格式,比如支持显示效果更为真实的PBR材质。FBX广泛应用于游戏开发领域,目前最火的三维游戏引擎Unity和Unreal都支持直接导入这种格式。Autodesk官方为FBX提供了开发包,支持解析和修改该格式数据文件。除此之外,也有一些开源第三方组件使用自己的方式兼容它。

综合来说,PLY、OBJ和3DS都属于比较早期的三维模型数据格式,受限于当年的图形技术的认知;而Max、glTF和FBX则设计得更为现代,文件组织结构更为合理,能提供更为强大的可视化效果。例如,现代三维模型数据格式已经不仅仅是像早期三维模型数据格式那样只包含模型数据本身,还会包括材质、动画、灯光甚至相机等,其描述的对象可以是整个三维场景。

7.1.2 从地形来认识三维模型(PLY格式)

如果没有三维图形的基础知识,上一小节的论述可能会让有的读者一头雾水。那么我们可以从GIS中的地形开始说起——在第6.3节中我们就已经使用过PLY格式的三维数据,将其表达成不规则三角网地形。但是,如图6.6所示的地形实在过于简陋,有没有办法给这个白模赋予着色信息,使其有更好的可视化效果呢?

include <gdal_priv.h> # include <algorithm> # include <array> # include <fstream> # include <iostream> # include <vector> using namespace std; struct VertexProperty {   double x;   double y;   double z;   uint8_t red;   uint8_t green;   uint8_t blue; }; size_t vertexCount; vector<VertexProperty> vertexData; size_t faceCount; vector< int > indices; //颜色查找表 using F_RGB = std::array< double , 3 >; vector<F_RGB> tableRGB ( 256) ; //生成渐变色 void Gradient (F_RGB& start, F_RGB& end, vector<F_RGB>& RGBList) {  F_RGB d;   for ( int i = 0 ; i < 3 ; i++) {    d[i] = (end[i] - start[i]) / RGBList. size ();  }   for ( size_t i = 0 ; i < RGBList. size (); i++) {     for ( int j = 0 ; j < 3 ; j++) {      RGBList[i][j] = start[j] + d[j] * i;    }  } } //初始化颜色查找表 void InitColorTable () {   F_RGB blue ({ 17, 60, 235}) ;   //蓝色   F_RGB green ({ 17, 235, 86}) ;   //绿色   vector<F_RGB> RGBList ( 60) ;   Gradient (blue, green, RGBList);   for ( int i = 0 ; i < 60 ; i++) {    tableRGB[i] = RGBList[i];  }   F_RGB yellow ({ 235, 173, 17}) ;   //黄色  RGBList. clear ();  RGBList. resize ( 60 );   Gradient (green, yellow, RGBList);   for ( int i = 0 ; i < 60 ; i++) {    tableRGB[i + 60 ] = RGBList[i];  }   F_RGB red ({ 235, 60, 17}) ;   //红色  RGBList. clear ();  RGBList. resize ( 60 );   Gradient (yellow, red, RGBList);   for ( int i = 0 ; i < 60 ; i++) {    tableRGB[i + 120 ] = RGBList[i];  }   F_RGB white ({ 235, 17, 235}) ;   //紫色  RGBList. clear ();  RGBList. resize ( 76 );   Gradient (red, white, RGBList);   for ( int i = 0 ; i < 76 ; i++) {    tableRGB[i + 180 ] = RGBList[i];  } } //根据高程选颜色 inline int GetColorIndex ( double z, double min_z, double max_z) {   int temp = ( int ) floor ((z - min_z) * 255 / (max_z - min_z) + 0.6 );   return temp; } void ReadDem () {  string workDir = getenv ( "GISBasic" );  string demPath = workDir + "/../Data/Model/dem.tif" ;  GDALDataset* dem = (GDALDataset*) GDALOpen (demPath. c_str (), GA_ReadOnly);   if (!dem) {    cout << "Can't Open Image!" << endl;     return ;  }   int srcDemWidth = dem-> GetRasterXSize ();   int srcDemHeight = dem-> GetRasterYSize ();   //坐标信息   double geoTransform[ 6 ] = { 0 };  dem-> GetGeoTransform (geoTransform);   double srcDx = geoTransform[ 1 ];   double srcDy = geoTransform[ 5 ];   double startX = geoTransform[ 0 ] + 0.5 * srcDx;   double startY = geoTransform[ 3 ] + 0.5 * srcDy;   double endX = startX + (srcDemWidth - 1 ) * srcDx;   double endY = startY + (srcDemHeight - 1 ) * srcDy;   size_t demBufNum = ( size_t )srcDemWidth * srcDemHeight;   vector< float> srcDemBuf (demBufNum, 0) ;   int depth = sizeof ( float );  dem-> GetRasterBand ( 1 )-> RasterIO (GF_Read, 0 , 0 , srcDemWidth, srcDemHeight,                                  srcDemBuf. data (), srcDemWidth, srcDemHeight,                                  GDT_Float32, depth, srcDemWidth * depth);   GDALClose (dem);   double minZ = *(std:: min_element (srcDemBuf. begin (), srcDemBuf. end ()));   double maxZ = *(std:: max_element (srcDemBuf. begin (), srcDemBuf. end ()));  vertexCount = ( size_t )srcDemWidth * srcDemHeight;  vertexData. resize (vertexCount);   for ( int yi = 0 ; yi < srcDemHeight; yi++) {     for ( int xi = 0 ; xi < srcDemWidth; xi++) {       size_t m = ( size_t )srcDemWidth * yi + xi;      vertexData[m].x = startX + xi * srcDx;      vertexData[m].y = startY + yi * srcDy;      vertexData[m].z = srcDemBuf[m];       int index = GetColorIndex (srcDemBuf[m], minZ, maxZ);      vertexData[m].red = ( uint8_t )(tableRGB[index][ 0 ] + 0.5 );      vertexData[m].green = ( uint8_t )(tableRGB[index][ 1 ] + 0.5 );      vertexData[m].blue = ( uint8_t )(tableRGB[index][ 2 ] + 0.5 );    }  }  faceCount = ( size_t )(srcDemHeight - 1 ) * (srcDemWidth - 1 ) * 2 ;   // indices.resize(faceCount);   for ( int yi = 0 ; yi < srcDemHeight - 1 ; yi++) {     for ( int xi = 0 ; xi < srcDemWidth - 1 ; xi++) {       size_t m = ( size_t )srcDemWidth * yi + xi;      indices. push_back (m);      indices. push_back (m + srcDemWidth);      indices. push_back (m + srcDemWidth + 1 );      indices. push_back (m + srcDemWidth + 1 );      indices. push_back (m + 1 );      indices. push_back (m);    }  } } void WriteDemModel () {  string workDir = getenv ( "GISBasic" );  string demPath = workDir + "/../Data/Model/dst.ply" ;   ofstream outfile (demPath) ;   if (!outfile) {     printf ( "write file error %s\n" , demPath. c_str ());d980.com     return ;  }  outfile << "ply\n" ;  outfile << "format ascii 1.0\n" ;  outfile << "comment CL generated\n" ;  outfile << "element vertex " << to_string (vertexCount) << '\n' ;  outfile << "property double x\n" ;  outfile << "property double y\n" ;  outfile << "property double z\n" ;  outfile << "property uchar red\n" ;  outfile << "property uchar green\n" ;  outfile << "property uchar blue\n" ;  outfile << "element face " << to_string (faceCount) << '\n' ;  outfile << "property list uchar int vertex_indices\n" ;  outfile << "end_header\n" ;  outfile << fixed;   for ( int vi = 0 ; vi < vertexCount; vi++) {    outfile << vertexData[vi].x << ' ' ;    outfile << vertexData[vi].y << ' ' ;    outfile << vertexData[vi].z << '\n' ;    outfile << ( int )vertexData[vi].red << ' ' ;    outfile << ( int )vertexData[vi].green << ' ' ;    outfile << ( int )vertexData[vi].blue << '\n' ;  }   for ( size_t fi = 0 ; fi < faceCount; fi++) {    outfile << 3 ;     for ( int ii = 0 ; ii < 3 ; ii++) {       int id = indices[fi * 3 + ii];


# include <algorithm> # include <array> # include <fstream> # include <iostream> # include <vector> using namespace std; struct VertexProperty {   double x;   double y;   double z;   double texCoordX;   double texCoordY; }; size_t vertexCount; vector<VertexProperty> vertexData; size_t faceCount; vector< int > indices; void ReadDem () {  string workDir = getenv ( "GISBasic" );  string demPath = workDir + "/../Data/Model/dem.tif" ;  GDALDataset* dem = (GDALDataset*) GDALOpen (demPath. c_str (), GA_ReadOnly);   if (!dem) {    cout << "Can't Open Image!" << endl;     return ;  }   int srcDemWidth = dem-> GetRasterXSize ();   int srcDemHeight = dem-> GetRasterYSize ();   //坐标信息   double geoTransform[ 6 ] = { 0 };  dem-> GetGeoTransform (geoTransform);   double srcDx = geoTransform[ 1 ];   double srcDy = geoTransform[ 5 ];   double startX = geoTransform[ 0 ] + 0.5 * srcDx;   double startY = geoTransform[ 3 ] + 0.5 * srcDy;   double endX = startX + (srcDemWidth - 1 ) * srcDx;   double endY = startY + (srcDemHeight - 1 ) * srcDy;   size_t demBufNum = ( size_t )srcDemWidth * srcDemHeight;   vector< float> srcDemBuf (demBufNum, 0) ;   int depth = sizeof ( float );  dem-> GetRasterBand ( 1 )-> RasterIO (GF_Read, 0 , 0 , srcDemWidth, srcDemHeight,                                  srcDemBuf. data (), srcDemWidth, srcDemHeight,                                  GDT_Float32, depth, srcDemWidth * depth);   GDALClose (dem);   double minZ = *(std:: min_element (srcDemBuf. begin (), srcDemBuf. end ()));   double maxZ = *(std:: max_element (srcDemBuf. begin (), srcDemBuf. end ()));  vertexCount = ( size_t )srcDemWidth * srcDemHeight;  vertexData. resize (vertexCount);   for ( int yi = 0 ; yi < srcDemHeight; yi++) {     for ( int xi = 0 ; xi < srcDemWidth; xi++) {       size_t m = ( size_t )srcDemWidth * yi + xi;      vertexData[m].x = startX + xi * srcDx;      vertexData[m].y = startY + yi * srcDy;      vertexData[m].z = srcDemBuf[m];      vertexData[m].texCoordX = ( double )xi / (srcDemWidth - 1 );      vertexData[m].texCoordY = ( double )yi / (srcDemHeight - 1 );    }  }  faceCount = ( size_t )(srcDemHeight - 1 ) * (srcDemWidth - 1 ) * 2 ;   // indices.resize(faceCount);   for ( int yi = 0 ; yi < srcDemHeight - 1 ; yi++) {     for ( int xi = 0 ; xi < srcDemWidth - 1 ; xi++) {       size_t m = ( size_t )srcDemWidth * yi + xi;      indices. push_back (m);      indices. push_back (m + srcDemWidth);      indices. push_back (m + srcDemWidth + 1 );      indices. push_back (m + srcDemWidth + 1 );      indices. push_back (m + 1 );      indices. push_back (m);    }  } } void WriteDemModel () {  string workDir = getenv ( "GISBasic" );  string demPath = workDir + "/../Data/Model/dst.obj" ;   ofstream outfile (demPath) ;   if (!outfile) {     printf ( "write file error %s\n" , demPath. c_str ());     return ;  }  outfile << "mtllib dst.mtl\n" ;  outfile << fixed;   for ( int vi = 0 ; vi < vertexCount; vi++) {    outfile << "v" << ' ' ;    outfile << vertexData[vi].x << ' ' ;    outfile << vertexData[vi].y << ' ' ;    outfile << vertexData[vi].z << '\n' ;  }   for ( int vi = 0 ; vi < vertexCount; vi++) {    outfile << "vt" << ' ' ;    outfile << vertexData[vi].texCoordX << ' ' ;    outfile << vertexData[vi].texCoordY << '\n' ;  }  outfile << "usemtl dst\n" ;   for ( size_t fi = 0 ; fi < faceCount; fi++) {    outfile << "f" ;     for ( int ii = 0 ; ii < 3 ; ii++) {       int id = indices[fi * 3 + ii] + 1 ;      outfile << ' ' << id << '/' << id;    }    outfile << '\n' ;  }  string mtlPath isingyun.com= workDir + "/../Data/Model/dst.mtl" ;   ofstream mtlfile (mtlPath) ;   if (!mtlfile) {     printf ( "write file error %s\n" , mtlPath. c_str ());     return ;  }  mtlfile << "newmtl dst\n" ;  mtlfile << "illum 2\n" ;  mtlfile << "map_Ka tex.jpg\n" ;  mtlfile << "map_Kd tex.jpg\n" ;  mtlfile << "map_Ks tex.jpg\n" ;  mtlfile << "Ns 10.000\n" ; } int main () {   GDALAllRegister ();   //注册格式   //设置Proj数据  std::string projDataPath = getenv ( "GISBasic" );  projDataPath += "/share/proj" ;   CPLSetConfigOption ( "PROJ_LIB" , projDataPath. c_str ());


# include <fstream> # include <iomanip> # include <iostream> # include <nlohmann/json.hpp> using namespace std; using namespace nlohmann; size_t pointNum = 0 ; size_t binBufNum = 0 ; size_t indicesNum = 0 ; void CreateBinFile () {  string workDir = getenv ( "GISBasic" );  string demPath = workDir + "/../Data/Model/dem.tif" ;  GDALDataset *img = (GDALDataset *) GDALOpen (demPath. c_str (), GA_ReadOnly);   if (!img) {     printf ( "Can't Open Image!" );     return ;  }   int bufWidth =bmxgaj.com img-> GetRasterXSize ();   //图像宽度   int bufHeight = img-> GetRasterYSize ();   //图像高度   int bandNum = img-> GetRasterCount ();     //波段数   if (bandNum != 1 ) {     printf ( "DEM波段数不为1" );     return ;  }   int depth = GDALGetDataTypeSize (img-> GetRasterBand ( 1 )-> GetRasterDataType ()) / 8 ;   //图像深度   //获取地理坐标信息   double padfTransform[ 6 ];   if (img-> GetGeoTransform (padfTransform) == CE_Failure) {     printf ( "获取仿射变换参数失败" );     return ;  }   double startX = padfTransform[ 0 ];   double dX = padfTransform[ 1 ];   double startY = padfTransform[ 3 ];   double dY = padfTransform[ 5 ];   //申请buf   size_t imgBufNum = ( size_t )bufWidth * bufHeight * bandNum;   float *imgBuf = new float [imgBufNum];   //读取  img-> RasterIO (GF_Read, 0 , 0 , bufWidth, bufHeight, imgBuf, bufWidth, bufHeight,GDT_Float32, bandNum, nullptr , bandNum * depth, bufWidth * bandNum * depth, depth);  pointNum = ( size_t )bufWidth * bufHeight;   size_t position_texture_num = pointNum * 5 ;   float *position_texture = new float [position_texture_num];   for ( int yi = 0 ; yi < bufHeight; yi++) {     for ( int xi = 0 ; xi < bufWidth; xi++) {       size_t n = ( size_t )(bufWidth * 5 ) * yi + 5 * xi;      position_texture[n] = dX * xi;      position_texture[n + 1 ] = dY * yi;       size_t m = ( size_t )(bufWidth * bandNum) * yi + bandNum * xi;      position_texture[n + 2 ] = imgBuf[m];      position_texture[n + 3 ] = float (xi) / (bufWidth - 1 );      position_texture[n + 4 ] = float (yi) / (bufHeight - 1 );    }  }   //释放   delete [] imgBuf;  imgBuf = nullptr ;  string binPath = workDir + "/../Data/Model/new.bin" ;   ofstream binFile (binPath, std::ios::binary) ;  binFile. write (( char *)position_texture, position_texture_num * sizeof ( float ));   size_t vertexBufNum = position_texture_num * sizeof ( float );  binBufNum = binBufNum + vertexBufNum;   int mod = vertexBufNum % sizeof ( uint16_t );   if (mod != 0 ) {     int spaceNum = sizeof ( float ) - mod;     char *space = new char [spaceNum];    binBufNum =wxwgly.com binBufNum + sizeof ( char ) * spaceNum;     memset (space, 0 , sizeof ( char ) * spaceNum);    binFile. write (space, sizeof ( char ) * spaceNum);     delete [] space;    space = nullptr ;  }  indicesNum = ( size_t )(bufWidth - 1 ) * (bufHeight - 1 ) * 2 * 3 ;   uint16_t *indices = new uint16_t [indicesNum];   for ( int yi = 0 ; yi < bufHeight - 1 ; yi++) {     for ( int xi = 0 ; xi < bufWidth - 1 ; xi++) {       uint16_t m00 = ( uint16_t )(bufWidth * yi + xi);       uint16_t m01 = ( uint16_t )(bufWidth * (yi + 1 ) + xi);       uint16_t m11 = ( uint16_t )(bufWidth * (yi + 1 ) + xi + 1 );       uint16_t m10 = ( uint16_t )(bufWidth * yi + xi + 1 );       size_t n = ( size_t )(bufWidth - 1 ) * yi + xi;      indices[n * 6 ] = m00;      indices[n * 6 + 1 ] = m01;      indices[n * 6 + 2 ] = m11;      indices[n * 6 + 3 ] = m11;      indices[n * 6 + 4 ] = m10;      indices[n * 6 + 5 ] = m00;    }  }  binFile. write (( char *)indices, sizeof ( uint16_t ) * indicesNum);  binBufNum = binBufNum + sizeof ( uint16_t ) * indicesNum;   delete [] position_texture;  position_texture = nullptr ;   delete [] indices;  indices = nullptr ; } int main () 802761.com {   GDALAllRegister ();   CPLSetConfigOption ( "GDAL_FILENAME_IS_UTF8" , "NO" );   //支持中文路径   //设置Proj数据  std::string projDataPath = getenv ( "GISBasic" );  projDataPath += "/share/proj" ;   CPLSetConfigOption ( "PROJ_LIB" , projDataPath. c_str ());  ordered_json gltf;  gltf[ "asset" ] = {{ "generator" , "CL" }, { "version" , "2.0" }};  gltf[ "scene" ] chinarunchi.com= 0 ;  gltf[ "scenes" ] = {{{ "nodes" , { 0 }}}};  gltf[ "nodes" ] = {{{ "mesh" , 0 }}};  ordered_json positionJson;  positionJson[ "POSITION" ] = 1 ;  positionJson[ "TEXCOORD_0" ] = 2 ;  ordered_json primitivesJson;  primitivesJson = {      {{ "attributes" , positionJson}, { "indices" , 0 }, { "material" , 0 }}};  gltf[ "meshes" ] = {{{ "primitives" , primitivesJson}}};  ordered_json pbrJson;ttzbapp.com.cn  pbrJson[ "baseColorTexture" ][ "index" ] = 0 ;  gltf[ "materials" ] = {{{ "pbrMetallicRoughness" , pbrJson}}};   CreateBinFile ();  gltf[ "textures" ] = {{{ "sampler" , 0 }, { "source" , 0 }}};  gltf[ "images" ] = {{{ "uri" , "tex.jpg" }}};  gltf[ "samplers" ] = {{{ "magFilter" , 9729 },                       { "minFilter" , 9987 },                       { "wrapS" , 33648 },                       { "wrapT" , 33648 }}};  gltf[ "buffers" ] = {{{ "uri" , "new.bin" }, { "byteLength" , binBufNum}}};  ordered_json indicesBufferJson;  indicesBufferJson[ "buffer" ] = 0 ;  indicesBufferJson[ "byteOffset" ] = pointNum * 5 * 4 ;  indicesBufferJson[ "byteLength" ] = indicesNum * 2 ;  indicesBufferJson[ "target" ] =ttzbapp.com 34963 ;  ordered_json positionBufferJson;  positionBufferJson[ "buffer" ] = 0 ;  positionBufferJson[ "byteStride" ] = sizeof ( float ) * 5 ;  positionBufferJson[ "byteOffset" ] = 0 ;  positionBufferJson[ "byteLength" ] = pointNum * 5 * 4 ;  positionBufferJson[ "target" ] = 34962 ;  gltf[ "bufferViews" ] =ttzb.tw.cn {indicesBufferJson, positionBufferJson};  ordered_json indicesAccessors;  indicesAccessors[ "bufferView" ] = 0 ;  indicesAccessors[ "byteOffset" ] = 0 ;  indicesAccessors[ "componentType" ] = 5123 ;  indicesAccessors[ "count" ] = indicesNum;  indicesAccessors[ "type" ] = "SCALAR" ;  indicesAccessors[ "max" ] = { 18719 };  indicesAccessors[ "min" ] = { 0 };  ordered_json positionAccessors;  positionAccessors[ "bufferView" ] = 1 ;  positionAccessors[ "byteOffset" ] = 0 ;  positionAccessors[ "componentType" ] = 5126 ;  positionAccessors[ "count" ] = pointNum;  positionAccessors[ "type" ] = "VEC3" ;  positionAccessors[ "max" ] ttzb.ln.cn= { 770 , 0.0 , 1261.151611328125 };  positionAccessors[ "min" ] = { 0.0 , -2390 , 733.5555419921875 };  ordered_json textureAccessors;  textureAccessors[ "bufferView" ] = 1 ;  textureAccessors[ "byteOffset" ] = sizeof ( float ) * 3 ;  textureAccessors[ "componentType" ] = 5126 ;  textureAccessors[ "count" ] = pointNum;  textureAccessors[ "type" ] = "VEC2" ;  textureAccessors[ "max" ] = { 1 , 1 };  textureAccessors[ "min" ] = { 0 , 0 };  gltf[ "accessors" ] =ttzb.gs.cn {indicesAccessors, positionAccessors, textureAccessors};  string workDir = getenv ( "GISBasic" );  string jsonFile = workDir + "/../Data/Model/new.gltf" ;


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70048957/viewspace-3108987/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2026-01-07

  • 博文量
    108
  • 访问量
    102113