Source code for openalea.plantconvert.gltf.reader

# from math import isnan
# import pygltflib as gltf
# import openalea.mtg.mtg as mtg
# import openalea.plantgl.all as pgl
# from . import utils
# from .maths import get_matrix4

from math import isnan

import numpy as np
import pygltflib as gltf

import openalea.mtg.mtg as mtg
import openalea.plantgl.all as pgl

from ..geometry import taper_along_x, transformed_from_mat
from . import buffer_tools


[docs] class mtg_builder(object): def __init__(self, filename): self.gltf = gltf.GLTF2.load(filename) self.g = mtg.MTG()
[docs] def build(self): self._read_meshes() self._read_topology() self.g.add_property("geometry") for s in self.g.scales_iter(): self._read_geometry(s) return self.g
def _read_meshes(self): self.data = [] self.g.add_property("ref_meshes") root = self.g.root self.g.node(root).ref_meshes = [] for mesh in self.gltf.meshes: if len(mesh.primitives) > 1 or len(mesh.weights) > 0: raise NotImplementedError( "Multiple primitives meshes are not supported yet" ) primitive = mesh.primitives[0] pos_ind = primitive.attributes.POSITION normal_ind = primitive.attributes.NORMAL tex_ind = primitive.attributes.TEXCOORD_0 indices_ind = primitive.indices # pos, normal, tex, indices are supposed to use the same buffer buffer = buffer_tools.get_buffer(self.gltf.accessors[pos_ind], self.gltf) data = self.gltf.get_data_from_buffer_uri(buffer.uri) # self.data.append(data) # read positions: accessor = self.gltf.accessors[pos_ind] buffer_view = self.gltf.bufferViews[accessor.bufferView] pos = buffer_tools.get_data(data, accessor, buffer_view) # read normals: accessor = self.gltf.accessors[normal_ind] buffer_view = self.gltf.bufferViews[accessor.bufferView] normal = buffer_tools.get_data(data, accessor, buffer_view) # read texture: try: accessor = self.gltf.accessors[tex_ind] except TypeError: tex = [] else: buffer_view = self.gltf.bufferViews[accessor.bufferView] tex = buffer_tools.get_data(data, accessor, buffer_view) # read indices: accessor = self.gltf.accessors[indices_ind] buffer_view = self.gltf.bufferViews[accessor.bufferView] indices = buffer_tools.get_data(data, accessor, buffer_view) triangles = pgl.TriangleSet() triangles.pointList = pos triangles.normalList = normal if len(tex) > 0: triangles.texCoordList = tex triangles.indexList = indices self.g.node(root).ref_meshes.append(triangles) self.taper_x = taper_along_x(self.g.node(root).ref_meshes) def _read_attributes(self, vid): node = self.gltf.nodes[vid] extras = node.extras for k, value in extras.items(): if k not in ["scale", "edge_type", "top", "base", "component_roots"]: setattr(self.g.node(vid), k, value) def _read_topology(self): self.max_scale = len(self.gltf.scenes) - 1 for scale, scene in enumerate(self.gltf.scenes): # each scene contains the root node of a scale root = scene.nodes[0] parents = [root] while len(parents) > 0: parent = parents.pop(0) # update here the parent's attribute self._read_attributes(parent) self.g.node(parent).label = self.gltf.nodes[parent].name components = self.gltf.nodes[parent].extras.get("component_roots", []) for comp in components: self.g.add_component(parent, comp) children = self.gltf.nodes[parent].children for child in children: edge_type = self.gltf.nodes[child].extras["edge_type"] self.g.add_child(parent, child, edge_type=edge_type) parents.extend(children) def _read_geometry( self, scale, tranform=None, vid=None ): # read the geometry at scale = scale # transform is the global transformation matrix of the parent node if tranform is None: tranform = np.identity(4) if vid is None: vid = self.g.roots(scale) for v in vid: mesh_id = getattr(self.gltf.nodes[v], "mesh", None) if mesh_id is not None: ref_geo = self.g[0]["ref_meshes"][mesh_id] top = self.gltf.nodes[v].extras.get("top", float("nan")) base = self.gltf.nodes[v].extras.get("base", float("nan")) if not isnan(top) and not isnan(base): tapered = self.taper_x(top, base, ref_geo) else: tapered = ref_geo # t = self.gltf.nodes[v].translation # q = self.gltf.nodes[v].rotation # s = np.array(self.gltf.nodes[v].scale) # mat = get_matrix4(t, q) mat = np.array(self.gltf.nodes[v].matrix).reshape((4, 4), order="F") global_mat = tranform @ mat self.g.node(v).geometry = transformed_from_mat( global_mat, tapered, is_mesh=False ) self.g.node(v).shapeIndex = mesh_id self._read_geometry(scale, global_mat, self.g.children(v)) self.g.node(0).shapes = [ {"meshIndex": i, "materialIndex": 0} for i in range(len(self.g[0]["ref_meshes"])) ] self.g.node(0).materials = dict( zip( range(len(self.g[0]["ref_meshes"])), [pgl.Material.DEFAULT_MATERIAL] * len(self.g[0]["ref_meshes"]), ) )
# def get_transformation(self, vid): # t = self.gltf.nodes[vid].translation # q = self.gltf.nodes[vid].rotation # s = self.gltf.nodes[vid].scale # mat = get_matrix4(t,q,s) # if self.g.parent(vid) is not None: # return self.get_transformation(self.g.parent(vid))@mat # else: # return mat