File size: 4,137 Bytes
ec0c8fa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
from typing import *
from pathlib import Path

import numpy as np


def write_glb(path: Union[str, Path], vertices: np.ndarray, faces: np.ndarray, vertex_colors: np.ndarray = None,  uv: np.ndarray = None):
    import pygltflib

    has_colors = vertex_colors is not None
    has_uv = uv is not None

    triangles_bytes = faces.astype(np.uint32).flatten().tobytes()
    vertices_bytes = vertices.astype(np.float32).tobytes()
    vertex_colors_bytes = vertex_colors.astype(np.float32).tobytes() if has_colors else None
    uv_bytes = uv.astype(np.float32).tobytes() if has_uv else None


    gltf = pygltflib.GLTF2(
        scene=0,
        scenes=[pygltflib.Scene(nodes=[0])],
        nodes=[pygltflib.Node(mesh=0)],
        meshes=[
            pygltflib.Mesh(
                primitives=[
                    pygltflib.Primitive(
                        attributes=pygltflib.Attributes(
                            POSITION=1, 
                            COLOR_0=2 if has_colors else None, 
                            TEXCOORD_0=2 + has_colors if has_uv else None
                        ), 
                        indices=0
                    )
                ]
            )
        ],
        accessors=list(filter(None, [
            pygltflib.Accessor(     # triangles accessor
                bufferView=0,
                componentType=pygltflib.UNSIGNED_INT,
                count=faces.size,
                type=pygltflib.SCALAR,
                max=[int(faces.max())],
                min=[int(faces.min())],
            ),
            pygltflib.Accessor(     # vertices accessor
                bufferView=1,
                componentType=pygltflib.FLOAT,
                count=len(vertices),
                type=pygltflib.VEC3,
                max=vertices.max(axis=0).tolist(),
                min=vertices.min(axis=0).tolist(),
            ),
            pygltflib.Accessor(     # vertex colors accessor
                bufferView=2,
                componentType=pygltflib.FLOAT,
                count=len(vertices),
                type=pygltflib.VEC3,
                max=vertex_colors.max(axis=0).tolist(),
                min=vertex_colors.min(axis=0).tolist(),
            ) if has_colors else None,
            pygltflib.Accessor(     # uv accessor
                bufferView=3,
                componentType=pygltflib.FLOAT,
                count=len(uv),
                type=pygltflib.VEC2,
                max=uv.max(axis=0).tolist(),
                min=uv.min(axis=0).tolist(),
            ) if has_uv else None,
        ])),
        bufferViews=list(filter(None, [
            pygltflib.BufferView(    # triangles buffer view
                buffer=0,
                byteLength=len(triangles_bytes),
                target=pygltflib.ELEMENT_ARRAY_BUFFER,
            ),
            pygltflib.BufferView(    # vertices buffer view
                buffer=0,
                byteOffset=len(triangles_bytes),
                byteLength=len(vertices_bytes),
                target=pygltflib.ARRAY_BUFFER,
            ),
            pygltflib.BufferView(    # vertex colors buffer view
                buffer=0,
                byteOffset=len(triangles_bytes) + len(vertices_bytes),
                byteLength=len(vertex_colors_bytes),
                target=pygltflib.ARRAY_BUFFER,
            ) if has_colors else None,
            pygltflib.BufferView(    # uv buffer view
                buffer=0,
                byteOffset=len(triangles_bytes) + len(vertices_bytes) + (len(vertex_colors_bytes) if has_colors else 0),
                byteLength=len(uv_bytes),
                target=pygltflib.ARRAY_BUFFER,
            ) if has_uv else None,
        ])),
        buffers=[
            pygltflib.Buffer(
                byteLength=len(triangles_bytes) + len(vertices_bytes) + (len(vertex_colors_bytes) if has_colors else 0) + (len(uv_bytes) if has_uv else 0),
            )
        ]
    )
    gltf.set_binary_blob(triangles_bytes + vertices_bytes + (vertex_colors_bytes or b'') + (uv_bytes or b''))
    with open(path, 'wb') as f:
        for chunk in gltf.save_to_bytes():
            f.write(chunk)