New Generators
Implementing a new Generator is an involved process that requires inheriting from the core SimForge classes and implementing the necessary methods. Once you know which external tool or library you want to leverage, you can start by creating a new Python module and defining the following classes:
-
Generation [required]:
ExModelExporter(ModelExporter)
- Class that exports generated model assetsExGenerator(Generator)
- The main class that handles the generation of assets
-
Generation [optional]:
ExBaker(Baker)
- Class that bakes textures for the generated assets
-
Assets [standard]:
ExGeometry(Geometry)
- Class for geometry assetsExMaterial(Material)
- Class for material assetsExModel(Model)
- Class for model assets
-
Assets [extra]:
ExImage(Image)
- Class for image assetsExArticulation(Articulation)
- Class for articulation assets
First, make sure to read the documentation of the external tool or library you want to integrate with SimForge. This will help you understand the API and any limitations or constraints that you need to consider. Then, take a look at the existing generators in the SimForge codebase to get an idea of how you could structure your generator.
Template:
from __future__ import annotations
from pathlib import Path
from typing import Any, ClassVar, Dict, Mapping, Tuple
from simforge import (
Articulation,
Baker,
BakeType,
Generator,
Geometry,
Image,
Material,
Model,
ModelExporter,
)
from simforge._typing import ExporterConfig
class ExModelExporter(ModelExporter):
def export(self, filepath: Path | str, **kwargs) -> Path:
raise NotImplementedError
class ExBaker(Baker):
def setup(self):
pass
def bake(self, texture_resolution: int | Dict[BakeType, int]):
if self.enabled:
raise NotImplementedError
def cleanup(self):
pass
class ExGenerator(Generator):
EXPORTERS: ClassVar[ExporterConfig] = ExModelExporter()
BAKER: ClassVar[ExBaker] = ExBaker()
def _setup_articulation(
self,
asset: ExArticulation,
**kwargs,
) -> Dict[str, Any]:
return kwargs
def _generate_articulation(
self,
asset: ExArticulation,
seed: int,
**setup_kwargs,
) -> Dict[str, Any]:
raise NotImplementedError
def _export_articulation(
self,
asset: ExArticulation,
seed: int,
export_kwargs: Mapping[str, Any] = {},
**generate_kwargs,
) -> Tuple[Path, Dict[str, Any]]:
return self.__export(asset=asset, seed=seed, **export_kwargs), generate_kwargs
def _cleanup_articulation(
self,
asset: ExArticulation,
):
asset.cleanup()
def _setup_geometry(
self,
asset: ExGeometry,
**kwargs,
) -> Dict[str, Any]:
return kwargs
def _generate_geometry(
self,
asset: ExGeometry,
seed: int,
**setup_kwargs,
) -> Dict[str, Any]:
raise NotImplementedError
def _export_geometry(
self,
asset: ExGeometry,
seed: int,
export_kwargs: Mapping[str, Any] = {},
**generate_kwargs,
) -> Tuple[Path, Dict[str, Any]]:
return self.__export(asset=asset, seed=seed, **export_kwargs), generate_kwargs
def _cleanup_geometry(
self,
asset: ExGeometry,
):
asset.cleanup()
def _setup_image(
self,
asset: ExImage,
**kwargs,
) -> Dict[str, Any]:
return kwargs
def _generate_image(
self,
asset: ExImage,
seed: int,
**setup_kwargs,
) -> Dict[str, Any]:
raise NotImplementedError
def _export_image(
self,
asset: ExImage,
seed: int,
export_kwargs: Mapping[str, Any] = {},
**generate_kwargs,
) -> Tuple[Path, Dict[str, Any]]:
return self.__export(asset=asset, seed=seed, **export_kwargs), generate_kwargs
def _cleanup_image(
self,
asset: ExImage,
):
asset.cleanup()
def _setup_material(
self,
asset: ExMaterial,
**kwargs,
) -> Dict[str, Any]:
return kwargs
def _generate_material(
self,
asset: ExMaterial,
seed: int,
**setup_kwargs,
) -> Dict[str, Any]:
raise NotImplementedError
def _export_material(
self,
asset: ExMaterial,
seed: int,
export_kwargs: Mapping[str, Any] = {},
**generate_kwargs,
) -> Tuple[Path, Dict[str, Any]]:
return self.__export(asset=asset, seed=seed, **export_kwargs), generate_kwargs
def _cleanup_material(
self,
asset: ExMaterial,
):
asset.cleanup()
def _setup_model(
self,
asset: ExModel,
**kwargs,
) -> Dict[str, Any]:
return kwargs
def _generate_model(
self,
asset: ExModel,
seed: int,
**setup_kwargs,
) -> Dict[str, Any]:
raise NotImplementedError
def _export_model(
self,
asset: ExModel,
seed: int,
export_kwargs: Mapping[str, Any] = {},
**generate_kwargs,
) -> Tuple[Path, Dict[str, Any]]:
return self.__export(asset=asset, seed=seed, **export_kwargs), generate_kwargs
def _cleanup_model(
self,
asset: ExModel,
):
asset.cleanup()
class ExArticulation(Articulation, asset_metaclass=True, asset_generator=ExGenerator):
def setup(self):
raise NotImplementedError
def cleanup(self):
pass
def seed(self, seed: int):
pass
class ExGeometry(Geometry, asset_metaclass=True, asset_generator=ExGenerator):
def setup(self):
raise NotImplementedError
def cleanup(self):
pass
def seed(self, seed: int):
pass
class ExImage(Image, asset_metaclass=True, asset_generator=ExGenerator):
def setup(self):
raise NotImplementedError
def cleanup(self):
pass
def seed(self, seed: int):
pass
class ExMaterial(Material, asset_metaclass=True, asset_generator=ExGenerator):
def setup(self):
raise NotImplementedError
def cleanup(self):
pass
def seed(self, seed: int):
pass
class ExModel(Model, asset_metaclass=True, asset_generator=ExGenerator):
def setup(self):
raise NotImplementedError
def cleanup(self):
pass
def seed(self, seed: int):
pass
If you have any questions regarding a specific generator, feel free to open a new issue.