gltf是类似于stl、obj、ply等常见的3D对象存储格式,它被设计出来是为了便于渲染的数据转换和传输。如果你的浏览器可以连接外网,可以通过 glTF Viewer 网址打开浏览gltf的3D对象。这里介绍两种语言下从gltf拿到网格的顶点和面片数据。
一、Python
第一步安装pygltflib:
pip install pygltflib
第二步,python解析:
- import pygltflib
- import numpy as np
-
- pathGltf="test.gltf"
- gltf=pygltflib.GLTF2().load(pathGltf)
- scene=gltf.scenes[gltf.scene]
- nodes=[gltf.nodes[node] for node in scenes.nodes]
- vertices=np.arry([node.mesh.primitives[0].attributes["POSITION"] for node in nodes])
- print(vertices)
不知道为什么,通过上面这种方式解析,node.mesh我这里是一个int类型的值,运行代码提示node.mesh没有primitives属性,然后在网上找了下面的代码是ok的:
- import pygltflib
- import pathlib
- import struct
-
- # load a gltf file
- fname = pathlib.Path("C:/Users/User/Desktop/cube.gltf")
- gltf = GLTF2().load(fname)
-
- # get the first mesh in the current scene
- mesh = gltf.meshes[gltf.scenes[gltf.scene].nodes[0]-1]
-
- # get the vertices for each primitive in the mesh
- for primitive in mesh.primitives:
-
- # get the binary data for this mesh primitive from the buffer
- accessor = gltf.accessors[primitive.attributes.POSITION]
- bufferView = gltf.bufferViews[accessor.bufferView]
- buffer = gltf.buffers[bufferView.buffer]
- data = gltf.get_data_from_buffer_uri(buffer.uri)
-
- # pull each vertex from the binary buffer and convert it into a tuple of python floats
- vertices = []
- for i in range(accessor.count):
- index = bufferView.byteOffset + accessor.byteOffset + i*12 # the location in the buffer of this vertex
- d = data[index:index+12] # the vertex data
- v = struct.unpack("
, d) # convert from base64 to three floats - vertices.append(v)
-
- # unpack floats
- vertices2 = []
- for a,b,c in vertices:
- vertices2 += [a,b,c]
-
- # create triangles
- vertices = vertices2
- triangles = []
- for i in range(0,len(vertices),9):
- triangles.append(vertices[i:i+9])
- # print data
- print(triangles)
二、C++解析
c++依赖的库主要是draco,这个库是开源的,网上可以下载,有了draco之后代码如下:
- #include
- #include
-
- // 读取gltf文件
- bool parse_gltf_from_file(const std::string& filename,std::unique_ptr
& mesh) { - draco::GltfDecoder gltfDec;
- draco::StatusOr
> stormesh=gltfDec.DecodeFromFile(filename); - if(!stormesh.ok()){
- return false;
- }
- std::unique_ptr
pDracomesh=std::move(stormesh).value(); - std::cout<<"faces num:"<
num_faces()< - pDracomesh.swap(mesh);
- return true;
- }
-
- //解析出顶点和面片数据
- bool get_faces_vertexes(const std::unique_ptr
& dracomesh, - std::vector
& vertexes, - std::vector
& faces) { - auto dump_attribute_to_vec3=[](const draco::PointAttribute& att,std::vector
& attD){ - if(att.size()==0) return;
- std::vector
tmp(att.size()) ; - for(int i=0;i
size();++i){ - if(!att.ConvertValue<float,3>(draco::AttributeValueIndex(i),&tmp[i][0])) return;
- }
- attD=std::move(tmp);
- }
-
- // 解析顶点
- const draco::PointAttribute* posAtt=nullptr;
- std::vector
points; - for(int i=0;i
num_attributes();++i){ - const draco::PointAttribute* pAtt=dracomesh->attribute(i);
- switch(pAtt->attribute_type()){
- case draco::PointAttribute::POSITION:
- posAtt=pAtt;
- dump_attribute_to_vec3(*pAtt,points);
- break;
- }
- }
- vertexes=points;
-
- // 解析面片
- faces.resize(dracomesh->num_faces());
- for(int i=0;i
num_faces();++i){ - for(int j=0;j<3;++j){
- const draco::PointIndex idx=dracomesh->face(draco::FaceIndex(i))[j];
- faces[i][j]=posAtt->mapped_index(idx).value();
- }
- }
-
- return true;
- }