国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)

這篇具有很好參考價(jià)值的文章主要介紹了【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

1、簡(jiǎn)介

官網(wǎng)地址:
https://www.khronos.org/gltf/

glTF? 是一種免版稅規(guī)范,用于通過(guò)引擎和應(yīng)用程序高效傳輸和加載 3D 場(chǎng)景和模型。
glTF 定義了一種可擴(kuò)展的發(fā)布格式,通過(guò)在整個(gè)行業(yè)中實(shí)現(xiàn) 3D 內(nèi)容的互操作使用來(lái)簡(jiǎn)化創(chuàng)作工作流程和交互式服務(wù)。

glTF?(GL 傳輸格式)用于在 Web 和本機(jī)應(yīng)用程序中傳輸和加載 3D 模型。glTF 減少了 3D 模型的大小以及解包和渲染這些模型所需的運(yùn)行時(shí)處理。這種格式在 Web 上很常用,并且在 Unity3D、Unreal Engine 4 和 Godot 等各種 3D 引擎中都有支持。

glTF 的內(nèi)部結(jié)構(gòu)模仿了圖形芯片在實(shí)時(shí)渲染時(shí)常用的內(nèi)存緩沖區(qū),因此可以將資產(chǎn)交付到桌面、Web 或移動(dòng)客戶(hù)端,并以最少的處理迅速顯示。因此,在導(dǎo)出到 glTF 時(shí),四邊形和 n 邊形會(huì)自動(dòng)轉(zhuǎn)換為三角形。

b3dm就是在原來(lái)gltf單個(gè)模型的基礎(chǔ)之上,做了批量化的數(shù)據(jù)組織方式,多了feature table和batch table兩個(gè)文件。3D Tiles 是一種開(kāi)放規(guī)范,用于在桌面、Web 和移動(dòng)應(yīng)用程序中共享、可視化、融合和與大量異構(gòu) 3D 地理空間內(nèi)容交互。

【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)
【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)
【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)

1.1 層級(jí)結(jié)構(gòu)

  • glTF Object Hierarchy
    這里來(lái)幾張作者收集的結(jié)構(gòu)圖說(shuō)明gltf的各種對(duì)象組成。
    【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀取(C++,Python)
    【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀取(C++,Python)
    【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀取(C++,Python)

1.2 術(shù)語(yǔ)定義

glTF 規(guī)范使用常見(jiàn)的工程和圖形術(shù)語(yǔ),如image、buffer、texture等來(lái)識(shí)別和描述某些glTF結(jié)構(gòu)及其屬性、狀態(tài)和行為。本節(jié)在規(guī)范的上下文中定義了這些術(shù)語(yǔ)的基本含義。規(guī)范文本提供了更完整的術(shù)語(yǔ)定義,并詳細(xì)闡述、擴(kuò)展或澄清了這些定義。當(dāng)本節(jié)中定義的術(shù)語(yǔ)在規(guī)范中以規(guī)范語(yǔ)言使用時(shí),規(guī)范中的定義支配并取代這些術(shù)語(yǔ)在其他技術(shù)上下文中(即規(guī)范之外)可能具有的任何含義。
【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)

  • accessor
    An object describing the number and the format of data elements stored in a binary buffer.

  • animation
    An object describing the keyframe data, including timestamps, and the target property affected by it.

  • back-facing
    See facingness.

  • buffer
    An external or embedded resource that represents a linear array of bytes.

  • buffer view
    An object that represents a range of a specific buffer, and optional metadata that controls how the buffer’s content is interpreted.

  • camera
    An object defining the projection parameters that are used to render a scene.

  • facingness
    A classification of a triangle as either front-facing or back-facing, depending on the orientation (winding order) of its vertices.

  • front-facing
    See facingness.

  • image
    A two dimensional array of pixels encoded as a standardized bitstream, such as PNG.

  • indexed geometry
    A mesh primitive that uses a separate source of data (index values) to assemble the primitive’s topology.

  • linear blend skinning
    A skinning method that computes a per-vertex transformation matrix as a linear weighted sum of transformation matrices of the designated nodes.

  • material
    A parametrized approximation of visual properties of the real-world object being represented by a mesh primitive.

  • mesh
    A collection of mesh primitives.

  • mesh primitive
    An object binding indexed or non-indexed geometry with a material.

  • mipmap
    A set of image representations consecutively reduced by the factor of 2 in each dimension.

  • morph target
    An altered state of a mesh primitive defined as a set of difference values for its vertex attributes.

  • node
    An object defining the hierarchy relations and the local transform of its content.

  • non-indexed geometry
    A mesh primitive that uses linear order of vertex attribute values to assemble the primitive’s topology.

  • normal
    A unit XYZ vector defining the perpendicular to the surface.

  • root node
    A node that is not a child of any other node.

  • sampler
    An object that controls how image data is sampled.

  • scene
    An object containing a list of root nodes to render.

  • skinning
    The process of computing and applying individual transforms for each vertex of a mesh primitive.

  • tangent
    A unit XYZ vector defining a tangential direction on the surface.

  • texture
    An object that combines an image and its sampler.

  • topology type
    State that controls how vertices are assembled, e.g. as lists of triangles, strips of lines, etc.

  • vertex attribute
    A property associated with a vertex.

  • winding order
    The relative order in which vertices are defined within a triangle

  • wrapping
    A process of selecting an image pixel based on normalized texture coordinates.

2、glTF文件預(yù)覽

2.1 VSCode(v2.0)

安裝第三方擴(kuò)展glTF Tool。
【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)

  • 打開(kāi)和預(yù)覽gltf文件
    【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)
  • 打開(kāi)和預(yù)覽glb文件(gltf二進(jìn)制格式)
    【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)

2.2 glTF Viewer(v2.0, js)

https://gltf-viewer.donmccurdy.com/
【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)
【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)

2.3 babylon.js(v2.0,js)

https://sandbox.babylonjs.com/

Babylon.js Sandbox - View glTF, glb, obj and babylon files. Drag and drop gltf, glb, obj or babylon files to view them.

【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)

3、tinygltf (v2.0, C++)

https://github.com/syoyo/tinygltf

Header only C++11 tiny glTF 2.0 library
Header only C++ tiny glTF library(loader/saver).

TinyGLTF is a header only C++11 glTF 2.0 https://github.com/KhronosGroup/glTF library.

TinyGLTF uses Niels Lohmann’s json library(https://github.com/nlohmann/json), so now it requires C++11 compiler. If you are looking for old, C++03 version, please use devel-picojson branch(but not maintained anymore).
注意:目前該庫(kù)僅支持glTF 2.0格式。
它的OpenGL示例編譯依賴(lài)庫(kù)需要額外下載。本身就是幾個(gè)頭文件直接使用。
【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)

3.1 下載和編譯

cd C:\Users\tomcat\Desktop\test
git clone https://github.com/syoyo/tinygltf.git
cd tinygltf
mkdir bin
cd bin
cmake ..
## or 
cmake -G "Visual Studio 15 2017" .. -A x64
.\\tools\\windows\\premake5.exe vs2017
  • 從GitHub下載該庫(kù)的源代碼
    【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)
  • 通過(guò)CMake生成該庫(kù)的vs2017的工程文件
    【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)
  • 生成的vs2017的工程文件的相關(guān)文件截圖
    【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)
  • vs2017打開(kāi)工程文件,進(jìn)行編譯庫(kù)文件
    【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)
  • 也可以通過(guò)premake5來(lái)生成該庫(kù)vs2017的工程文件,如下圖所示:
    【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)
  • tinygltf自帶例子中一個(gè)小例子編譯后的運(yùn)行結(jié)果
    【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)

3.2 官網(wǎng)代碼示例

