Loading...
墨滴

张春成

2021/09/07  阅读:16  主题:默认主题

ParseGLTF

ParseGLTF

解析GLTF文件的代码。


Parse GLTF and GLB Files

Parse the 3D model of .gltf and .glb files into

  • vertex: The vertex of the 3D models;
  • mesh: The 3-vertex mesh element of the 3D models.
import os
import base64
import struct

import pandas as pd

import plotly.express as px
import plotly.graph_objects as go
import numpy as np

from gltflib import GLTF

File Name Setup

fname = r'3dModel/deer-printable.glb'
fname = r'3dModel/fullDeer.glb'

Excellent Functions

def parse_gltf(fname):
    '''
    Parse the GLTF or GLB file,

    '''


    gltf = GLTF.load(fname)
    gltf.convert_to_base64_resource(gltf.resources[0])
    gltf.export_gltf(fname + '.gltf')

    resources = gltf.resources
    bufferViews = gltf.model.bufferViews
    accessors = gltf.model.accessors

    return resources, bufferViews, accessors

def parse_buffer(resources, idx):
    '''
    Parse buffer from the resources of idx.
    '''


    buffer = resources[idx]

    bins = buffer.uri.split(','1)[1]

    # ! Make sure you are using the correct decoder
    packed = base64.b64decode(bins)

    describe = dict(
        fname=fname,
        buffer=buffer,
        mime_type=buffer.mime_type,
        uri_header=buffer.uri[:80],
        uri_length=len(buffer.uri),
        bins_header=bins[:80],
        bins_length=len(bins),
    )

    return describe, bins, packed

def parse_accessor(ac, resources, bufferViews):
    '''
    Parse the data of the accessor [ac]
    '''


    bv = bufferViews[ac.bufferView]

    describe, bins, packed = parse_buffer(resources, bv.buffer)
    packed_bytes = packed[bv.byteOffset: bv.byteOffset + bv.byteLength]

    ctype = ac.componentType

    d = struct.unpack(componentTypes[ctype][2].format(ac.count * types[ac.type]), packed_bytes)
    d = np.array(d).reshape((-1, types[ac.type]))

    return d
componentTypes = {
    5126: ['FLOAT'4'<{}f'],
    5123: ['UNSIGNED_SHORT'2'<{}H'], # ? Not so sure about this.
}

types = {
    'VEC4'4,
    'VEC3'3,
    'VEC2'2,
    'SCALAR'1,
}

Check What We Got

The accessors with valid max and min attributes are the vertex accessors.

resources, bufferViews, accessors = parse_gltf(fname)

display(resources)

display(bufferViews)

display(accessors)
[Base64Resource(15992380 bytes)]



[BufferView(extensions=None, extras=None, name=None, buffer=0, byteOffset=0, byteLength=98784, byteStride=None, target=34963),
 BufferView(extensions=None, extras=None, name=None, buffer=0, byteOffset=98784, byteLength=114372, byteStride=None, target=34962),
 BufferView(extensions=None, extras=None, name=None, buffer=0, byteOffset=213156, byteLength=114372, byteStride=None, target=34962),
 BufferView(extensions=None, extras=None, name=None, buffer=0, byteOffset=327528, byteLength=76248, byteStride=None, target=34962),
 BufferView(extensions=None, extras=None, name=None, buffer=0, byteOffset=403776, byteLength=6148885, byteStride=None, target=None),
 BufferView(extensions=None, extras=None, name=None, buffer=0, byteOffset=6552661, byteLength=1117135, byteStride=None, target=None),
 BufferView(extensions=None, extras=None, name=None, buffer=0, byteOffset=7669796, byteLength=6203620, byteStride=None, target=None),
 BufferView(extensions=None, extras=None, name=None, buffer=0, byteOffset=13873416, byteLength=2118963, byteStride=None, target=None)]



