diff --git a/src/ansys/pyensight/core/utils/dsg_server.py b/src/ansys/pyensight/core/utils/dsg_server.py index 31eecf2b4cc..b7f5f48ec60 100644 --- a/src/ansys/pyensight/core/utils/dsg_server.py +++ b/src/ansys/pyensight/core/utils/dsg_server.py @@ -1044,6 +1044,21 @@ def _handle_part(self, part_cmd: Any) -> None: self._finish_part() self._part.reset(part_cmd) + def find_group_pb(self, group_id: int) -> Any: + """Return the group command protobuffer for a specific group id. + + Parameters + ---------- + group_id: int + The group DSG protocol entity id. + + Returns + ------- + any + The group command protobuffer or None. + """ + return self._groups.get(group_id, None) + def _handle_group(self, group: Any) -> None: """Handle a DSG UPDATE_GROUP command diff --git a/src/ansys/pyensight/core/utils/omniverse_dsg_server.py b/src/ansys/pyensight/core/utils/omniverse_dsg_server.py index d3625e497cb..0085826e426 100644 --- a/src/ansys/pyensight/core/utils/omniverse_dsg_server.py +++ b/src/ansys/pyensight/core/utils/omniverse_dsg_server.py @@ -357,6 +357,7 @@ def create_dsg_lines( parent_prim, verts, tcoords, + width, matrix=[1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], diffuse=[1.0, 1.0, 1.0, 1.0], variable=None, @@ -364,20 +365,6 @@ def create_dsg_lines( first_timestep=False, mat_info={}, ): - # TODO: GLB extension maps to DSG PART attribute map - width = self.line_width - wireframe = width == 0.0 - if width < 0.0: - tmp = verts.reshape(-1, 3) - mins = numpy.min(tmp, axis=0) - maxs = numpy.max(tmp, axis=0) - dx = maxs[0] - mins[0] - dy = maxs[1] - mins[1] - dz = maxs[2] - mins[2] - diagonal = math.sqrt(dx * dx + dy * dy + dz * dz) - width = diagonal * math.fabs(width) - self.line_width = width - # include the line width in the hash part_hash.update(str(self.line_width).encode("utf-8")) @@ -410,6 +397,7 @@ def create_dsg_lines( endCaps.Set(2) # Rounded = 2 prim = lines.GetPrim() + wireframe = width == 0.0 prim.CreateAttribute( "omni:scene:visualization:drawWireframe", Sdf.ValueTypeNames.Bool ).Set(wireframe) @@ -880,9 +868,30 @@ def finalize_part(self, part: Part) -> None: part.cmd.line_color[2] * part.cmd.diffuse, part.cmd.line_color[3], ] - # TODO: texture coordinates on lines are current invalid in OV + # TODO: texture coordinates on lines are currently invalid in Omniverse var_cmd = None tcoords = None + # line info can come from self or our parent group + width = self._omni.line_width + # Allow the group to override + group = self.session.find_group_pb(part.cmd.parent_id) + if group: + try: + width = float(group.attributes.get("ANSYS_linewidth", str(width))) + except ValueError: + pass + if width < 0.0: + tmp = verts.reshape(-1, 3) + mins = numpy.min(tmp, axis=0) + maxs = numpy.max(tmp, axis=0) + dx = maxs[0] - mins[0] + dy = maxs[1] - mins[1] + dz = maxs[2] - mins[2] + diagonal = math.sqrt(dx * dx + dy * dy + dz * dz) + width = diagonal * math.fabs(width) + if self._omni.line_width < 0.0: + self._omni.line_width = width + # Generate the lines _ = self._omni.create_dsg_lines( name, @@ -891,6 +900,7 @@ def finalize_part(self, part: Part) -> None: parent_prim, verts, tcoords, + width, matrix=matrix, diffuse=line_color, variable=var_cmd, diff --git a/src/ansys/pyensight/core/utils/omniverse_glb_server.py b/src/ansys/pyensight/core/utils/omniverse_glb_server.py index f98c488a48b..2a75482696d 100644 --- a/src/ansys/pyensight/core/utils/omniverse_glb_server.py +++ b/src/ansys/pyensight/core/utils/omniverse_glb_server.py @@ -153,6 +153,7 @@ def _parse_mesh(self, meshid: int, parentid: int, parentname: str) -> None: cmd, part_pb = self._create_pb("PART", parent_id=parentid, name=part_name) if mode == pygltflib.POINTS: part_pb.render = dynamic_scene_graph_pb2.UpdatePart.RenderingMode.NODES + # Size of the spheres part_pb.node_size_default = line_width else: part_pb.render = dynamic_scene_graph_pb2.UpdatePart.RenderingMode.CONNECTIVITY @@ -401,10 +402,39 @@ def _walk_node(self, nodeid: int, parentid: int) -> None: # GLB node -> DSG Group cmd, group_pb = self._create_pb("GROUP", parent_id=parentid, name=name) group_pb.matrix4x4.extend(matrix) - self._handle_update_command(cmd) - if node.mesh is not None: + # This is a little ugly, but spheres have a size that is part of the PART + # protobuffer. So, if the current mesh has the "ANSYS_linewidth" extension, + # we need to temporally change the line width. However, if this is a lines + # object, then we need to set the ANSYS_linewidth attribute. Unfortunately, + # this is only available on the GROUP protobuffer, thus we will try to set + # both here. + # Note: in the EnSight push, ANSYS_linewidth will only ever be set on the + # top level node. In the GLB case, we will scope it to the group. Thus, + # every "mesh" protobuffer sequence will have an explicit line width in + # the group above the part. + + # save/restore the current line_width + orig_width = self._callback_handler._omni.line_width + mesh = self._gltf.meshes[node.mesh] + try: + # check for line_width on the mesh object + width = float(mesh.extensions["ANSYS_linewidth"]["linewidth"]) + # make sure spheres work + self._callback_handler._omni.line_width = width + except (KeyError, ValueError): + pass + # make sure lines work (via the group attributes map) + group_pb.attributes["ANSYS_linewidth"] = str(self._callback_handler._omni.line_width) + # send the group protobuffer + self._handle_update_command(cmd) + # Export the mesh self._parse_mesh(node.mesh, group_pb.id, name) + # restore the old line_width + self._callback_handler._omni.line_width = orig_width + else: + # send the group protobuffer + self._handle_update_command(cmd) # Handle node.rotation, node.translation, node.scale, node.matrix for child_id in node.children: @@ -580,7 +610,7 @@ def upload_file(self, glb_filename: str, timeline: List[float] = [0.0, 0.0]) -> view_pb.fieldofview = camera.perspective.yfov view_pb.aspectratio = camera.aspectratio.aspectRatio self._handle_update_command(cmd) - # walk the scene nodes RJF + # walk the scene nodes scene = self._gltf.scenes[scene_idx] try: if self._callback_handler._omni.line_width == 0.0: