diff --git a/genesis/engine/entities/base_entity.py b/genesis/engine/entities/base_entity.py index 727caa3bf9..4d0e54adcf 100644 --- a/genesis/engine/entities/base_entity.py +++ b/genesis/engine/entities/base_entity.py @@ -19,6 +19,96 @@ def __init__( material, surface, ): + if isinstance(material, gs.materials.Rigid): + # small sdf res is sufficient for primitives regardless of size + if isinstance(morph, gs.morphs.Primitive): + material._sdf_max_res = 32 + + # some morph should not smooth surface normal + if isinstance(morph, (gs.morphs.Box, gs.morphs.Cylinder, gs.morphs.Terrain)): + surface.smooth = False + + if isinstance(morph, (gs.morphs.URDF, gs.morphs.MJCF, gs.morphs.Terrain)): + if not isinstance(material, (gs.materials.Rigid, gs.materials.Avatar, gs.materials.Hybrid)): + gs.raise_exception(f"Unsupported material for morph: {material} and {morph}.") + + if surface.double_sided is None: + surface.double_sided = isinstance(material, gs.materials.PBD.Cloth) + + # validate and populate default surface.vis_mode considering morph type + if isinstance(material, (gs.materials.Rigid, gs.materials.Avatar, gs.materials.Tool)): + if surface.vis_mode is None: + surface.vis_mode = "visual" + + if surface.vis_mode not in ("visual", "collision", "sdf"): + gs.raise_exception( + f"Invalid `surface.vis_mode` for material {material}: '{surface.vis_mode}'. Only supporting " + "'visual', 'collision' and 'sdf'." + ) + elif isinstance( + material, + ( + gs.materials.PBD.Liquid, + gs.materials.PBD.Particle, + gs.materials.MPM.Liquid, + gs.materials.MPM.Sand, + gs.materials.MPM.Snow, + gs.materials.SPH.Liquid, + ), + ): + if surface.vis_mode is None: + surface.vis_mode = "particle" + + if surface.vis_mode not in ("particle", "recon"): + gs.raise_exception( + f"Invalid `surface.vis_mode` for material {material}: '{surface.vis_mode}'. Only supporting " + "'particle' and 'recon'." + ) + elif isinstance(material, (gs.materials.SF.Smoke)): + if surface.vis_mode is None: + surface.vis_mode = "particle" + + if surface.vis_mode not in ("particle",): + gs.raise_exception( + f"Invalid `surface.vis_mode` for material {material}: '{surface.vis_mode}'. Only supporting " + "'particle'." + ) + elif isinstance(material, (gs.materials.PBD.Base, gs.materials.MPM.Base, gs.materials.SPH.Base)): + if surface.vis_mode is None: + surface.vis_mode = "visual" + + if surface.vis_mode not in ("visual", "particle", "recon"): + gs.raise_exception( + f"Invalid `surface.vis_mode` for material {material}: '{surface.vis_mode}'. Only supporting " + "'visual', 'particle' and 'recon'." + ) + elif isinstance(material, (gs.materials.FEM.Base)): + if surface.vis_mode is None: + surface.vis_mode = "visual" + + if surface.vis_mode not in ("visual",): + gs.raise_exception( + f"Invalid `surface.vis_mode` for material {material}: '{surface.vis_mode}'. Only supporting " + "'visual'." + ) + elif isinstance(material, (gs.materials.Hybrid)): # determine the visual of the outer soft part + if surface.vis_mode is None: + surface.vis_mode = "particle" + + if surface.vis_mode not in ["particle", "visual"]: + gs.raise_exception( + f"Invalid `surface.vis_mode` for material {material}: '{surface.vis_mode}'. Only supporting " + "'particle' and 'visual'." + ) + else: + gs.raise_exception(f"Material not supported.: {material}") + + # Set material-dependent default options + if isinstance(morph, gs.morphs.FileMorph): + # Rigid entities will convexify geom by default + if morph.convexify is None: + morph.convexify = isinstance(material, (gs.materials.Rigid, gs.materials.Avatar)) + self._uid = gs.UID() self._idx = idx self._scene = scene diff --git a/genesis/engine/entities/rigid_entity/rigid_entity.py b/genesis/engine/entities/rigid_entity/rigid_entity.py index ae94906b00..c9e5dc00d5 100644 --- a/genesis/engine/entities/rigid_entity/rigid_entity.py +++ b/genesis/engine/entities/rigid_entity/rigid_entity.py @@ -1,6 +1,7 @@ from copy import copy from itertools import chain from typing import Literal +from typing import TYPE_CHECKING import numpy as np import taichi as ti @@ -25,6 +26,10 @@ from .rigid_joint import RigidJoint from .rigid_link import RigidLink +if TYPE_CHECKING: + from genesis.engine.solvers.base_solver import Solver + from genesis.engine.scene import Scene + @ti.data_oriented class RigidEntity(Entity): @@ -57,6 +62,9 @@ def __init__( equality_start=0, visualize_contact=False, ): + if material is None: + material = gs.materials.Rigid() + super().__init__(idx, scene, morph, solver, material, surface) self._idx_in_solver = idx_in_solver @@ -83,36 +91,29 @@ def __init__( self._is_built = False - self._load_model() + self._load_model(morph, material, self.surface) - def _load_model(self): + def _load_model(self, morph, material, surface): self._links = gs.List() self._joints = gs.List() self._equalities = gs.List() - if isinstance(self._morph, gs.morphs.Mesh): - self._load_mesh(self._morph, self._surface) - elif isinstance(self._morph, (gs.morphs.MJCF, gs.morphs.URDF, gs.morphs.Drone)): - self._load_scene(self._morph, self._surface) - elif isinstance(self._morph, gs.morphs.Primitive): - self._load_primitive(self._morph, self._surface) - elif isinstance(self._morph, gs.morphs.Terrain): - self._load_terrain(self._morph, self._surface) + if isinstance(morph, gs.morphs.Mesh): + self._load_mesh(morph, material, surface) + elif isinstance(morph, (gs.morphs.MJCF, gs.morphs.URDF, gs.morphs.Drone)): + self._load_scene(morph, material, surface) + elif isinstance(morph, gs.morphs.Primitive): + self._load_primitive(morph, material, surface) + elif isinstance(morph, gs.morphs.Terrain): + self._load_terrain(morph, material, surface) else: - gs.raise_exception(f"Unsupported morph: {self._morph}.") + gs.raise_exception(f"Unsupported morph: {morph}.") - self._requires_jac_and_IK = self._morph.requires_jac_and_IK + self._requires_jac_and_IK = morph.requires_jac_and_IK self._update_child_idxs() - def _update_child_idxs(self): - for link in self._links: - if link.parent_idx != -1: - parent_link = self._links[link.parent_idx_local] - if link.idx not in parent_link.child_idxs: - parent_link.child_idxs.append(link.idx) - - def _load_primitive(self, morph, surface): + def _load_primitive(self, morph, material, surface): if morph.fixed: joint_type = gs.JOINT_TYPE.FIXED n_qs = 0 @@ -180,7 +181,7 @@ def _load_primitive(self, morph, surface): link, (joint,) = self._add_by_info( l_info=dict( is_robot=False, - name=f"{link_name_prefix}_baselink", + name=f"{link_name_prefix}_base", pos=np.array(morph.pos), quat=np.array(morph.quat), inertial_pos=gu.zero_pos(), @@ -189,7 +190,7 @@ def _load_primitive(self, morph, surface): ), j_infos=[ dict( - name=f"{link_name_prefix}_baselink_joint", + name=f"{link_name_prefix}_root_joint", n_qs=n_qs, n_dofs=n_dofs, type=joint_type, @@ -198,10 +199,10 @@ def _load_primitive(self, morph, surface): ], g_infos=g_infos, morph=morph, - surface=surface, + material=material, ) - def _load_mesh(self, morph, surface): + def _load_mesh(self, morph, material, surface): if morph.fixed: joint_type = gs.JOINT_TYPE.FIXED n_qs = 0 @@ -247,12 +248,13 @@ def _load_mesh(self, morph, surface): ) ) - link_name = morph.file.rsplit("/", 1)[-1].replace(".", "_") + *_, link_name = morph.file.rsplit("/", 1) + link_name.replace(".", "_") link, (joint,) = self._add_by_info( l_info=dict( is_robot=False, - name=f"{link_name}_baselink", + name=f"{link_name}_base", pos=np.array(morph.pos), quat=np.array(morph.quat), inertial_pos=gu.zero_pos(), @@ -261,7 +263,7 @@ def _load_mesh(self, morph, surface): ), j_infos=[ dict( - name=f"{link_name}_baselink_joint", + name=f"{link_name}_root_joint", n_qs=n_qs, n_dofs=n_dofs, type=joint_type, @@ -270,10 +272,10 @@ def _load_mesh(self, morph, surface): ], g_infos=g_infos, morph=morph, - surface=surface, + material=material, ) - def _load_terrain(self, morph, surface): + def _load_terrain(self, morph, material, surface): vmesh, mesh, self.terrain_hf = tu.parse_terrain(morph, surface) self.terrain_scale = np.array((morph.horizontal_scale, morph.vertical_scale), dtype=gs.np_float) @@ -300,7 +302,7 @@ def _load_terrain(self, morph, surface): link, (joint,) = self._add_by_info( l_info=dict( is_robot=False, - name="baselink", + name="base", pos=np.array(morph.pos), quat=np.array(morph.quat), inertial_pos=None, @@ -312,7 +314,7 @@ def _load_terrain(self, morph, surface): ), j_infos=[ dict( - name="joint_baselink", + name="root_joint", n_qs=0, n_dofs=0, type=gs.JOINT_TYPE.FIXED, @@ -320,10 +322,10 @@ def _load_terrain(self, morph, surface): ], g_infos=g_infos, morph=morph, - surface=surface, + material=material, ) - def _load_scene(self, morph, surface): + def _load_scene(self, morph, material, surface): # Mujoco's unified MJCF+URDF parser is not good enough for now to be used for loading both MJCF and URDF files. # First, it would happen when loading visual meshes having supported format (i.e. Collada files '.dae'). # Second, it does not take into account URDF 'mimic' joint constraints. However, it does a better job at @@ -517,7 +519,7 @@ def _load_scene(self, morph, surface): # Exclude joints with 0 dofs to align with Mujoco link_j_infos = [j_info for j_info in link_j_infos if j_info["n_dofs"] > 0] - self._add_by_info(l_info, link_j_infos, link_g_infos, morph, surface) + self._add_by_info(l_info, link_j_infos, link_g_infos, morph, material) # Add equality constraints sequentially for eq_info in eqs_info: @@ -529,6 +531,13 @@ def _load_scene(self, morph, surface): sol_params=eq_info["sol_params"], ) + def _update_child_idxs(self): + for link in self._links: + if link.parent_idx != -1: + parent_link = self._links[link.parent_idx_local] + if link.idx not in parent_link.child_idxs: + parent_link.child_idxs.append(link.idx) + def _build(self): for link in self._links: link._build() @@ -600,7 +609,7 @@ def _init_jac_and_IK(self): dtype=gs.ti_float, shape=self._solver._batch_shape((self.n_dofs, self._IK_error_dim)) ) - def _add_by_info(self, l_info, j_infos, g_infos, morph, surface): + def _add_by_info(self, l_info, j_infos, g_infos, morph, material): if len(j_infos) > 1 and any(j_info["type"] in (gs.JOINT_TYPE.FREE, gs.JOINT_TYPE.FIXED) for j_info in j_infos): raise ValueError( "Compounding joints of types 'FREE' or 'FIXED' with any other joint on the same body not supported" @@ -760,9 +769,10 @@ def _add_by_info(self, l_info, j_infos, g_infos, morph, surface): # Add collision geometries for g_info in cg_infos: - friction = g_info.get("friction", self.material.friction) - if friction is None: - friction = gu.default_friction() + if material is not None: + friction = material.friction + else: + friction = g_info.get("friction", self.material.friction) link._add_geom( mesh=g_info["mesh"], init_pos=g_info.get("pos", gu.zero_pos()), diff --git a/genesis/engine/entities/tool_entity/tool_entity.py b/genesis/engine/entities/tool_entity/tool_entity.py index 0cc57b0748..a5aec65074 100644 --- a/genesis/engine/entities/tool_entity/tool_entity.py +++ b/genesis/engine/entities/tool_entity/tool_entity.py @@ -18,15 +18,7 @@ @ti.data_oriented class ToolEntity(Entity): # Mesh-based tool body entity - def __init__( - self, - scene, - idx, - solver, - material, - morph, - surface, - ): + def __init__(self, scene, idx, solver, material, morph, surface): super().__init__(idx, scene, morph, solver, material, surface) self._init_pos = np.array(morph.pos, dtype=gs.np_float) diff --git a/genesis/engine/materials/rigid.py b/genesis/engine/materials/rigid.py index c0310d4786..417294ca25 100644 --- a/genesis/engine/materials/rigid.py +++ b/genesis/engine/materials/rigid.py @@ -20,7 +20,7 @@ class Rigid(Material): rho : float, optional The density of the material used to compute mass. Default is 200.0. friction : float, optional - Friction coefficient within the rigid solver. If None, a default of 1.0 may be used or parsed from file. + Friction coefficient within the rigid solver. Default is 1.0. needs_coup : bool, optional Whether the material participates in coupling with other solvers. Default is True. coup_friction : float, optional @@ -42,7 +42,7 @@ class Rigid(Material): def __init__( self, rho=200.0, - friction=None, + friction=1.0, needs_coup=True, coup_friction=0.1, coup_softness=0.002, @@ -54,9 +54,8 @@ def __init__( ): super().__init__() - if friction is not None: - if friction < 1e-2 or friction > 5.0: - gs.raise_exception("`friction` must be in the range [1e-2, 5.0] for simulation stability.") + if friction < 1e-2 or friction > 5.0: + gs.raise_exception("`friction` must be in the range [1e-2, 5.0] for simulation stability.") if coup_friction < 0: gs.raise_exception("`coup_friction` must be non-negative.") @@ -76,7 +75,7 @@ def __init__( if sdf_min_res > sdf_max_res: gs.raise_exception("`sdf_min_res` must be smaller than or equal to `sdf_max_res`.") - self._friction = float(friction) if friction is not None else None + self._friction = float(friction) self._needs_coup = bool(needs_coup) self._coup_friction = float(coup_friction) self._coup_softness = float(coup_softness) diff --git a/genesis/engine/scene.py b/genesis/engine/scene.py index 4c1798835f..2d4af21e7d 100644 --- a/genesis/engine/scene.py +++ b/genesis/engine/scene.py @@ -281,121 +281,26 @@ def add_entity( surface : gs.surfaces.Surface | None, optional The surface of the entity. If None, use ``gs.surfaces.Default()``. visualize_contact : bool - Whether to visualize contact forces applied to this entity as arrows in the viewer and rendered images. Note that this will not be displayed in images rendered by camera using the `RayTracer` renderer. + Whether to visualize contact forces applied to this entity as arrows in the viewer and rendered images. + Note that this will not be displayed in images rendered by camera using the `RayTracer` renderer. vis_mode : str | None, optional - The visualization mode of the entity. This is a handy shortcut for setting `surface.vis_mode` without explicitly creating a surface object. + The visualization mode of the entity. This is a handy shortcut for setting `surface.vis_mode` without + explicitly creating a surface object. Returns ------- entity : genesis.Entity The created entity. """ - if material is None: - material = gs.materials.Rigid() - if surface is None: surface = ( gs.surfaces.Default() ) # assign a local surface, otherwise modification will apply on global default surface - if isinstance(material, gs.materials.Rigid): - # small sdf res is sufficient for primitives regardless of size - if isinstance(morph, gs.morphs.Primitive): - material._sdf_max_res = 32 - - # some morph should not smooth surface normal - if isinstance(morph, (gs.morphs.Box, gs.morphs.Cylinder, gs.morphs.Terrain)): - surface.smooth = False - - if isinstance(morph, (gs.morphs.URDF, gs.morphs.MJCF, gs.morphs.Terrain)): - if not isinstance(material, (gs.materials.Rigid, gs.materials.Avatar, gs.materials.Hybrid)): - gs.raise_exception(f"Unsupported material for morph: {material} and {morph}.") - - if surface.double_sided is None: - if isinstance(material, gs.materials.PBD.Cloth): - surface.double_sided = True - else: - surface.double_sided = False - if vis_mode is not None: surface.vis_mode = vis_mode - # validate and populate default surface.vis_mode considering morph type - if isinstance(material, (gs.materials.Rigid, gs.materials.Avatar, gs.materials.Tool)): - if surface.vis_mode is None: - surface.vis_mode = "visual" - - if surface.vis_mode not in ["visual", "collision", "sdf"]: - gs.raise_exception( - f"Unsupported `surface.vis_mode` for material {material}: '{surface.vis_mode}'. Expected one of: ['visual', 'collision', 'sdf']." - ) - - elif isinstance( - material, - ( - gs.materials.PBD.Liquid, - gs.materials.PBD.Particle, - gs.materials.MPM.Liquid, - gs.materials.MPM.Sand, - gs.materials.MPM.Snow, - gs.materials.SPH.Liquid, - ), - ): - if surface.vis_mode is None: - surface.vis_mode = "particle" - - if surface.vis_mode not in ["particle", "recon"]: - gs.raise_exception( - f"Unsupported `surface.vis_mode` for material {material}: '{surface.vis_mode}'. Expected one of: ['particle', 'recon']." - ) - - elif isinstance(material, (gs.materials.SF.Smoke)): - if surface.vis_mode is None: - surface.vis_mode = "particle" - - if surface.vis_mode not in ["particle"]: - gs.raise_exception( - f"Unsupported `surface.vis_mode` for material {material}: '{surface.vis_mode}'. Expected one of: ['particle', 'recon']." - ) - - elif isinstance(material, (gs.materials.PBD.Base, gs.materials.MPM.Base, gs.materials.SPH.Base)): - if surface.vis_mode is None: - surface.vis_mode = "visual" - - if surface.vis_mode not in ["visual", "particle", "recon"]: - gs.raise_exception( - f"Unsupported `surface.vis_mode` for material {material}: '{surface.vis_mode}'. Expected one of: ['visual', 'particle', 'recon']." - ) - - elif isinstance(material, (gs.materials.FEM.Base)): - if surface.vis_mode is None: - surface.vis_mode = "visual" - - if surface.vis_mode not in ["visual"]: - gs.raise_exception( - f"Unsupported `surface.vis_mode` for material {material}: '{surface.vis_mode}'. Expected one of: ['visual']." - ) - - elif isinstance(material, (gs.materials.Hybrid)): # determine the visual of the outer soft part - if surface.vis_mode is None: - surface.vis_mode = "particle" - - if surface.vis_mode not in ["particle", "visual"]: - gs.raise_exception( - f"Unsupported `surface.vis_mode` for material {material}: '{surface.vis_mode}'. Expected one of: ['particle', 'visual']." - ) - - else: - gs.raise_exception() - - # Set material-dependent default options - if isinstance(morph, gs.morphs.FileMorph): - # Rigid entities will convexify geom by default - if morph.convexify is None: - morph.convexify = isinstance(material, (gs.materials.Rigid, gs.materials.Avatar)) - - entity = self._sim._add_entity(morph, material, surface, visualize_contact) - return entity + return self._sim._add_entity(morph, material, surface, visualize_contact) @gs.assert_unbuilt def link_entities( diff --git a/genesis/engine/simulator.py b/genesis/engine/simulator.py index 5bc70a6541..b8907c2d3d 100644 --- a/genesis/engine/simulator.py +++ b/genesis/engine/simulator.py @@ -1,4 +1,5 @@ from typing import TYPE_CHECKING + import numpy as np import taichi as ti @@ -152,34 +153,26 @@ def __init__( self._entities: list[Entity] = gs.List() def _add_entity(self, morph: Morph, material, surface, visualize_contact=False): - if isinstance(material, gs.materials.Tool): - entity = self.tool_solver.add_entity(self.n_entities, material, morph, surface) - + if material is None or isinstance(material, gs.materials.Rigid): + entity = self.rigid_solver.add_entity(self.n_entities, material, morph, surface, visualize_contact) elif isinstance(material, gs.materials.Avatar): entity = self.avatar_solver.add_entity(self.n_entities, material, morph, surface, visualize_contact) - - elif isinstance(material, gs.materials.Rigid): - entity = self.rigid_solver.add_entity(self.n_entities, material, morph, surface, visualize_contact) - + elif isinstance(material, gs.materials.Tool): + entity = self.tool_solver.add_entity(self.n_entities, material, morph, surface) elif isinstance(material, gs.materials.MPM.Base): entity = self.mpm_solver.add_entity(self.n_entities, material, morph, surface) - elif isinstance(material, gs.materials.SPH.Base): entity = self.sph_solver.add_entity(self.n_entities, material, morph, surface) - elif isinstance(material, gs.materials.PBD.Base): entity = self.pbd_solver.add_entity(self.n_entities, material, morph, surface) - elif isinstance(material, gs.materials.FEM.Base): entity = self.fem_solver.add_entity(self.n_entities, material, morph, surface) - elif isinstance(material, gs.materials.Hybrid): entity = HybridEntity( self.n_entities, self.scene, material, morph, surface ) # adding to solver is handled in the hybrid entity - else: - gs.raise_exception(f"Material not supported.: {material}") + gs.raise_exception(f"Material not supported: {material}") self._entities.append(entity) return entity diff --git a/genesis/engine/solvers/avatar_solver.py b/genesis/engine/solvers/avatar_solver.py index b926805417..23f1249b1e 100644 --- a/genesis/engine/solvers/avatar_solver.py +++ b/genesis/engine/solvers/avatar_solver.py @@ -29,7 +29,7 @@ def __init__(self, scene, sim, options): self._options = options def _init_mass_mat(self): - self.entity_max_dofs = max([entity.n_dofs for entity in self._entities]) + self.entity_max_dofs = max(entity.n_dofs for entity in self._entities) def _init_invweight(self): pass diff --git a/genesis/engine/solvers/base_solver.py b/genesis/engine/solvers/base_solver.py index dca57e73f8..7572956b53 100644 --- a/genesis/engine/solvers/base_solver.py +++ b/genesis/engine/solvers/base_solver.py @@ -1,4 +1,5 @@ from typing import TYPE_CHECKING + import numpy as np import taichi as ti import torch diff --git a/genesis/engine/solvers/mpm_solver.py b/genesis/engine/solvers/mpm_solver.py index 8e20472733..3018404465 100644 --- a/genesis/engine/solvers/mpm_solver.py +++ b/genesis/engine/solvers/mpm_solver.py @@ -1,4 +1,5 @@ from typing import TYPE_CHECKING + import numpy as np import taichi as ti import torch diff --git a/genesis/engine/solvers/pbd_solver.py b/genesis/engine/solvers/pbd_solver.py index 681f99225d..c258d22949 100644 --- a/genesis/engine/solvers/pbd_solver.py +++ b/genesis/engine/solvers/pbd_solver.py @@ -251,7 +251,6 @@ def add_entity(self, idx, material, morph, surface): vvert_start=self.n_vverts, vface_start=self.n_vfaces, ) - elif isinstance(material, gs.materials.PBD.Elastic): entity = PBD3DEntity( scene=self.scene, @@ -267,7 +266,6 @@ def add_entity(self, idx, material, morph, surface): vvert_start=self.n_vverts, vface_start=self.n_vfaces, ) - elif isinstance(material, gs.materials.PBD.Liquid): entity = PBDParticleEntity( scene=self.scene, @@ -279,7 +277,6 @@ def add_entity(self, idx, material, morph, surface): idx=idx, particle_start=self.n_particles, ) - elif isinstance(material, gs.materials.PBD.Particle): entity = PBDFreeParticleEntity( scene=self.scene, @@ -291,9 +288,8 @@ def add_entity(self, idx, material, morph, surface): idx=idx, particle_start=self.n_particles, ) - else: - raise NotImplementedError() + gs.raise_exception(f"Material not supported: {material}") self._entities.append(entity) diff --git a/genesis/engine/solvers/rigid/constraint_solver_decomp.py b/genesis/engine/solvers/rigid/constraint_solver_decomp.py index 95c4430377..8f8ca3e126 100644 --- a/genesis/engine/solvers/rigid/constraint_solver_decomp.py +++ b/genesis/engine/solvers/rigid/constraint_solver_decomp.py @@ -1,4 +1,5 @@ from typing import TYPE_CHECKING + import numpy as np import taichi as ti import numpy.typing as npt diff --git a/genesis/engine/solvers/rigid/rigid_solver_decomp.py b/genesis/engine/solvers/rigid/rigid_solver_decomp.py index 90e2f0ba38..8360a352ae 100644 --- a/genesis/engine/solvers/rigid/rigid_solver_decomp.py +++ b/genesis/engine/solvers/rigid/rigid_solver_decomp.py @@ -1,4 +1,4 @@ -from typing import Literal, TYPE_CHECKING +from typing import Literal, Type, TYPE_CHECKING from dataclasses import dataclass import numpy as np @@ -7,21 +7,21 @@ import taichi as ti import genesis as gs +import genesis.utils.array_class as array_class +import genesis.utils.geom as gu from genesis.engine.entities.base_entity import Entity +from genesis.engine.entities import AvatarEntity, DroneEntity, RigidEntity +from genesis.engine.states.solvers import RigidSolverState from genesis.options.solvers import RigidOptions -import genesis.utils.geom as gu from genesis.utils import linalg as lu from genesis.utils.misc import ti_field_to_torch, DeprecationError, ALLOCATE_TENSOR_WARNING -from genesis.engine.entities import AvatarEntity, DroneEntity, RigidEntity -from genesis.engine.states.solvers import RigidSolverState from genesis.styles import colors, formats -import genesis.utils.array_class as array_class +from ....utils.sdf_decomp import SDF from ..base_solver import Solver from .collider_decomp import Collider from .constraint_solver_decomp import ConstraintSolver from .constraint_solver_decomp_island import ConstraintSolverIsland -from ....utils.sdf_decomp import SDF if TYPE_CHECKING: from genesis.engine.scene import Scene @@ -145,20 +145,13 @@ def __init__(self, scene: "Scene", sim: "Simulator", options: RigidOptions) -> N self._cur_step = -1 def add_entity(self, idx, material, morph, surface, visualize_contact) -> Entity: + EntityClass: Type[RigidEntity] if isinstance(material, gs.materials.Avatar): EntityClass = AvatarEntity if visualize_contact: gs.raise_exception("AvatarEntity does not support 'visualize_contact=True'.") else: - if isinstance(morph, gs.morphs.Drone): - EntityClass = DroneEntity - else: - EntityClass = RigidEntity - - if morph.is_free: - verts_state_start = self.n_free_verts - else: - verts_state_start = self.n_fixed_verts + EntityClass = DroneEntity if isinstance(morph, gs.morphs.Drone) else RigidEntity morph._enable_mujoco_compatibility = self._enable_mujoco_compatibility @@ -177,7 +170,7 @@ def add_entity(self, idx, material, morph, surface, visualize_contact) -> Entity geom_start=self.n_geoms, cell_start=self.n_cells, vert_start=self.n_verts, - verts_state_start=verts_state_start, + verts_state_start=self.n_free_verts if morph.is_free else self.n_fixed_verts, face_start=self.n_faces, edge_start=self.n_edges, vgeom_start=self.n_vgeoms, diff --git a/genesis/engine/solvers/rigid/support_field_decomp.py b/genesis/engine/solvers/rigid/support_field_decomp.py index a9aeb77f54..31c1a601b3 100644 --- a/genesis/engine/solvers/rigid/support_field_decomp.py +++ b/genesis/engine/solvers/rigid/support_field_decomp.py @@ -1,5 +1,7 @@ -from typing import TYPE_CHECKING from math import pi +from typing import TYPE_CHECKING + + from dataclasses import dataclass import numpy as np diff --git a/genesis/engine/solvers/tool_solver.py b/genesis/engine/solvers/tool_solver.py index b41f59d58e..7314f8ac31 100644 --- a/genesis/engine/solvers/tool_solver.py +++ b/genesis/engine/solvers/tool_solver.py @@ -1,4 +1,5 @@ from typing import TYPE_CHECKING + import taichi as ti from genesis.engine.boundaries import FloorBoundary diff --git a/genesis/options/surfaces.py b/genesis/options/surfaces.py index dfc357d940..a8cabb9376 100644 --- a/genesis/options/surfaces.py +++ b/genesis/options/surfaces.py @@ -513,7 +513,7 @@ def set_texture(self, texture): class BSDF(Surface): """ - Plastic surface is the most basic type of surface. + Bidirectional Scattering Distribution Function. Parameters ---------- @@ -579,7 +579,8 @@ def set_texture(self, texture): class Emission(Surface): """ - Emission surface. This surface emits light. Note that in Genesis's ray tracing pipeline, lights are not a special type of objects, but simply entities with emission surfaces. + Emission surface. This surface emits light. Note that in Genesis's ray tracing pipeline, lights are not a special + type of objects, but simply entities with emission surfaces. Parameters ---------- @@ -597,9 +598,11 @@ def set_texture(self, texture): ############################ Handy shortcuts ############################ + + class Default(BSDF): """ - The default surface type used in Genesis. This is just an alias for `Plastic`. + The default surface type used in Genesis. This is just an alias for `BSDF`. """ pass diff --git a/genesis/utils/geom.py b/genesis/utils/geom.py index 831ca79617..a5284693af 100644 --- a/genesis/utils/geom.py +++ b/genesis/utils/geom.py @@ -1620,10 +1620,6 @@ def default_solver_params(): return np.array([0.0, 1.0e00, 9.0e-01, 9.5e-01, 1.0e-03, 5.0e-01, 2.0e00]) -def default_friction(): - return 1.0 - - def default_dofs_kp(n=6): return np.full((n,), fill_value=100.0, dtype=gs.np_float) diff --git a/genesis/utils/urdf.py b/genesis/utils/urdf.py index afdf906281..5764dbfcaa 100644 --- a/genesis/utils/urdf.py +++ b/genesis/utils/urdf.py @@ -170,7 +170,6 @@ def parse_urdf(morph, surface): g_info["quat"] = gu.R_to_quat(geom.origin[:3, :3]) g_info["contype"] = 1 if geom_is_col else 0 g_info["conaffinity"] = 1 if geom_is_col else 0 - g_info["friction"] = gu.default_friction() g_info["sol_params"] = gu.default_solver_params() link_g_infos += link_g_infos_