[Accessor(extensions=None, extras=None, name=None, bufferView=0, byteOffset=None, componentType=5123, normalized=None, count=49392, type='SCALAR', max=None, min=None, sparse=None),
 Accessor(extensions=None, extras=None, name=None, bufferView=1, byteOffset=None, componentType=5126, normalized=None, count=9531, type='VEC3', max=[2.438467025756836, 6.775949001312256, 3.775106906890869], min=[-1.54141104221344, -0.01114455983042717, -1.244312047958374], sparse=None),
 Accessor(extensions=None, extras=None, name=None, bufferView=2, byteOffset=None, componentType=5126, normalized=None, count=9531, type='VEC3', max=None, min=None, sparse=None),
 Accessor(extensions=None, extras=None, name=None, bufferView=3, byteOffset=None, componentType=5126, normalized=None, count=9531, type='VEC2', max=None, min=None, sparse=None)]

Parse from Buffer

And Automatically select the idx_vertex and idx_meshes, I do not if the method works forever.

ds = []
idx_vertex = -1
idx_meshes = -1

for j in range(len(accessors)):
    accessor = accessors[j]

    if accessor.min:
        idx_vertex = j

    d = parse_accessor(accessor, resources, bufferViews)
    ds.append(d)

    if d.shape[1] == 1:
        idx_meshes = j

display(idx_vertex, idx_meshes, [e.shape for e in ds])
1



0



[(49392, 1), (9531, 3), (9531, 3), (9531, 2)]

Check the Data Details

ds[0], ds[1], ds[2], ds[3]
(array([[ 0],
        [ 1],
        [ 2],
        ...,
        [58],
        [56],
        [57]]),
 array([[0.206407  , 4.90350294, 2.95625091],
        [0.195921  , 4.87971783, 2.963691  ],
        [0.19394843, 4.88100863, 2.99142122],
        ...,
        [0.29448101, 5.17738295, 2.49478698],
        [0.306748  , 5.20883894, 2.5882709 ],
        [0.48311001, 5.26201487, 2.5467689 ]]),
 array([[-0.91591316,  0.30660406, -0.25903106],
        [-0.97743601,  0.064569  , -0.201121  ],
        [-0.98845887,  0.05413099,  0.14148799],
        ...,
        [-0.63948184, -0.75505179, -0.14477497],
        [-0.77751702, -0.089656  ,  0.62243801],
        [ 0.88460547,  0.42173076,  0.19903888]]),
 array([[0.32930681, 0.92279738],
        [0.33733615, 0.93756545],
        [0.35515046, 0.93445587],
        ...,
        [0.7043426 , 0.91362393],
        [0.69977868, 0.90015256],
        [0.68084556, 0.96216458]]))

Plot if Things Go Right

d2plot = ds[idx_vertex]

x = d2plot[:, 0]
y = d2plot[:, 1]
z = d2plot[:, 2]

trace = go.Scatter3d(
   x = x, y = y, z = z,mode = 'markers', marker = dict(
      size = 1,
      color = z, # set color to an array/list of desired values
      colorscale = 'Viridis'
      )
   )
layout = go.Layout(title = '3D Scatter plot')
fig = go.Figure(data = [trace], layout = layout)
fig

Save the Results

You may have to change the

  • vertex: The vertex;
  • meshes: The 3-vertex meshes.

to save the correct results.

vertex = ds[idx_vertex]
meshes = ds[idx_meshes]
df_vertex = pd.DataFrame(vertex, columns=['x''y''z'])
df_vertex.to_csv(fname + '-vertex.csv')
df_vertex
x y z
0 0.206407 4.903503 2.956251
1 0.195921 4.879718 2.963691
2 0.193948 4.881009 2.991421
3 0.200583 4.908579 2.986342
4 0.207705 4.903961 3.014799
... ... ... ...
9526 0.335468 5.175738 2.421746
9527 0.316176 5.173036 2.451739
9528 0.294481 5.177383 2.494787
9529 0.306748 5.208839 2.588271
9530 0.483110 5.262015 2.546769

9531 rows × 3 columns

df_meshes = pd.DataFrame(meshes, columns=['id'])
df_meshes.to_csv(fname + '-meshes.csv')
df_meshes
id
0 0
1 1
2 2
3 2
4 3
... ...
49387 649
49388 652
49389 58
49390 56
49391 57

49392 rows × 1 columns

张春成

2021/09/07  阅读:16  主题:默认主题

作者介绍

张春成