add full support for locations, better helpers and more server fixes

This commit is contained in:
Yeicor
2024-03-02 23:00:07 +01:00
parent a2a14ca257
commit c51ddade4b
9 changed files with 198 additions and 224 deletions

View File

@@ -1,6 +1,7 @@
import importlib.metadata
import numpy as np
from build123d import Location, Plane, Vector
from pygltflib import *
_checkerboard_image_bytes = base64.decodebytes(
@@ -11,22 +12,22 @@ _checkerboard_image_bytes = base64.decodebytes(
class GLTFMgr:
"""A utility class to build our GLTF2 objects easily and incrementally"""
gltf: GLTF2 = GLTF2(
asset=Asset(generator=f"yacv_server@{importlib.metadata.version('yacv_server')}"),
scene=0,
scenes=[Scene(nodes=[0])],
nodes=[Node(mesh=0)],
meshes=[Mesh(primitives=[])],
accessors=[],
bufferViews=[BufferView(buffer=0, byteLength=len(_checkerboard_image_bytes), byteOffset=0)],
buffers=[Buffer(byteLength=len(_checkerboard_image_bytes))],
samplers=[Sampler(magFilter=NEAREST)],
textures=[Texture(source=0, sampler=0)],
images=[Image(bufferView=0, mimeType='image/png')],
)
def __init__(self):
self.gltf = GLTF2(
asset=Asset(generator=f"yacv_server@{importlib.metadata.version('yacv_server')}"),
scene=0,
scenes=[Scene(nodes=[0])],
nodes=[Node(mesh=0)],
meshes=[Mesh(primitives=[])],
accessors=[],
bufferViews=[BufferView(buffer=0, byteLength=len(_checkerboard_image_bytes), byteOffset=0)],
buffers=[Buffer(byteLength=len(_checkerboard_image_bytes))],
samplers=[Sampler(magFilter=NEAREST)],
textures=[Texture(source=0, sampler=0)],
images=[Image(bufferView=0, mimeType='image/png')],
)
self.gltf.set_binary_blob(_checkerboard_image_bytes)
# TODO: Custom image support for loading textured planes as CAD objects
def add_face(self, vertices_raw: List[Tuple[float, float, float]], indices_raw: List[Tuple[int, int, int]],
tex_coord_raw: List[Tuple[float, float]]):
@@ -36,12 +37,12 @@ class GLTFMgr:
tex_coord = np.array([[t[0], t[1]] for t in tex_coord_raw], dtype=np.float32)
self._add_any(vertices, indices, tex_coord, mode=TRIANGLES, material="face")
def add_edge(self, vertices_raw: List[Tuple[float, float, float]]):
def add_edge(self, vertices_raw: List[Tuple[float, float, float]], mat: str = None):
"""Add an edge to the GLTF as a new primitive of the unique mesh"""
vertices = np.array([[v[0], v[1], v[2]] for v in vertices_raw], dtype=np.float32)
indices = np.array(list(map(lambda i: [i, i + 1], range(len(vertices) - 1))), dtype=np.uint32)
tex_coord = np.array([])
self._add_any(vertices, indices, tex_coord, mode=LINE_STRIP, material="edge")
self._add_any(vertices, indices, tex_coord, mode=LINE_STRIP, material=mat or "edge")
def add_vertex(self, vertex: Tuple[float, float, float]):
"""Add a vertex to the GLTF as a new primitive of the unique mesh"""
@@ -50,6 +51,19 @@ class GLTFMgr:
tex_coord = np.array([], dtype=np.float32)
self._add_any(vertices, indices, tex_coord, mode=POINTS, material="vertex")
def add_location(self, loc: Location):
"""Add a location to the GLTF as a new primitive of the unique mesh"""
pl = Plane(loc)
def vert(v: Vector) -> Tuple[float, float, float]:
return v.X, v.Y, v.Z
# Add 1 origin vertex and 3 edges with custom colors to identify the X, Y and Z axis
self.add_vertex(vert(pl.origin))
self.add_edge([vert(pl.origin), vert(pl.origin + pl.x_dir)], mat="locX")
self.add_edge([vert(pl.origin), vert(pl.origin + pl.y_dir)], mat="locY")
self.add_edge([vert(pl.origin), vert(pl.origin + pl.z_dir)], mat="locZ")
def add_material(self, kind: str) -> int:
"""It is important to use a different material for each primitive to be able to change them at runtime"""
new_material: Material
@@ -62,6 +76,15 @@ class GLTFMgr:
elif kind == "vertex":
new_material = Material(name="vertex", alphaCutoff=None, pbrMetallicRoughness=PbrMetallicRoughness(
baseColorFactor=[0, 0.3, 0.3, 1]))
elif kind == "locX":
new_material = Material(name="locX", alphaCutoff=None, pbrMetallicRoughness=PbrMetallicRoughness(
baseColorFactor=[0.97, 0.24, 0.24, 1]))
elif kind == "locY":
new_material = Material(name="locY", alphaCutoff=None, pbrMetallicRoughness=PbrMetallicRoughness(
baseColorFactor=[0.42, 0.8, 0.15, 1]))
elif kind == "locZ":
new_material = Material(name="locZ", alphaCutoff=None, pbrMetallicRoughness=PbrMetallicRoughness(
baseColorFactor=[0.09, 0.55, 0.94, 1]))
else:
raise ValueError(f"Unknown material kind {kind}")
self.gltf.materials.append(new_material)
@@ -129,9 +152,9 @@ class GLTFMgr:
) if len(tex_coord) > 0 else None
] if it is not None])
binary_blob = self.gltf.binary_blob()
byte_offset_base = len(binary_blob)
self.gltf.bufferViews.extend([it for it in [
prev_binary_blob = self.gltf.binary_blob()
byte_offset_base = len(prev_binary_blob)
self.gltf.bufferViews.extend([bv for bv in [
BufferView(
buffer=0,
byteOffset=byte_offset_base,
@@ -149,131 +172,7 @@ class GLTFMgr:
byteOffset=byte_offset_base + len(indices_blob) + len(vertices_blob),
byteLength=len(tex_coord_blob),
target=ARRAY_BUFFER,
) if len(tex_coord) > 0 else None
] if it is not None])
)
] if bv.byteLength > 0])
self.gltf.set_binary_blob(binary_blob + indices_blob + vertices_blob + tex_coord_blob)
#
#
# def create_gltf(vertices: np.ndarray, indices: np.ndarray, tex_coord: np.ndarray, mode: int = TRIANGLES,
# material: Optional[Material] = None, images: Optional[List[Image]] = None) -> GLTF2:
# """Create a glTF object from vertices and optionally indices.
#
# If indices are not set, vertices are interpreted as line_strip."""
#
# assert vertices.ndim == 2
# assert vertices.shape[1] == 3
# vertices = vertices.astype(np.float32)
# vertices_blob = vertices.tobytes()
# # print(vertices)
#
# indices = indices.astype(np.uint8)
# indices_blob = indices.flatten().tobytes()
# # print(indices)
#
# tex_coord = tex_coord.astype(np.float32)
# tex_coord_blob = tex_coord.tobytes()
# # print(tex_coord)
#
# if images is None:
# images = []
# image_blob = b''
# image_blob_pointers = []
# for i, img in enumerate(images):
# image_blob = img_to_blob(i, image_blob, image_blob_pointers, images, img)
#
# gltf = GLTF2(
# scene=0,
# scenes=[Scene(nodes=[0])],
# nodes=[Node(mesh=0)],
# meshes=[
# Mesh(
# primitives=[
# Primitive(
# attributes=Attributes(POSITION=1, TEXCOORD_0=2) if len(tex_coord) > 0 else Attributes(
# POSITION=1),
# indices=0,
# mode=mode,
# material=0 if material is not None else None,
# )
# ]
# )
# ],
# materials=[material] if material is not None else [],
# accessors=[
# Accessor(
# bufferView=0,
# componentType=UNSIGNED_BYTE,
# count=indices.size,
# type=SCALAR,
# max=[int(indices.max())],
# min=[int(indices.min())],
# ),
# Accessor(
# bufferView=1,
# componentType=FLOAT,
# count=len(vertices),
# type=VEC3,
# max=vertices.max(axis=0).tolist(),
# min=vertices.min(axis=0).tolist(),
# ),
# ] + ([
# Accessor(
# bufferView=2,
# componentType=FLOAT,
# count=len(tex_coord),
# type=VEC2,
# max=tex_coord.max(axis=0).tolist(),
# min=tex_coord.min(axis=0).tolist(),
# )] if len(tex_coord) > 0 else [])
# ,
# bufferViews=[
# BufferView(
# buffer=0,
# byteLength=len(indices_blob),
# target=ELEMENT_ARRAY_BUFFER,
# ),
# BufferView(
# buffer=0,
# byteOffset=len(indices_blob),
# byteLength=len(vertices_blob),
# target=ARRAY_BUFFER,
# ),
# ] + (
# [
# BufferView(
# buffer=0,
# byteOffset=len(indices_blob) + len(vertices_blob),
# byteLength=len(tex_coord_blob),
# target=ARRAY_BUFFER,
# ),
# ] if len(tex_coord) > 0 else []) + (
# [
# BufferView(
# buffer=0,
# byteOffset=len(indices_blob) + len(
# vertices_blob) + len(tex_coord_blob) + image_blob_pointers[i],
# byteLength=image_blob_pointers[i + 1] - image_blob_pointers[i] if i + 1 < len(
# image_blob_pointers) else len(image_blob) - image_blob_pointers[i],
# )
# for i, img in enumerate(images)
# ] if len(images) > 0 else []),
# buffers=[
# Buffer(
# byteLength=len(indices_blob) + len(vertices_blob) + len(tex_coord_blob) + len(image_blob),
# )
# ],
# samplers=[Sampler(magFilter=NEAREST)] if len(images) > 0 else [],
# textures=[Texture(source=i, sampler=0) for i, _ in enumerate(images)],
# images=images,
# )
#
# gltf.set_binary_blob(indices_blob + vertices_blob + tex_coord_blob + image_blob)
#
# return gltf
def img_blob(img: Image) -> bytes:
return base64.decodebytes(img.uri.split('base64,', maxsplit=1)[1].encode('ascii'))
self.gltf.set_binary_blob(prev_binary_blob + indices_blob + vertices_blob + tex_coord_blob)