From 266210352b288c8369f40b0174a14fe70e7d18c2 Mon Sep 17 00:00:00 2001 From: Einar Forselv Date: Fri, 6 Dec 2024 16:47:26 +0100 Subject: [PATCH] Read dracu data the extension's own bufferview --- examples/gltf_scenes.py | 8 ++++-- moderngl_window/loaders/scene/gltf2.py | 38 ++++++++++++++++++++------ 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/examples/gltf_scenes.py b/examples/gltf_scenes.py index 36a852f..eff48eb 100644 --- a/examples/gltf_scenes.py +++ b/examples/gltf_scenes.py @@ -33,7 +33,7 @@ def __init__(self, **kwargs): # self.scene = self.load_scene("CesiumMilkTruck/glTF-Embedded/CesiumMilkTruck.gltf") # self.scene = self.load_scene("CesiumMilkTruck/glTF-Binary/CesiumMilkTruck.glb") # self.scene = self.load_scene("CesiumMilkTruck/glTF/CesiumMilkTruck.gltf") - # self.scene = self.load_scene("Sponza/glTF/Sponza.gltf") + self.scene = self.load_scene("Sponza/glTF/Sponza.gltf") # self.scene = self.load_scene("Lantern/glTF-Binary/Lantern.glb") # self.scene = self.load_scene("Buggy/glTF-Binary/Buggy.glb") # self.scene = self.load_scene("VC/glTF-Binary/VC.glb") @@ -67,7 +67,9 @@ def __init__(self, **kwargs): # --- Draco compressed --- # self.scene = self.load_scene("Box/glTF-Draco/Box.gltf") - self.scene = self.load_scene("Buggy/glTF-Draco/Buggy.gltf") + # self.scene = self.load_scene("Buggy/glTF-Draco/Buggy.gltf") + # self.scene = self.load_scene("2CylinderEngine/glTF-Draco/2CylinderEngine.gltf") + # self.scene = self.load_scene("CesiumMilkTruck/glTF-Draco/CesiumMilkTruck.gltf") self.camera = KeyboardCamera( self.wnd.keys, @@ -85,7 +87,7 @@ def __init__(self, **kwargs): self.camera.position = ( self.scene.get_center() - + glm.vec3(0.0, 0.0, self.scene.diagonal_size / 2.0) + + glm.vec3(0.0, 0.0, self.scene.diagonal_size / 1.75) ) def on_render(self, time: float, frame_time: float): diff --git a/moderngl_window/loaders/scene/gltf2.py b/moderngl_window/loaders/scene/gltf2.py index f227a53..36c0b0b 100644 --- a/moderngl_window/loaders/scene/gltf2.py +++ b/moderngl_window/loaders/scene/gltf2.py @@ -364,6 +364,12 @@ def _link_data(self) -> None: # Link accessors to mesh primitives for mesh in self.meshes: for primitive in mesh.primitives: + # Link the bufferview for draco compressed buffers + if primitive.extensions.get("KHR_draco_mesh_compression"): + ext = primitive.extensions["KHR_draco_mesh_compression"] + buffer_view_id = ext["bufferView"] + ext["bufferView"] = self.buffer_views[buffer_view_id] + if primitive.indices is not None: primitive.accessor = self.accessors[primitive.indices] for name, value in primitive.attributes.items(): @@ -395,12 +401,12 @@ def check_extensions(self, supported: list[str]) -> None: if extReq is not None: for ext in extReq: if ext not in supported: - raise ValueError(f"Extension {ext} not supported") + raise ValueError(f"Extension '{ext}' not supported") extUse = self.data.get("extensionsUsed") if extUse is not None: for ext in extUse: if ext not in supported: - raise ValueError("Extension {ext} not supported") + raise ValueError(f"Extension '{ext}' not supported") def buffers_exist(self) -> None: """Checks if the bin files referenced exist""" @@ -411,7 +417,7 @@ def buffers_exist(self) -> None: path = self.path.parent / buff.uri if not path.exists(): raise FileNotFoundError( - "Buffer {} referenced in {} not found".format(path, self.path) + f"Buffer {path} referenced in {self.path} not found" ) def images_exist(self) -> None: @@ -457,12 +463,14 @@ def load(self, materials: list[Material]) -> list[Mesh]: ctx = moderngl_window.ctx() meshes: list[Mesh] = [] + # FIXME: Split this up in methods # Read all primitives as separate meshes for now # According to the spec they can have different materials and vertex format for primitive in self.primitives: # Handle draco compressed meshes if primitive.extensions.get("KHR_draco_mesh_compression"): - data = primitive.accessor.read_raw() + buffer_view = primitive.extensions["KHR_draco_mesh_compression"]["bufferView"] + data = buffer_view.read_raw() import DracoPy mesh = DracoPy.decode(data) @@ -678,9 +686,10 @@ def __init__(self, accessor_id: int, data: dict[str, Any]): self.byteOffset = data.get("byteOffset", 0) self.componentType = COMPONENT_TYPE[data["componentType"]] self.count = data.get("count", 1) + self.type: str = data.get("type", "") + self.min = numpy.array(data.get("min") or [-0.5, -0.5, -0.5], dtype="f4") self.max = numpy.array(data.get("max") or [0.5, 0.5, 0.5], dtype="f4") - self.type = data.get("type", "") def read(self) -> tuple[int, ComponentType, npt.NDArray[Any]]: """ @@ -706,7 +715,7 @@ def read_raw(self) -> bytes: Read the raw bytes. Useful for draco compressed meshes or any data that is not a simple vertex buffer. """ - return self.bufferView.read_raw() + return self.bufferView.read_raw(byte_offset=self.byteOffset) def info(self) -> tuple[GLTFBuffer, GLTFBufferView, int, int, ComponentType, int, int]: """ @@ -726,6 +735,11 @@ def info(self) -> tuple[GLTFBuffer, GLTFBufferView, int, int, ComponentType, int self.count, ) + def __str__(self) -> str: + return "Accessor".format( + self.id, self.bufferViewId, self.byteOffset, self.componentType.name, self.count + ) + class GLTFBufferView: def __init__(self, view_id: int, data: dict[str, Any]): @@ -747,8 +761,11 @@ def read( vbo = numpy.frombuffer(data, count=count, dtype=dtype) return vbo - def read_raw(self) -> bytes: - return self.buffer.read(byte_length=self.byteLength, byte_offset=self.byteOffset) + def read_raw(self, byte_offset: int = 0) -> bytes: + return self.buffer.read( + byte_offset=self.byteOffset + byte_offset, + byte_length=self.byteLength, + ) def info(self, byte_offset: int = 0) -> tuple[GLTFBuffer, int, int]: """ @@ -758,6 +775,11 @@ def info(self, byte_offset: int = 0) -> tuple[GLTFBuffer, int, int]: """ return self.buffer, self.byteLength, byte_offset + self.byteOffset + def __str__(self) -> str: + return "BufferView".format( + self.id, self.bufferId, self.byteOffset, self.byteLength + ) + class GLTFBuffer: def __init__(self, buffer_id: int, data: dict[str, str], path: Path):