综合来说,PLY、OBJ和3DS都属于比较早期的三维模型数据格式,受限于当年的图形技术的认知;而Max、glTF和FBX则设计得更为现代,文件组织结构更为合理,能提供更为强大的可视化效果。例如,现代三维模型数据格式已经不仅仅是像早期三维模型数据格式那样只包含模型数据本身,还会包括材质、动画、灯光甚至相机等,其描述的对象可以是整个三维场景。
如果没有三维图形的基础知识,上一小节的论述可能会让有的读者一头雾水。那么我们可以从GIS中的地形开始说起——在第6.3节中我们就已经使用过PLY格式的三维数据,将其表达成不规则三角网地形。但是,如图6.6所示的地形实在过于简陋,有没有办法给这个白模赋予着色信息,使其有更好的可视化效果呢?
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];
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 ());
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/ ,如需转载,请注明出处,否则将追究法律责任。