/ Define these only in *one* .cc file.
#define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
// #define TINYGLTF_NOEXCEPTION // optional. disable exception handling.
#include "tiny_gltf.h"

using namespace tinygltf;

Model model;
TinyGLTF loader;
std::string err;
std::string warn;

bool ret = loader.LoadASCIIFromFile(&model, &err, &warn, argv[1]);
//bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, argv[1]); // for binary glTF(.glb)

if (!warn.empty()) {
  printf("Warn: %s\n", warn.c_str());
}

if (!err.empty()) {
  printf("Err: %s\n", err.c_str());
}

if (!ret) {
  printf("Failed to parse glTF\n");
  return -1;
}

4、TinyGLTFLoader (v1.0, C++)

【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀取(C++,Python)

Tiny glTF loader, header only C++ glTF 1.x parsing library.

【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀取(C++,Python)

4.1 下載和編譯

https://github.com/syoyo/tinygltfloader
注意:目前該庫(kù)僅支持glTF 1.0格式。
這個(gè)庫(kù)不需要編譯,直接引用頭文件.h就可以了。

4.2 picojson庫(kù)

https://github.com/kazuho/picojson/

a header-file-only, JSON parser serializer in C++
copyright ? 2009-2010 Cybozu Labs, Inc. Copyright ? 2011-2015 Kazuho Oku

代碼示例如下:

const char* json = "{\"a\":1}";
picojson::value v;
std::string err;
const char* json_end = picojson::parse(v, json, json + strlen(json), &err);
if (! err.empty()) {
  std::cerr << err << std::endl;
}
picojson::value v;

// parse the input
std::cin >> v;
std::string err = picojson::get_last_error();
if (! err.empty()) {
  std::cerr << err << std::endl;
  exit(1);
}

// check if the type of the value is "object"
if (! v.is<picojson::object>()) {
  std::cerr << "JSON is not an object" << std::endl;
  exit(2);
}

// obtain a const reference to the map, and print the contents
const picojson::value::object& obj = v.get<picojson::object>();
for (picojson::value::object::const_iterator i = obj.begin();
     i != obj.end();
     ++i) {
  std::cout << i->first << ': ' << i->second.to_str() << std::endl;
}

4.3 官網(wǎng)代碼示例

Copy stb_image.h, picojson.h and tiny_gltf_loader.h to your project.

// Define these only in *one* .cc file.
#define TINYGLTF_LOADER_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#include "tiny_gltf_loader.h"

using namespace tinygltf;

Scene scene; 
TinyGLTFLoader loader;
std::string err;
  
bool ret = loader.LoadASCIIFromFile(scene, err, argv[1]);
//bool ret = loader.LoadBinaryFromFile(scene, err, argv[1]); // for binary glTF(.glb) 
if (!err.empty()) {
  printf("Err: %s\n", err.c_str());
}

if (!ret) {
  printf("Failed to parse glTF\n");
  return -1;
}
【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀取(C++,Python)【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)

【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)
【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)

4.4 自己測(cè)試代碼1

根據(jù)前面貼的結(jié)構(gòu)圖,編寫(xiě)代碼遍歷gltf1.0文件包含的所有幾何數(shù)據(jù)(頂點(diǎn)、法線(xiàn)、面、紋理坐標(biāo)、紋理圖片數(shù)據(jù)等)。

//***********************************************************************
//   Purpose:   tiny_gltf_loader遍歷gltf v1.0文件的幾何數(shù)據(jù)
//   Author:    愛(ài)看書(shū)的小沐
//   Date:      2022-4-19
//   Languages: C++
//   Platform:  Visual Studio 2017
//   OS:        Win10 win64
// ***********************************************************************

#define TINYGLTF_LOADER_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#include "tiny_gltf_loader.h"

void DumpNode(const tinygltf::Node &node, tinygltf::Scene &scene) {

  for (size_t i = 0; i < node.meshes.size(); i++) {
	  std::map<std::string, tinygltf::Mesh>::const_iterator it_mesh = scene.meshes.find(node.meshes[i]);
	  if (it_mesh == scene.meshes.end()) {
		  continue;
	  }

	  const tinygltf::Mesh& mesh = it_mesh->second;
	  for (size_t i = 0; i < mesh.primitives.size(); i++) {
		  const tinygltf::Primitive &primitive = mesh.primitives[i];
		  if (primitive.indices.empty()) return;

		  ///
		  // get texture data
		  tinygltf::Material &mat = scene.materials[primitive.material];
		  if (mat.values.find("diffuse") != mat.values.end()) {
			  std::string diffuseTexName = mat.values["diffuseTex"].string_value;
			  //std::string diffuseTexName2 = mat.values["diffuse"].string_value;
			  if (scene.textures.find(diffuseTexName) != scene.textures.end()) {
				  tinygltf::Texture &tex = scene.textures[diffuseTexName];
				  if (scene.images.find(tex.source) != scene.images.end()) {
					  tinygltf::Image &image = scene.images[tex.source];
					  image.image;
					  image.width;
					  image.height;
					  image.component;
					  image.image.size();

				  }
			  }
		  }

		  ///
		  // get face data primitive.indices
		  const tinygltf::Accessor indexAccessor = scene.accessors[primitive.indices];
		  indexAccessor.type;
		  indexAccessor.componentType;
		  indexAccessor.byteStride;
		  indexAccessor.byteOffset;
		  indexAccessor.count;
		  const tinygltf::BufferView &bufferView = scene.bufferViews[indexAccessor.bufferView];
		  const tinygltf::Buffer &buffer = scene.buffers[bufferView.buffer];
		  printf("\n");

		  float* pointArr = NULL;
		  float* normalArr = NULL;
		  float* textureArr = NULL;
		  unsigned short* faceIndex = NULL;
		  int faceCount = 0;
		  int pointCount = 0;
		  int normalCount = 0;
		  int texCount = 0;

		  faceCount = indexAccessor.count;
		  faceIndex = new unsigned short[faceCount];
		  //assert(bufferView.byteLength == faceCount *sizeof(unsigned short));
		  memcpy(faceIndex, &buffer.data[0] + bufferView.byteOffset+ indexAccessor.byteOffset, faceCount * sizeof(unsigned short));

		  ///
		  // get point and texture data
		  std::map<std::string, std::string>::const_iterator it(primitive.attributes.begin());
		  std::map<std::string, std::string>::const_iterator itEnd(primitive.attributes.end());

		  for (; it != itEnd; it++) {
			  assert(scene.accessors.find(it->second) != scene.accessors.end());
			  const tinygltf::Accessor &accessor = scene.accessors[it->second];
			  const tinygltf::BufferView &bufferView_pt = scene.bufferViews[accessor.bufferView];
			  const tinygltf::Buffer &buffer_pt = scene.buffers[bufferView_pt.buffer];

			  int count = 1;
			  if (accessor.type == TINYGLTF_TYPE_SCALAR) {
				  count = 1;
			  }
			  else if (accessor.type == TINYGLTF_TYPE_VEC2) {
				  count = 2;
			  }
			  else if (accessor.type == TINYGLTF_TYPE_VEC3) {
				  count = 3;
			  }
			  else if (accessor.type == TINYGLTF_TYPE_VEC4) {
				  count = 4;
			  }
			  else {
				  assert(0);
			  }

			  if (it->first.compare("POSITION") == 0) {
				  pointCount = accessor.count * count;
				  pointArr = new float[pointCount];
				  memcpy(pointArr, &buffer_pt.data[0]+ bufferView_pt.byteOffset + accessor.byteOffset, pointCount* sizeof(float));
			  }
			  else if (it->first.compare("NORMAL") == 0) {
				  normalCount = accessor.count * count;
				  normalArr = new float[normalCount];
				  memcpy(normalArr, &buffer_pt.data[0] + bufferView_pt.byteOffset + accessor.byteOffset, normalCount * sizeof(float));
			  }
			  else if (it->first.compare("TEXCOORD_0") == 0) {
				  texCount = accessor.count * count;
				  textureArr = new float[texCount];
				  memcpy(textureArr, &buffer_pt.data[0] + bufferView_pt.byteOffset + accessor.byteOffset, texCount * sizeof(float));
			  }

			  if ((it->first.compare("POSITION") == 0) ||
				  (it->first.compare("NORMAL") == 0) ||
				  (it->first.compare("TEXCOORD_0") == 0)) {

				  //#define GL_BYTE 0x1400              5120
				  //#define GL_UNSIGNED_BYTE 0x1401     5121
				  //#define GL_SHORT 0x1402             5122
				  //#define GL_UNSIGNED_SHORT 0x1403	5123
				  //#define GL_INT 0x1404				5124
				  //#define GL_UNSIGNED_INT 0x1405      5125
				  //#define GL_FLOAT 0x1406				5126

				  accessor.type;
				  accessor.componentType;
				  accessor.byteStride;
				  accessor.byteOffset;
				  accessor.count;
				  const tinygltf::BufferView &bufferView = scene.bufferViews[accessor.bufferView];
				  const tinygltf::Buffer &buffer = scene.buffers[bufferView.buffer];
				  printf("\n");

			  }
		  }
	  }
  }

  for (size_t i = 0; i < node.children.size(); i++) {
	  std::map<std::string, tinygltf::Node>::const_iterator it =
		  scene.nodes.find(node.children[i]);

	  if (it != scene.nodes.end()) {
		  //DrawNode(scene, it->second);
	  }
  }
}

