Spaces:
Configuration error
Configuration error
| 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) |