文章目录

  • 1、简介
    • 1.1 层级结构
    • 1.2 术语定义
  • 2、glTF文件预览
    • 2.1 VSCode(v2.0)
    • 2.2 glTF Viewer(v2.0, js)
    • 2.3 babylon.js(v2.0,js)
  • 3、tinygltf (v2.0, C++)
    • 3.1 下载和编译
    • 3.2 官网代码示例
  • 4、TinyGLTFLoader (v1.0, C++)
    • 4.1 下载和编译
    • 4.2 picojson库
    • 4.3 官网代码示例
    • 4.4 自己测试代码1
    • 4.5 自己测试代码2
  • 5、libgltf (v2.0, C++)
    • 5.1 下载和编译
    • 5.2 nlohmann/json库
    • 5.3 官网代码示例1
    • 5.4 官网代码示例2
    • 5.5 自己测试代码
  • 6、assimp (v1.0, v2.0, C++)
    • 6.1 下载和编译
    • 6.2 官网代码示例
  • 7、gltflib (v2.0, python)
    • 7.1 Parsing a glTF 2.0 Model
    • 7.2 Exporting a glTF 2.0 Model
    • 7.3 Converting Between glTF and GLB
  • 8、three.js(v2.0, javascript)
    • 8.1 下载和编译
    • 8.2 官网代码示意
  • 结语

1、简介

官网地址:
https://www.khronos.org/gltf/

glTF™ 是一种免版税规范,用于通过引擎和应用程序高效传输和加载 3D 场景和模型。
glTF 定义了一种可扩展的发布格式,通过在整个行业中实现 3D 内容的互操作使用来简化创作工作流程和交互式服务。

glTF™(GL 传输格式)用于在 Web 和本机应用程序中传输和加载 3D 模型。glTF 减少了 3D 模型的大小以及解包和渲染这些模型所需的运行时处理。这种格式在 Web 上很常用,并且在 Unity3D、Unreal Engine 4 和 Godot 等各种 3D 引擎中都有支持。

glTF 的内部结构模仿了图形芯片在实时渲染时常用的内存缓冲区,因此可以将资产交付到桌面、Web 或移动客户端,并以最少的处理迅速显示。因此,在导出到 glTF 时,四边形和 n 边形会自动转换为三角形。

b3dm就是在原来gltf单个模型的基础之上,做了批量化的数据组织方式,多了feature table和batch table两个文件。3D Tiles 是一种开放规范,用于在桌面、Web 和移动应用程序中共享、可视化、融合和与大量异构 3D 地理空间内容交互。



1.1 层级结构

  • glTF Object Hierarchy
    这里来几张作者收集的结构图说明gltf的各种对象组成。


1.2 术语定义

glTF 规范使用常见的工程和图形术语,如image、buffer、texture等来识别和描述某些glTF结构及其属性、状态和行为。本节在规范的上下文中定义了这些术语的基本含义。规范文本提供了更完整的术语定义,并详细阐述、扩展或澄清了这些定义。当本节中定义的术语在规范中以规范语言使用时,规范中的定义支配并取代这些术语在其他技术上下文中(即规范之外)可能具有的任何含义。

  • 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文件预览

2.1 VSCode(v2.0)

安装第三方扩展glTF Tool。

  • 打开和预览gltf文件
  • 打开和预览glb文件(gltf二进制格式)

2.2 glTF Viewer(v2.0, js)

https://gltf-viewer.donmccurdy.com/

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.

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).
注意:目前该库仅支持glTF 2.0格式。
它的OpenGL示例编译依赖库需要额外下载。本身就是几个头文件直接使用。

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下载该库的源代码
  • 通过CMake生成该库的vs2017的工程文件
  • 生成的vs2017的工程文件的相关文件截图
  • vs2017打开工程文件,进行编译库文件
  • 也可以通过premake5来生成该库vs2017的工程文件,如下图所示:
  • tinygltf自带例子中一个小例子编译后的运行结果

3.2 官网代码示例

/ 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++)

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

4.1 下载和编译

https://github.com/syoyo/tinygltfloader
注意:目前该库仅支持glTF 1.0格式。
这个库不需要编译,直接引用头文件.h就可以了。

4.2 picojson库

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 官网代码示例

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;
}


4.4 自己测试代码1

根据前面贴的结构图,编写代码遍历gltf1.0文件包含的所有几何数据(顶点、法线、面、纹理坐标、纹理图片数据等)。

//***********************************************************************
//   Purpose:   tiny_gltf_loader遍历gltf v1.0文件的几何数据
//   Author:    爱看书的小沐
//   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 datatinygltf::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.indicesconst 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 datastd::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               5126accessor.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 自己测试代码2

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

//***********************************************************************
//   Purpose:   tiny_gltf_loader增加读取b3dm文件格式的接口
//   Author:    爱看书的小沐
//   Date:      2022-4-19
//   Languages: C++
//   Platform:  Visual Studio 2017
//   OS:        Win10 win64
// ***********************************************************************// 读取b3dm文件的文件头,返回值为头部的长度
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 contentsconst 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的版本号
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文件的所有内容
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.

注意:目前该库仅支持glTF 2.0格式。
它的编译依赖库不不不需要额外下载。

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的源代码,如下图所示:

  • 下载libgltf的源代码的文件夹,如下所示:

  • 通过cmake生成vs2017的工程文件。

  • vs2017打开上面生成的工程文件,编译生成libgltf的库文件,如下图所示:

5.2 nlohmann/json库

https://github.com/nlohmann/json

JSON for Modern C++


代码示例如下:

// 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 官网代码示例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 官网代码示例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;
#elseint error_code = 1;
#endif#if defined(LIBGLTF_CHARACTOR_ENCODING_IS_UNICODE) && defined(LIBGLTF_PLATFORM_WINDOWS)std::wstring input_file_path;
#elsestd::string input_file_path;
#endif{
#if defined(LIBGLTF_CHARACTOR_ENCODING_IS_UNICODE) && defined(LIBGLTF_PLATFORM_WINDOWS)std::wstringstream argument;
#elsestd::stringstream argument;
#endifargument << _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);
#elsestd::shared_ptr<libgltf::IglTFLoader> gltf_loader = libgltf::IglTFLoader::Create(libgltf::UTF8ToUNICODE(input_file_path));
#endif
#elsestd::shared_ptr<libgltf::IglTFLoader> gltf_loader = libgltf::IglTFLoader::Create(input_file_path);
#endifstd::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 futurelibgltf::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

运行结果如下:

5.5 自己测试代码

//***********************************************************************
//   Purpose:   在libgltf代码中增加读取b3dm文件格式的接口
//   Author:    爱看书的小沐
//   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.

Asset-Importer-Lib(简称 assimp)是一个库,用于加载和处理来自各种 3D 数据格式的几何场景。通过支持节点层次结构、静态或蒙皮网格、材质、骨骼动画和潜在纹理数据,它主要针对典型的游戏场景进行定制。但也支持一些 3D 打印和 CAD 格式。

  • 目前assimp库支持如下模型格式的导入:
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官网上下载代码,用cmake默认直接编译即可。

6.2 官网代码示例

  • 代码示例:这是一段加载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);elseprintf("  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_POLYGONint 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 avoidspelling 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);// ReleseaiReleaseImport(scene);aiDetachAllLogStreams();return EXIT_SUCCESS;
}
  • 运行结果如下:
    (1)加载gltf1.0的模型文件:Duck1.glb

    (2)加载gltf2.0的模型文件:Avocado2.glb

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

7.1 Parsing a glTF 2.0 Model

from gltflib import GLTFgltf = 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)

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 GLTFgltf = GLTF.load('D:/glTF-Sample-Models/2.0/BoxTextured/gltf/BoxTextured.gltf')
gltf.export('D:/BoxTextured.glb')
from gltflib import GLTFgltf = 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')

相关测试代码见网址链接:
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

8.2 官网代码示意

  • 代码1:
import * as THREE from 'three';// initconst 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 );// animationfunction 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>

结语

如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;o_O???
如果您需要相关功能的代码定制化开发,可以留言私信作者;(✿◡‿◡)
感谢各位童鞋们的支持!( ´ ▽´ )ノ ( ´ ▽´)っ!!!

【CAD开发】glTF和b3dm文件格式读取(C++,Python)相关推荐

  1. 【CAD开发】gltf文件格式的转换工具汇总(js、python、c++)

    文章目录 1.gltf格式简介 2.C# 代码 2.1 3dsMax/maya导出插件(Babylon.js) 2.python代码 2.1 gltflib (v2.0) 3.JavaScript代码 ...

  2. JavaCV音视频开发宝典:使用JavaCV读取海康平台或海康网络摄像头sdk回调视频TS码流并解析预览图像

    <JavaCV音视频开发宝典>专栏目录导航 <JavaCV音视频开发宝典>专栏介绍和目录 ​ 前言 两年前博主写了如何利用JavaCV解析各种h264裸流,<JavaCV ...

  3. 2021-02-08【Web作业开发记录】Java代码读取文件问题

    [Web作业开发记录]Java代码读取文件问题 1.问题分析 在项目中需要读取properties文件,而对于gradle项目,在java文件夹底下的properties文件在编译打包时会自动忽略,最 ...

  4. 【车载开发系列】UDS诊断---读取内存($0x23)

    [车载开发系列]UDS诊断-读取内存($0x23) UDS诊断---读取内存($0x23) [车载开发系列]UDS诊断---读取内存($0x23) 一.概念定义 二.注意事项 三.报文格式 1)报文请 ...

  5. NX二次开发-ug表达式函数ug_find_file读取当前prt所在路径

    NX二次开发-ug表达式函数ug_find_file读取当前prt所在路径 ug_find_file(ug_askCurrentWorkPart()) 该方法最早是看唐工在QQ群里发的,被我收集了.

  6. 【车载开发系列】UDS诊断---读取DTC信息($0x19)

    [车载开发系列]UDS诊断-读取DTC信息($0x19) UDS诊断---读取DTC信息($0x19) [车载开发系列]UDS诊断---读取DTC信息($0x19) 一.概念定义 1)DTC概念 2) ...

  7. JavaCV音视频开发宝典:使用JavaCV读取海康平台或海康网络摄像头sdk回调录像回放视频PS码流并解析预览图像

    <JavaCV音视频开发宝典>专栏目录导航 <JavaCV音视频开发宝典>专栏介绍和目录 ​ 前言 上一章中<JavaCV音视频开发宝典:使用JavaCV读取海康平台或海 ...

  8. 【沁恒WCH CH32V307V-R1开发板两路ADC读取实验】

    [沁恒WCH CH32V307V-R1开发板两路ADC读取实验] 1. 前言 2. 软件配置 2.1 安装MounRiver Studio 3. ADC项目测试 3.1 打开ADC工程 3.2 编译项 ...

  9. 【车载开发系列】UDS诊断---读取周期标识符($0x2A)

    [车载开发系列]UDS诊断-读取周期标识符($0x2A) UDS诊断---读取周期标识符($0x2A) [车载开发系列]UDS诊断---读取周期标识符($0x2A) 一.概念定义 二.报文格式 1)请 ...

最新文章

  1. CVE-2018-4407 苹果设备远程溢出漏洞
  2. windosw7 Hosts文件的位置
  3. Play Framework 的模板引擎
  4. Android 功耗(9)---MTK功耗基础知识
  5. 从0打卡leetcode之day 3 -- 最大子序列和
  6. 150分试卷c语言,连续5道C语言题目一共送150分啊,题目2.一个农场有头母牛,现 爱问知识人...
  7. Memcached、Redis、RabbitMQ
  8. openssl加解密原理
  9. 【产业互联网周报】AWS 全球换帅,中国区发布战略;杨杰回应回A,中移动计划千亿投5G;全球缺芯潮持续...
  10. 银联手机POS,支付黑科技
  11. 吸引力法则~助攻遇到自己的另一半
  12. matlab代码:基于主从博弈的智能小区代理商定价策略及电动汽车充电管理
  13. 怎样的100位区块链开发者,入选这份严苛至极的特训名单?
  14. HotSpot的新生代三区划分好在哪?
  15. php 跳转邮箱,JS点击跳转登陆邮箱功能简单的实现方法
  16. 我的博客也开通了,誓要戒骄,戒躁,每天学习,每天总结
  17. arm服务器运行onlyoffice
  18. bluedroid key miss问题
  19. 【操作系统】FIFO先进先出页面置换算法(C语言实现)
  20. 注册宝网络验证系统,安全免费的网络验证系统

热门文章

  1. CANdbc编辑器的下载和入门介绍
  2. networkx学习(五)无标度网络
  3. 汽车的杂七杂八-SOME/IP+控制器
  4. python获取网页数据后写入mysql_HTTP协议与使用Python获取数据并写入MySQL
  5. 核心之外的8个必备Maven插件
  6. 【Excel自动化办公Part4】:调整字体与样式的操作——字体、边框、对齐格式、颜色填充
  7. 《SpringBoot2.0 实战》系列-整合thymeleaf 实现模板文件转图片
  8. SDUT java 单词和字符鉴别器
  9. Docker 【Nginx集群部署】
  10. 关于小米mini路由器开启ssh红灯解决