static void Dump(const tinygltf::Scene &scene) {
  std::cout << "=== Dump glTF ===" << std::endl;
  std::cout << "asset.generator          : " << scene.asset.generator
            << std::endl;
  std::cout << "asset.premultipliedAlpha : " << scene.asset.premultipliedAlpha
            << std::endl;
  std::cout << "asset.version            : " << scene.asset.version
            << std::endl;
  std::cout << "asset.profile.api        : " << scene.asset.profile_api
            << std::endl;
  std::cout << "asset.profile.version    : " << scene.asset.profile_version
            << std::endl;
  std::cout << std::endl;
  std::cout << "=== Dump scene ===" << std::endl;
  std::cout << "defaultScene: " << scene.defaultScene << std::endl;

  {
    std::map<std::string, tinygltf::Node>::const_iterator it(
        scene.nodes.begin());
    std::map<std::string, tinygltf::Node>::const_iterator itEnd(
        scene.nodes.end());
    std::cout << "nodes(items=" << scene.nodes.size() << ")" << std::endl;
    for (; it != itEnd; it++) {
      DumpNode(it->second, (tinygltf::Scene &)scene);
    }
  }
}

int main(int argc, char **argv) {
  /*if (argc < 2) {
    printf("Needs input.gltf\n");
    exit(1);
  }*/

  tinygltf::Scene scene;
  tinygltf::TinyGLTFLoader loader;
  std::string err;
  std::string input_filename("c:\\Users\\tomcat\\Desktop\\BlockB.b3dm");
  std::string ext = GetFilePathExtension(input_filename);

  bool ret = false;
  if (ext.compare("glb") == 0) {
	  // assume binary glTF.
	  ret = loader.LoadBinaryFromFile(&scene, &err, input_filename.c_str());
  }
  else if (ext.compare("gltf") == 0) {
	  // assume ascii glTF.
	  ret = loader.LoadASCIIFromFile(&scene, &err, input_filename.c_str());
  }
  else if (ext.compare("b3dm") == 0) {
	  ret = loader.LoadB3dmFromFile(&scene, &err, input_filename.c_str());
  }
  else {
	  return false;
  }

  if (!err.empty()) {
    printf("Err: %s\n", err.c_str());
  }

  if (!ret) {
    printf("Failed to parse glTF\n");
    return -1;
  }

  Dump(scene);

  return 0;
}

4.5 自己測(cè)試代碼2

在頭文件tiny_gltf_loader.h中,增加讀取b3dm文件格式(3d地圖瓦片)的接口。

//***********************************************************************
//   Purpose:   tiny_gltf_loader增加讀取b3dm文件格式的接口
//   Author:    愛(ài)看書(shū)的小沐
//   Date:      2022-4-19
//   Languages: C++
//   Platform:  Visual Studio 2017
//   OS:        Win10 win64
// ***********************************************************************

// 讀取b3dm文件的文件頭,返回值為頭部的長(zhǎng)度
int ReadB3dmHeader(std::ifstream &f, bool &rtcCenterEnable, float *rtcCenterPos)
{
	rtcCenterEnable = false;
	if (rtcCenterPos) {
		rtcCenterPos[0] = 0;
		rtcCenterPos[1] = 0;
		rtcCenterPos[2] = 0;
	}
	int header[7];
	int len_header = 7 * sizeof(int);

	f.seekg(0, f.beg);
	std::vector<char> buf(len_header);
	f.read(&buf.at(0), static_cast<std::streamsize>(len_header));
	::memcpy(header, &buf.at(0), len_header);

	int len_featureTable = header[3];
	if (len_featureTable > 20 && rtcCenterPos != nullptr) {
		char *json = new char[len_featureTable + 1];
		f.read(json, len_featureTable);
		json[len_featureTable] = '\0';

		picojson::value v;
		std::string err;
		const char* json_end = picojson::parse(v, json, json + strlen(json), &err);
		if (!err.empty()) {
			std::cerr << err << std::endl;
		}

		// obtain a const reference to the map, and print the contents
		const picojson::value::object& obj = v.get<picojson::object>();
		for (picojson::value::object::const_iterator i = obj.begin(); i != obj.end() ; ++i) {
			std::cout << i->first << ': ' << i->second.to_str() << std::endl;

			if (i->first.compare("RTC_CENTER") == 0) {
				const picojson::value::array& center = i->second.get<picojson::array>();
				rtcCenterPos[0] = (float)center[0].get<double>();
				rtcCenterPos[1] = (float)center[1].get<double>();
				rtcCenterPos[2] = (float)center[2].get<double>();
				rtcCenterEnable = true;
			}
		}

		delete[] json;
	}

	return len_header + header[3] + header[4] + header[5] + header[6];
}

// 讀取gltf文件的文件頭,返回值為gltf的版本號(hào)
int ReadGltfHeader(std::ifstream &f, int offset)
{
	std::vector<char> buf(16);

	f.seekg(offset, f.beg);
	f.read(&buf.at(0), static_cast<std::streamsize>(buf.size()));
	//std::string strBuf;
	//strBuf.clear();
	//strBuf.assign(buf.begin(), buf.end());
	return buf[4];
}

// 讀取b3dm文件的b3dm頭部和gltf頭部
int TinyGLTFLoader::ReadB3dmVersion(const std::string &filename, bool &rtcCenterEnable, float *rtcCenterPos) {
	std::stringstream ss;

	std::ifstream f(filename.c_str(), std::ios::binary);
	if (!f) {
		return 0;
	}

	int len_b3dm = ReadB3dmHeader(f, rtcCenterEnable, rtcCenterPos);
	int ver = ReadGltfHeader(f, len_b3dm);
	f.close();
	return ver;
}

