GenMake-Crystal-Engine / glb_export.py
mhtbhatia's picture
Upload 12 files
cb789b0 verified
import numpy as np
import os
from pygltflib import (
GLTF2, Scene, Node, Mesh, Primitive,
Buffer, BufferView, Accessor, Asset, ARRAY_BUFFER
)
def export_pointcloud_glb(points_xyz: np.ndarray, out_path: str):
"""
points_xyz: (N,3) float32 in mm coordinates (X,Y,Z)
Writes a strict GLB that XCS can import as a point cloud.
Crucial Fix: Injects COLOR_0 (pure white) so the F2 Ultra UV fires.
"""
os.makedirs(os.path.dirname(out_path), exist_ok=True)
pos_xyz = points_xyz.astype(np.float32)
# FORCE WHITE COLOR FOR LASER POWER
col = np.ones((pos_xyz.shape[0], 3), dtype=np.float32)
pos_bytes = pos_xyz.tobytes()
col_bytes = col.tobytes()
blob = pos_bytes + col_bytes
bv_pos = BufferView(buffer=0, byteOffset=0, byteLength=len(pos_bytes), target=ARRAY_BUFFER)
bv_col = BufferView(buffer=0, byteOffset=len(pos_bytes), byteLength=len(col_bytes), target=ARRAY_BUFFER)
min_xyz = pos_xyz.min(axis=0).tolist()
max_xyz = pos_xyz.max(axis=0).tolist()
acc_pos = Accessor(
bufferView=0,
byteOffset=0,
componentType=5126, # FLOAT
count=pos_xyz.shape[0],
type="VEC3",
min=min_xyz,
max=max_xyz
)
acc_col = Accessor(
bufferView=1,
byteOffset=0,
componentType=5126, # FLOAT
count=col.shape[0],
type="VEC3"
)
prim = Primitive(attributes={"POSITION": 0, "COLOR_0": 1}, mode=0)
mesh = Mesh(primitives=[prim])
gltf = GLTF2(
asset=Asset(version="2.0"),
scene=0,
scenes=[Scene(nodes=[0])],
nodes=[Node(mesh=0)],
meshes=[mesh],
buffers=[Buffer(byteLength=len(blob))],
bufferViews=[bv_pos, bv_col],
accessors=[acc_pos, acc_col],
)
gltf.set_binary_blob(blob)
gltf.save(out_path)