// 讀取b3dm文件的所有內(nèi)容
bool TinyGLTFLoader::LoadB3dmFromFile(Scene *scene, std::string *err,
	const std::string &filename,
	unsigned int check_sections) {
	std::stringstream ss;

	std::ifstream f(filename.c_str(), std::ios::binary);
	if (!f) {
		ss << "Failed to open file: " << filename << std::endl;
		if (err) {
			(*err) = ss.str();
		}
		return false;
	}

	bool rtcCenterEnable = false;
	float rtcCenterPos[3] = {0};
	int len_b3dm = ReadB3dmHeader(f, rtcCenterEnable, rtcCenterPos);
	int ver = ReadGltfHeader(f, len_b3dm);
	if (ver != 1) return false;

	f.seekg(0, f.end);
	size_t sz = static_cast<size_t>(f.tellg());
	std::vector<char> buf(sz - len_b3dm);

	f.seekg(len_b3dm, f.beg);
	f.read(&buf.at(0), static_cast<std::streamsize>(sz - len_b3dm));
	f.close();

	std::string basedir = GetBaseDir(filename);

	bool ret = LoadBinaryFromMemory(
		scene, err, reinterpret_cast<unsigned char *>(&buf.at(0)),
		static_cast<unsigned int>(buf.size()), basedir, check_sections);

	return ret;
}

5、libgltf (v2.0, C++)

https://github.com/code4game/libgltf

libgltf:glTF 2.0 parser/loader for C++11, supports many extensions
likes KHR_draco_mesh_compression, KHR_lights_punctual,
KHR_materials_clearcoat, and more.

注意:目前該庫(kù)僅支持glTF 2.0格式。
它的編譯依賴(lài)庫(kù)不不不需要額外下載。
【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)

5.1 下載和編譯

cd C:\Users\tomcat\Desktop\test
git clone https://github.com/code4game/libgltf.git
cd libgltf
git submodule update --init
mkdir bin
cd bin
cmake ..
## or 
cmake -G "Visual Studio 15 2017" .. -A x64
  • 從github上下載libgltf的源代碼,如下圖所示:
    【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)

  • 下載libgltf的源代碼的文件夾,如下所示:
    【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀取(C++,Python)

  • 通過(guò)cmake生成vs2017的工程文件。
    【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)
    【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀取(C++,Python)

  • vs2017打開(kāi)上面生成的工程文件,編譯生成libgltf的庫(kù)文件,如下圖所示:
    【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀取(C++,Python)
    【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀取(C++,Python)

5.2 nlohmann/json庫(kù)

https://github.com/nlohmann/json

JSON for Modern C++

【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)
代碼示例如下:

// write a JSON file

// create an empty structure (null)
json j;

// add a number that is stored as double (note the implicit conversion of j to an object)
j["pi"] = 3.141;

// add a Boolean that is stored as bool
j["happy"] = true;

// add a string that is stored as std::string
j["name"] = "Niels";

// add another null object by passing nullptr
j["nothing"] = nullptr;

// add an object inside the object
j["answer"]["everything"] = 42;

// add an array that is stored as std::vector (using an initializer list)
j["list"] = { 1, 0, 2 };

// add another object (using an initializer list of pairs)
j["object"] = { {"currency", "USD"}, {"value", 42.99} };

// instead, you could also write (which looks very similar to the JSON above)
json j2 = {
  {"pi", 3.141},
  {"happy", true},
  {"name", "Niels"},
  {"nothing", nullptr},
  {"answer", {
    {"everything", 42}
  }},
  {"list", {1, 0, 2}},
  {"object", {
    {"currency", "USD"},
    {"value", 42.99}
  }}
};
// read a JSON file
std::ifstream i("file.json");
json j;
i >> j;

// write prettified JSON to another file
std::ofstream o("pretty.json");
o << std::setw(4) << j << std::endl;

5.3 官網(wǎng)代碼示例1

std::shared_ptr<libgltf::IglTFLoader> gltf_loader = libgltf::IglTFLoader::Create(/*your gltf file*/);
std::shared_ptr<libgltf::SGlTF> loaded_gltf = gltf_loader->glTF().lock();
if (!loaded_gltf)
{
    printf("failed to load your gltf file");
}

5.4 官網(wǎng)代碼示例2

#include "runtest.h"
#include <libgltf/libgltf_ext.h>

#include <string>
#include <sstream>
#include <fstream>

#if defined(LIBGLTF_PLATFORM_WINDOWS)
#include <tchar.h>
#include <crtdbg.h>
#endif

#if defined(LIBGLTF_CHARACTOR_ENCODING_IS_UNICODE) && defined(LIBGLTF_PLATFORM_WINDOWS)
int _tmain(int _iArgc, wchar_t* _pcArgv[])
#else
int main(int _iArgc, char* _pcArgv[])
#endif
{
#if defined(LIBGLTF_PLATFORM_WINDOWS) && defined(_DEBUG)
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif

#if defined(LIBGLTF_BUILD_COVERAGE)
    int error_code = 0;
#else
    int error_code = 1;
#endif

#if defined(LIBGLTF_CHARACTOR_ENCODING_IS_UNICODE) && defined(LIBGLTF_PLATFORM_WINDOWS)
    std::wstring input_file_path;
#else
    std::string input_file_path;
#endif

    {
#if defined(LIBGLTF_CHARACTOR_ENCODING_IS_UNICODE) && defined(LIBGLTF_PLATFORM_WINDOWS)
        std::wstringstream argument;
#else
        std::stringstream argument;
#endif
        argument << _pcArgv[1];
        input_file_path = argument.str();
    }

    if (input_file_path.length() == 0)
    {
        printf("Command line format: runtest input_file_path\n");
        return error_code;
    }

#if defined(LIBGLTF_CHARACTOR_ENCODING_IS_UTF16)
    std::shared_ptr<libgltf::IglTFLoader> gltf_loader = libgltf::IglTFLoader::Create(libgltf::UTF8ToUTF16(input_file_path));
#elif defined(LIBGLTF_CHARACTOR_ENCODING_IS_UTF32)
    std::shared_ptr<libgltf::IglTFLoader> gltf_loader = libgltf::IglTFLoader::Create(libgltf::UTF8ToUTF32(input_file_path));
#elif defined(LIBGLTF_CHARACTOR_ENCODING_IS_UNICODE)
#if defined(LIBGLTF_PLATFORM_WINDOWS)
    std::shared_ptr<libgltf::IglTFLoader> gltf_loader = libgltf::IglTFLoader::Create(input_file_path);
#else
    std::shared_ptr<libgltf::IglTFLoader> gltf_loader = libgltf::IglTFLoader::Create(libgltf::UTF8ToUNICODE(input_file_path));
#endif
#else
    std::shared_ptr<libgltf::IglTFLoader> gltf_loader = libgltf::IglTFLoader::Create(input_file_path);
#endif
    
    std::shared_ptr<libgltf::SGlTF> loaded_gltf = gltf_loader->glTF().lock();
    if (loaded_gltf)
    {
        printf("operator << Success\n");
    }
    else
    {
        printf("operator << Failed\n");
        return error_code;
    }

	int num_node = loaded_gltf->nodes.size();
	int num_mesh = loaded_gltf->meshes.size();
	const std::shared_ptr<libgltf::SMesh>& mesh = loaded_gltf->meshes[0];
	int num_pri = mesh->primitives.size();

    libgltf::TDimensionVector<1, size_t> triangle_data;
    std::shared_ptr<libgltf::TAccessorStream<libgltf::TDimensionVector<1, size_t> > > triangle_stream = std::make_shared<libgltf::TAccessorStream<libgltf::TDimensionVector<1, size_t> > >(triangle_data);
    gltf_loader->GetOrLoadMeshPrimitiveIndicesData(0, 0, triangle_stream);

    libgltf::TDimensionVector<3, float> position_data;
    std::shared_ptr<libgltf::TAccessorStream<libgltf::TDimensionVector<3, float> > > position_stream = std::make_shared<libgltf::TAccessorStream<libgltf::TDimensionVector<3, float> > >(position_data);
    gltf_loader->GetOrLoadMeshPrimitiveAttributeData(0, 0, GLTFTEXT("position"), position_stream);

    libgltf::TDimensionVector<3, float> normal_data;
    std::shared_ptr<libgltf::TAccessorStream<libgltf::TDimensionVector<3, float> > > normal_stream = std::make_shared<libgltf::TAccessorStream<libgltf::TDimensionVector<3, float> > >(normal_data);
    gltf_loader->GetOrLoadMeshPrimitiveAttributeData(0, 0, GLTFTEXT("normal"), normal_stream);

    libgltf::TDimensionVector<2, float> texcoord_0_data;
    std::shared_ptr<libgltf::TAccessorStream<libgltf::TDimensionVector<2, float> > > texcoord_0_stream = std::make_shared<libgltf::TAccessorStream<libgltf::TDimensionVector<2, float> > >(texcoord_0_data);
    gltf_loader->GetOrLoadMeshPrimitiveAttributeData(0, 0, GLTFTEXT("texcoord_0"), texcoord_0_stream);

    std::vector<uint8_t> image0_data;
    libgltf::string_t image0_data_type;
    gltf_loader->GetOrLoadImageData(0, image0_data, image0_data_type);

    //TODO: just convert to json, save the mesh or image data to file in future
    libgltf::string_t output_content;
    if (loaded_gltf >> output_content)
    {
        printf("nodes: %d\n", num_node);
		printf("meshes: %d\n", num_mesh);
		printf("meshes[0]'s primitives: %d\n", num_pri);

		printf("triangle_data: %d\n", triangle_data.size());
		printf("position_data: %d\n", position_data.size());
		printf("normal_data: %d\n", normal_data.size());
		printf("texcoord_0_data: %d\n", texcoord_0_data.size());
		printf("image0_data: %d\n", image0_data.size());
        printf("operator >> Success\n");
    }
    else
    {
        printf("operator >> Failed\n");
        return error_code;
    }

    return 0;
}

加載三維模型文件:C:\Users\tomcat\Desktop\dtiles_3\BlockBAB\BlockBAB.glb
【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀取(C++,Python)
運(yùn)行結(jié)果如下:
【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀取(C++,Python)

5.5 自己測(cè)試代碼

//***********************************************************************
//   Purpose:   在libgltf代碼中增加讀取b3dm文件格式的接口
//   Author:    愛(ài)看書(shū)的小沐
//   Date:      2022-4-19
//   Languages: C++
//   Platform:  Visual Studio 2017
//   OS:        Win10 win64
// ***********************************************************************

int CFileLoader::ReadB3dmHeader(const string_t& _sFilePath) const
{
	float RTC_CENTER[3] = { 0,0,0 };
	bool RTC_CENTER_enable = false;

	const std::vector<uint8_t>& file_data = (*this)[_sFilePath];
	if (file_data.empty()) return 0;
	int header[7];
	::memcpy(header, file_data.data(), 7*sizeof(int));

	int len_featureTable = header[3];
	if (len_featureTable > 20) {
		char *buffer = new char[len_featureTable + 1];
		::memcpy(buffer, file_data.data() + 7 * sizeof(int), len_featureTable * sizeof(char));
		buffer[len_featureTable] = '\0';
		auto j = json::parse(buffer);
		
		bool ret = j.contains(json::json_pointer("/RTC_CENTER"));
		if (ret) {
			auto center = j["RTC_CENTER"];
			RTC_CENTER[0] = center[0];
			RTC_CENTER[1] = center[1];
			RTC_CENTER[2] = center[2];
			RTC_CENTER_enable = true;
		}
		else {
			RTC_CENTER[0] = 0;
			RTC_CENTER[1] = 0;
			RTC_CENTER[2] = 0;
			RTC_CENTER_enable = false;
		}

		delete[] buffer;
	}
	return 7*sizeof(int)+ header[3] + header[4] + header[5] + header[6];
}

6、assimp (v1.0, v2.0, C++)

https://github.com/assimp/assimp
https://assimp-docs.readthedocs.io/en/v5.1.0/

The official Open-Asset-Importer-Library Repository. Loads 40+ 3D-file-formats into one unified and clean data structure.
【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀取(C++,Python)
Asset-Importer-Lib(簡(jiǎn)稱(chēng) assimp)是一個(gè)庫(kù),用于加載和處理來(lái)自各種 3D 數(shù)據(jù)格式的幾何場(chǎng)景。通過(guò)支持節(jié)點(diǎn)層次結(jié)構(gòu)、靜態(tài)或蒙皮網(wǎng)格、材質(zhì)、骨骼動(dòng)畫(huà)和潛在紋理數(shù)據(jù),它主要針對(duì)典型的游戲場(chǎng)景進(jìn)行定制。但也支持一些 3D 打印和 CAD 格式。

  • 目前assimp庫(kù)支持如下模型格式的導(dǎo)入:
3D Manufacturing Format (.3mf)
Collada (.dae, .xml)
Blender (.blend)
Biovision BVH (.bvh)
3D Studio Max 3DS (.3ds)
3D Studio Max ASE (.ase)
glTF (.glTF)
glTF2.0 (.glTF)
FBX-Format, as ASCII and binary (.fbx)
Stanford Polygon Library (.ply)
AutoCAD DXF (.dxf)
IFC-STEP (.ifc)
Neutral File Format (.nff)
Sense8 WorldToolkit (.nff)
Valve Model (.smd, .vta)
Quake I (.mdl)
Quake II (.md2)
Quake III (.md3)
Quake 3 BSP (.pk3)
RtCW (.mdc)
Doom 3 (.md5mesh, .md5anim, .md5camera)
DirectX X (.x)
Quick3D (.q3o, .q3s)
Raw Triangles (.raw)
AC3D (.ac, .ac3d)
Stereolithography (.stl)
Autodesk DXF (.dxf)
Irrlicht Mesh (.irrmesh, .xml)
Irrlicht Scene (.irr, .xml)
Object File Format ( .off )
Wavefront Object (.obj)
Terragen Terrain ( .ter )
3D GameStudio Model ( .mdl )
3D GameStudio Terrain ( .hmp )
Ogre ( .mesh.xml, .skeleton.xml, .material )
OpenGEX-Fomat (.ogex)
Milkshape 3D ( .ms3d )
LightWave Model ( .lwo )
LightWave Scene ( .lws )
Modo Model ( .lxo )
CharacterStudio Motion ( .csm )
Stanford Ply ( .ply )
TrueSpace (.cob, .scn)
XGL-3D-Format (.xgl)

6.1 下載和編譯

從它的GitHub官網(wǎng)上下載代碼,用cmake默認(rèn)直接編譯即可。
【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)

6.2 官網(wǎng)代碼示例

  • 代碼示例:這是一段加載gltf模型文件的代碼。
#include <stdlib.h>
#include <stdio.h>

/* assimp include files. These three are usually needed. */
#include <assimp/cimport.h>
#include <assimp/scene.h>
#include <assimp/postprocess.h>

#pragma comment(lib, "..\\..\\lib\\Debug\\assimp-vc141-mtd.lib")
#pragma comment(lib, "..\\..\\contrib\\zlib\\Debug\\zlibstaticd.lib")

/* ---------------------------------------------------------------------------- */
inline static void print_error(const char* msg) {
	printf("ERROR: %s\n", msg);
}

#define NEW_LINE "\n"
#define DOUBLE_NEW_LINE NEW_LINE NEW_LINE

/* the global Assimp scene object */
const C_STRUCT aiScene* scene = NULL;
C_STRUCT aiVector3D scene_min, scene_max, scene_center;

/* current rotation angle */
static float angle = 0.f;

#define aisgl_min(x,y) (x<y?x:y)
#define aisgl_max(x,y) (y>x?y:x)

/* ---------------------------------------------------------------------------- */
void get_bounding_box_for_node (const C_STRUCT aiNode* nd,
	C_STRUCT aiVector3D* min,
	C_STRUCT aiVector3D* max,
	C_STRUCT aiMatrix4x4* trafo
){
	C_STRUCT aiMatrix4x4 prev;
	unsigned int n = 0, t;

	prev = *trafo;
	aiMultiplyMatrix4(trafo,&nd->mTransformation);

	for (; n < nd->mNumMeshes; ++n) {
		const C_STRUCT aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]];
		for (t = 0; t < mesh->mNumVertices; ++t) {

			C_STRUCT aiVector3D tmp = mesh->mVertices[t];
			aiTransformVecByMatrix4(&tmp,trafo);

			min->x = aisgl_min(min->x,tmp.x);
			min->y = aisgl_min(min->y,tmp.y);
			min->z = aisgl_min(min->z,tmp.z);

			max->x = aisgl_max(max->x,tmp.x);
			max->y = aisgl_max(max->y,tmp.y);
			max->z = aisgl_max(max->z,tmp.z);
		}
	}

	for (n = 0; n < nd->mNumChildren; ++n) {
		get_bounding_box_for_node(nd->mChildren[n],min,max,trafo);
	}
	*trafo = prev;
}

/* ---------------------------------------------------------------------------- */
void get_bounding_box(C_STRUCT aiVector3D* min, C_STRUCT aiVector3D* max)
{
	C_STRUCT aiMatrix4x4 trafo;
	aiIdentityMatrix4(&trafo);

	min->x = min->y = min->z =  1e10f;
	max->x = max->y = max->z = -1e10f;
	get_bounding_box_for_node(scene->mRootNode,min,max,&trafo);
}

/* ---------------------------------------------------------------------------- */
void color4_to_float4(const C_STRUCT aiColor4D *c, float f[4])
{
	f[0] = c->r;f[1] = c->g;f[2] = c->b;f[3] = c->a;
}

/* ---------------------------------------------------------------------------- */
void set_float4(float f[4], float a, float b, float c, float d)
{
	f[0] = a;f[1] = b;f[2] = c;f[3] = d;
}

/* ---------------------------------------------------------------------------- */
void apply_material(const C_STRUCT aiMaterial *mtl)
{
	float c[4];

	int fill_mode;
	int ret1, ret2;
	C_STRUCT aiColor4D diffuse;
	C_STRUCT aiColor4D specular;
	C_STRUCT aiColor4D ambient;
	C_STRUCT aiColor4D emission;
	ai_real shininess, strength;
	int two_sided;
	int wireframe;
	unsigned int max;

	set_float4(c, 0.8f, 0.8f, 0.8f, 1.0f);
	if (AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &diffuse))
		color4_to_float4(&diffuse, c);
	printf("	GL_DIFFUSE: %.3f, %.3f, %.3f, %.3f\n", c[0], c[1], c[2], c[3]);

	set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f);
	if (AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &specular))
		color4_to_float4(&specular, c);
	printf("	GL_SPECULAR: %.3f, %.3f, %.3f, %.3f\n", c[0], c[1], c[2], c[3]);

	set_float4(c, 0.2f, 0.2f, 0.2f, 1.0f);
	if (AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &ambient))
		color4_to_float4(&ambient, c);
	printf("	GL_AMBIENT: %.3f, %.3f, %.3f, %.3f\n", c[0], c[1], c[2], c[3]);

	set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f);
	if (AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &emission))
		color4_to_float4(&emission, c);
	printf("	GL_EMISSION:%.3f, %.3f, %.3f, %.3f\n", c[0], c[1], c[2], c[3]);

	max = 1;
	ret1 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS, &shininess, &max);
	if (ret1 == AI_SUCCESS) {
		max = 1;
		ret2 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS_STRENGTH, &strength, &max);
		if (ret2 == AI_SUCCESS)
			printf("	GL_SHININESS: %.3f\n", shininess * strength);
		else
			printf("	GL_SHININESS: %.3f\n", shininess);
	}

	max = 1;
	if (AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_ENABLE_WIREFRAME, &wireframe, &max))
		printf("	fill_mode: %s\n", wireframe ? "GL_LINE" : "GL_FILL");

	max = 1;
	if ((AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_TWOSIDED, &two_sided, &max)) && two_sided)
		printf("	two_sided: true\n");
}

/* ---------------------------------------------------------------------------- */
void recursive_render (const C_STRUCT aiScene *sc, const C_STRUCT aiNode* nd)
{
	unsigned int i;
	unsigned int n = 0, t;
	C_STRUCT aiMatrix4x4 m = nd->mTransformation;

	/* update transform */
	aiTransposeMatrix4(&m);

	/* draw all meshes assigned to this node */
	printf("Node(name: %s, mNumMeshes: %d)\n", nd->mName.data, nd->mNumMeshes);
	for (; n < nd->mNumMeshes; ++n) {
		const C_STRUCT aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]];

		apply_material(sc->mMaterials[mesh->mMaterialIndex]);

		printf("	mNumFaces(%d): %d\n", n, mesh->mNumFaces);
		for (t = 0; t < mesh->mNumFaces; ++t) {
			const C_STRUCT aiFace* face = &mesh->mFaces[t];

			//1:GL_POINTS, 2:GL_LINES, 3:GL_TRIANGLES, 0:GL_POLYGON
			int face_mode = face->mNumIndices;

			for(i = 0; i < face->mNumIndices; i++) {
				int index = face->mIndices[i];

				//if(mesh->mColors[0] != NULL)
				//	glColor4fv((GLfloat*)&mesh->mColors[0][index]);
				//if(mesh->mNormals != NULL)
				//	glNormal3fv(&mesh->mNormals[index].x);
				//glVertex3fv(&mesh->mVertices[index].x);
			}
		}
	}

	/* draw all children */
	for (n = 0; n < nd->mNumChildren; ++n) {
		recursive_render(sc, nd->mChildren[n]);
	}
}

/* ---------------------------------------------------------------------------- */
int loadasset (const char* path)
{
	/* we are taking one of the postprocessing presets to avoid
	   spelling out 20+ single postprocessing flags here. */
	scene = aiImportFile(path,aiProcessPreset_TargetRealtime_MaxQuality);

	if (scene) {
		get_bounding_box(&scene_min,&scene_max);
		scene_center.x = (scene_min.x + scene_max.x) / 2.0f;
		scene_center.y = (scene_min.y + scene_max.y) / 2.0f;
		scene_center.z = (scene_min.z + scene_max.z) / 2.0f;

		printf("scene_center: (%.3f, %.3f, %.3f)\n"
			, scene_center.x, scene_center.y, scene_center.z);
		return 0;
	}
	return 1;
}

/* ---------------------------------------------------------------------------- */
int main(int argc, char **argv)
{
	const char* model_file = NULL;
	C_STRUCT aiLogStream stream;

	// Check and validate the specified model file extension.
	model_file = "D:\\test_3dxml\\Duck1.glb";
	const char* extension = strrchr(model_file, '.');
	if (!extension) {
		print_error("Please provide a file with a valid extension.");
		return EXIT_FAILURE;
	}

	if (AI_FALSE == aiIsExtensionSupported(extension)) {
		print_error("The specified model file extension is currently "
			"unsupported in Assimp " ASSIMP_VERSION ".");
		return EXIT_FAILURE;
	}

	stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT,NULL);
	aiAttachLogStream(&stream);
	stream = aiGetPredefinedLogStream(aiDefaultLogStream_FILE,"assimp_log.txt");
	aiAttachLogStream(&stream);

	// Load the model file.
	if(0 != loadasset(model_file)) {
		print_error("Failed to load model. Please ensure that the specified file exists.");
		aiDetachAllLogStreams();
		return EXIT_FAILURE;
	}

	// Print the model data.
	recursive_render(scene, scene->mRootNode);

	// Relese
	aiReleaseImport(scene);
	aiDetachAllLogStreams();
	return EXIT_SUCCESS;
}
  • 運(yùn)行結(jié)果如下:
    (1)加載gltf1.0的模型文件:Duck1.glb
    【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)
    (2)加載gltf2.0的模型文件:Avocado2.glb
    【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)

7、gltflib (v2.0, python)

https://pypi.org/project/gltflib/

Library for parsing, creating, and converting glTF 2.0 files in Python 3.6+.

This library is intended for working with glTF 2.0 at a fairly low level, meaning you are responsible for managing the actual geometry data yourself. This library facilitates saving this data into a properly formatted glTF/GLB file. It also helps with converting resources inside a glTF/GLB file between external files or web URLs, data URLs, and embedded GLB resources.

pip install gltflib

【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)

7.1 Parsing a glTF 2.0 Model

from gltflib import GLTF

gltf = GLTF.load('D:/glTF-Sample-Models/2.0/BoxTextured/gltf/BoxTextured.gltf')
# print(gltf.model)

print(gltf.model.buffers[0].uri)
print(gltf.resources)
resource = gltf.resources[0]
print(resource)

【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)

7.2 Exporting a glTF 2.0 Model

import struct
import operator
from gltflib import (
    GLTF, GLTFModel, Asset, Scene, Node, Mesh, Primitive, Attributes, Buffer, BufferView, Accessor, AccessorType,
    BufferTarget, ComponentType, GLBResource, FileResource)

vertices = [
    (-4774424.719997984, 4163079.2597148907, 671001.6353722484),
    (-4748098.650098154, 4163079.259714891, 837217.8990777463),
    (-4689289.5292739635, 4246272.966707474, 742710.4976137652)
]

vertex_bytearray = bytearray()
for vertex in vertices:
    for value in vertex:
        vertex_bytearray.extend(struct.pack('f', value))
bytelen = len(vertex_bytearray)
mins = [min([operator.itemgetter(i)(vertex) for vertex in vertices]) for i in range(3)]
maxs = [max([operator.itemgetter(i)(vertex) for vertex in vertices]) for i in range(3)]
model = GLTFModel(
    asset=Asset(version='2.0'),
    scenes=[Scene(nodes=[0])],
    nodes=[Node(mesh=0)],
    meshes=[Mesh(primitives=[Primitive(attributes=Attributes(POSITION=0))])],
    buffers=[Buffer(byteLength=bytelen, uri='vertices.bin')],
    bufferViews=[BufferView(buffer=0, byteOffset=0, byteLength=bytelen, target=BufferTarget.ARRAY_BUFFER.value)],
    accessors=[Accessor(bufferView=0, byteOffset=0, componentType=ComponentType.FLOAT.value, count=len(vertices),
                        type=AccessorType.VEC3.value, min=mins, max=maxs)]
)

resource = FileResource('vertices.bin', data=vertex_bytearray)
gltf = GLTF(model=model, resources=[resource])
gltf.export('triangle.gltf')
# gltf.export('triangle.glb')

7.3 Converting Between glTF and GLB

from gltflib import GLTF

gltf = GLTF.load('D:/glTF-Sample-Models/2.0/BoxTextured/gltf/BoxTextured.gltf')
gltf.export('D:/BoxTextured.glb')
from gltflib import GLTF

gltf = GLTF.load('D:/glTF-Sample-Models/2.0/BoxTextured/glTF-Binary/BoxTextured.glb')
glb_resource = gltf.get_glb_resource()
gltf.convert_to_file_resource(glb_resource, 'BoxTextured.bin')
gltf.export('D:/BoxTextured.gltf')

相關(guān)測(cè)試代碼見(jiàn)網(wǎng)址鏈接:
https://download.csdn.net/download/hhy321/85182743

8、three.js(v2.0, javascript)

8.1 下載和編譯

https://github.com/mrdoob/three.js

下載GitHub代碼:

git clone --depth=1 https://github.com/mrdoob/three.js.git

使用npm編譯代碼:

npm install
npm start
or 
npm run dev

【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀取(C++,Python)

8.2 官網(wǎng)代碼示意

  • 代碼1:
import * as THREE from 'three';

// init

const camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 );
camera.position.z = 1;

const scene = new THREE.Scene();

const geometry = new THREE.BoxGeometry( 0.2, 0.2, 0.2 );
const material = new THREE.MeshNormalMaterial();

const mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );

const renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( animation );
document.body.appendChild( renderer.domElement );

// animation

function animation( time ) {

	mesh.rotation.x = time / 2000;
	mesh.rotation.y = time / 1000;

	renderer.render( scene, camera );

}
  • 代碼2:
<script type="module">
	import * as THREE from 'three';
	import Stats from './jsm/libs/stats.module.js';
	import { GUI } from './jsm/libs/lil-gui.module.min.js';
	import { GLTFLoader } from './jsm/loaders/GLTFLoader.js';
	import { GPUComputationRenderer } from './jsm/misc/GPUComputationRenderer.js';

	/* TEXTURE WIDTH FOR SIMULATION */
	const WIDTH = 64;
	const BIRDS = WIDTH * WIDTH;

	/* BAKE ANIMATION INTO TEXTURE and CREATE GEOMETRY FROM BASE MODEL */
	const BirdGeometry = new THREE.BufferGeometry();
	let textureAnimation, durationAnimation, birdMesh, materialShader, indicesPerBird;

	function nextPowerOf2( n ) {
		return Math.pow( 2, Math.ceil( Math.log( n ) / Math.log( 2 ) ) );
	}

	Math.lerp = function ( value1, value2, amount ) {
		amount = Math.max( Math.min( amount, 1 ), 0 );
		return value1 + ( value2 - value1 ) * amount;
	};

	const gltfs = [ 'models/gltf/Parrot.glb', 'models/gltf/Flamingo.glb' ];
	const colors = [ 0xccFFFF, 0xffdeff ];
	const sizes = [ 0.2, 0.1 ];
	const selectModel = Math.floor( Math.random() * gltfs.length );
	new GLTFLoader().load( gltfs[ selectModel ], function ( gltf ) {
		//.........
		//.........
		//.........
	}
	
//.........	
//.........	
//.........
</script>

【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)

【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀取(C++,Python)

結(jié)語(yǔ)

如果您覺(jué)得該方法或代碼有一點(diǎn)點(diǎn)用處,可以給作者點(diǎn)個(gè)贊,或打賞杯咖啡;╮( ̄▽?zhuān)?╭
如果您感覺(jué)方法或代碼不咋地//(ㄒoㄒ)//,就在評(píng)論處留言,作者繼續(xù)改進(jìn);o_O???
如果您需要相關(guān)功能的代碼定制化開(kāi)發(fā),可以留言私信作者;(????)
感謝各位童鞋們的支持!( ′ ▽′ )? ( ′ ▽′)っ!??!

【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-400839.html

到了這里,關(guān)于【CAD開(kāi)發(fā)】glTF和b3dm文件格式讀?。–++,Python)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 3DM/PLY格式在線(xiàn)轉(zhuǎn)換

    3DM/PLY格式在線(xiàn)轉(zhuǎn)換

    3D模型在線(xiàn)轉(zhuǎn)換(https://3dconvert.nsdt.cloud/)是一個(gè)可以進(jìn)行3D模型格式轉(zhuǎn)換的在線(xiàn)工具,支持多種3D模型格式進(jìn)行在線(xiàn)預(yù)覽和互相轉(zhuǎn)換。 3DM是一種常用的三維模型文件格式,具有多種幾何體和材質(zhì),文件大小較小,兼容性較好,適用于工業(yè)設(shè)計(jì)、建筑設(shè)計(jì)、產(chǎn)品設(shè)計(jì)、數(shù)字藝術(shù)

    2024年02月04日
    瀏覽(19)
  • 3DM/XYZ格式在線(xiàn)轉(zhuǎn)換

    3DM/XYZ格式在線(xiàn)轉(zhuǎn)換

    3D模型在線(xiàn)轉(zhuǎn)換(https://3dconvert.nsdt.cloud/)是一個(gè)可以進(jìn)行3D模型格式轉(zhuǎn)換的在線(xiàn)工具,支持多種3D模型格式進(jìn)行在線(xiàn)預(yù)覽和互相轉(zhuǎn)換。 3DM是一種常用的三維模型文件格式,具有多種幾何體和材質(zhì),文件大小較小,兼容性較好,適用于工業(yè)設(shè)計(jì)、建筑設(shè)計(jì)、產(chǎn)品設(shè)計(jì)、數(shù)字藝術(shù)

    2024年02月03日
    瀏覽(30)
  • 【衛(wèi)星三維重建】衛(wèi)星影像三維重建數(shù)據(jù)集-MVS3DM數(shù)據(jù)集介紹

    【衛(wèi)星三維重建】衛(wèi)星影像三維重建數(shù)據(jù)集-MVS3DM數(shù)據(jù)集介紹

    MVS3DM數(shù)據(jù)集是用于IARPA多視圖衛(wèi)星影像3D重建挑戰(zhàn)賽的標(biāo)準(zhǔn)數(shù)據(jù)集(IARPA Multi-View Stereo 3D Mapping Challenge),該數(shù)據(jù)集由Digital Globe WorldView-3衛(wèi)星影像以及機(jī)載激光雷達(dá)獲取的影像覆蓋范圍內(nèi)的點(diǎn)云數(shù)據(jù)作為算法真值數(shù)據(jù)組成。 衛(wèi)星影像數(shù)據(jù)類(lèi)型和數(shù)量 :包含50張WorldView3全色影像(

    2024年03月12日
    瀏覽(310)
  • Unity CAD(dxf)文件讀取

    Unity CAD(dxf)文件讀取

    讀取后經(jīng)過(guò)處理的效果 dxf文件讀取(包含讀取demo) unity 需要切換到.NET Framework或.NET 4.0 CADReadDemo.unitypackage 新建場(chǎng)景,把VerySimpleReadDemo腳本掛到任意物體上,填入dxf文件路徑,設(shè)置需要讀取的層級(jí)名稱(chēng): 運(yùn)行即可在控制臺(tái)看到輸出日志 首先輸出所有的層級(jí)名稱(chēng): 然后輸出知道

    2024年02月19日
    瀏覽(16)
  • 輕量級(jí)3D STEP STL 格式處理 SDK 之CAD DLL C++ Crack

    輕量級(jí)3D STEP STL 格式處理 SDK 之CAD DLL C++ Crack

    CAD DLL ?allows adding? CAD ?functionality to applications in different languages that support? DLL ?technology. The library can be used in a vast range of industrial sectors: mechanical engineering, building, circuit technology, cartography, analytic systems, and many other spheres that involve work with CAD. If you need a library compatible with Linux

    2024年02月10日
    瀏覽(20)
  • 如何使用 ThreeJs 以 glTF、FBX 和 OBJ 文件格式加載 3D 模型,使用 ThreeJS 加載和顯示帶有紋理的 3D 模型

    在本文中,我展示了如何使用 ThreeJS 在 Web 視圖中加載 3D 模型。Three.js 是一個(gè)跨瀏覽器的 JavaScript 庫(kù)和應(yīng)用程序編程接口,用于使用 WebGL 在 Web 瀏覽器中創(chuàng)建和顯示動(dòng)畫(huà) 3D 計(jì)算機(jī)圖形。加載不完整的原因有很多,例如紋理和材質(zhì)渲染不正確。 創(chuàng)建場(chǎng)景 渲染場(chǎng)景 動(dòng)畫(huà)立方體

    2023年04月08日
    瀏覽(32)
  • Panda3d如何獲取到可用的模型?Maya、3D Max、OBJ等3D格式轉(zhuǎn)換為egg、gltf文件

    Panda3d如何獲取到可用的模型?Maya、3D Max、OBJ等3D格式轉(zhuǎn)換為egg、gltf文件

    ? 使用Panda3d進(jìn)行3D環(huán)境建模也有一段時(shí)間了,真的是被折磨的頭禿。。。不過(guò)也不得不說(shuō),Panda3D也確實(shí)是一個(gè)比較優(yōu)秀的3D游戲引擎,還是能滿(mǎn)足你的大部分需要的。 ? 如果你在深入使用Panda3d后,我相信有個(gè)問(wèn)題那絕對(duì)是讓人頭大的,那就是模型問(wèn)題。對(duì)于沒(méi)有學(xué)過(guò)3D建模

    2024年02月05日
    瀏覽(54)
  • vue-3d-model js在線(xiàn)預(yù)覽obj,dae,ply,json,fbx,stl,gltf格式的3D文件

    vue-3d-model js在線(xiàn)預(yù)覽obj,dae,ply,json,fbx,stl,gltf格式的3D文件

    在線(xiàn)預(yù)覽地址vue-3d-model js在線(xiàn)預(yù)覽obj,dae,ply,json,fbx,stl,gltf格式的3D文件 效果: 例子使用了.obj 3D文件格式,自帶了截圖和旋轉(zhuǎn)功能,其他的3D格式只需要切換一個(gè)vue的模板標(biāo)簽即可。具體標(biāo)簽格式如下: 可支持obj,dae,ply,json,fbx,stl,gltf等格式的3D文件格式顯示。只需要單頁(yè)面html即

    2024年02月12日
    瀏覽(26)
  • Python讀取文件相對(duì)路徑理解以及文件讀取路徑格式

    Python讀取文件相對(duì)路徑理解以及文件讀取路徑格式

    絕對(duì)路徑 :指的是是當(dāng)前文件在 計(jì)算機(jī)磁盤(pán)中存放的具體位置 就是死的,物理上面的 相對(duì)路徑 :指的是文件 相對(duì)于當(dāng)前的py文件所處的位置 。就是參照py文件來(lái)說(shuō)明路徑,參照物嘛 讀取文件路徑方式(path.xls文件為例子) ? 執(zhí)行命令的py文件同path.xls文件在同一個(gè)目錄an

    2024年02月06日
    瀏覽(28)
  • 【CAD二次開(kāi)發(fā)】重新加載acad.pgp快捷菜單文件

    【CAD二次開(kāi)發(fā)】重新加載acad.pgp快捷菜單文件

    為了加快繪圖速度,好多人會(huì)進(jìn)行CAD快捷命令的修改,那怎么在不需要重啟CAD的情況下自動(dòng)更新? CAD修改acad.pgp,快捷命令后,自動(dòng)更新。 方法一 命令行輸入reinit,命令。 在彈出的窗口中,選擇‘PGP文件’,那么修改后的快捷命令將更新。 方法二 c#代碼的方式

    2024年02月09日
    瀏覽(25)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包