Model Librarian

September 19, 2022 · View on GitHub

A Model Librarian is a model records database.

from tdw.librarian import ModelLibrarian

lib = ModelLibrarian()
from tdw.librarian import ModelLibrarian

lib = ModelLibrarian(library="path/to/your/database/file.json")

A Model Librarian contains ModelRecord objects.

record = lib.records[0]
print(record.name, record.wcategory) # afl_lamp table lamp

Default Libraries

TDW has three database files for three remote model libraries. To access these files, just provide the filename in the constructor without a path, e.g.:

from tdw.librarian import ModelLibrarian

lib = ModelLibrarian(library="models_full.json")

If you don't provided a value for library, the default is models_core.json.

LibraryDescriptionFree?
models_core.jsonApproximately 200 high-quality models.
models_full.jsonApproximately 2000 high-quality models + all models from models_core.json.
models_special.jsonPrimitives and specialized models.
models_flex.jsonPrimitives that have been optimized for Flex deformation.

Command API

Send the add_object command to add a model to the scene from a remote or local asset bundle.

from tdw.controller import Controller

c = Controller()

init(c) # Initialize the scene. Your code here.
record = get_record() # Get a model record. Your code here.
position = get_position() # Your code here.
rotation = get_rotation() # Your code here.

object_id = Controller.get_unique_id()
c.communicate({"$type": "add_object",
                "name": record.name,
                "url": record.get_url(),
                "scale_factor": record.scale_factor,
                "position": position,
                "rotation": rotation,
                "id": object_id})

The Controller class includes a few helper functions for using records to add objects to the scene. See the Controller documentation.

ModelRecord API

A record of a model asset bundle.

from tdw.librarian import ModelRecord

record = ModelRecord() # Creates a record with blank or default values.
from tdw.librarian import ModelRecord

record = ModelRecord(data=data) # Creates a record from JSON data.

Fields

FieldTypeDescription
namestrThe name of the model.
urlsDict[str, str]A dictionary of URLs or local filepaths of asset bundles per platform. See: ModelRecord.get_url()
wnidstrThe WordNet/ImageNet semantic category ID of the model.
wcategorystrThe category description associated with the wnid. Required for the _category image pass to work correctly.
scale_factorfloatWhen the model is first loaded into the build, it will be scaled from its default size by this factor.
flexboolIf true, this model is Flex-compatible.
do_not_useboolIf true, there is something wrong with this model (we're working on it!). The build will still load the model if prompted; this is just a warning for you.
do_not_use_reasonstrIf do_not_use == True, this is a brief reason why.
substructureList[dict]A list of all sub-objects in the model and their visual materials. Use this with the set_visual_material command.
Each element is a dictionary structured as: {"name": "sub-object", "materials": ["material", "material", "etc."]}
boundsDict[str, Dict[str, float]]A list of points around the object defining its bounds after being scaled by the scale_factor.
canonical_rotationDict[str, float]The Vector3 Euler angles that the object should face if an avatar is loaded into the scene (and the avatar isn't rotated).
physics_qualityfloatThe percentage of the object's mesh covered by colliders.
asset_bundle_sizesDict[str, int]A dictionary of asset bundle sizes. Key=Platform. Value=The size of the binary in bytes.
composite_objectboolIf true, this model is a composite object.
volumefloatThe volume of the object in cubic meters.
container_shapesList[ContainerShape]A list of ContainerShape data. This data is used by the ContainerManager add-on.
affordance_pointsList[Dict[str, float]]A list of "affordance points" where an object can be picked up. This data is used by the Replicant add-on.

Functions

def get_url(self) -> str:

Returns the URL of the asset bundle for this platform. This is a wrapper for record.urls.

lib = ModelLibrarian()
record = lib.records[0]

print(record.get_url())

ModelLibrarian API

Fields

FieldTypeDescription
librarystrThe path to the records database file.
datadictThe raw JSON dictionary loaded from the records database file.
descriptionstrA brief description of the library.
recordsList[ModelRecord]The list of model records.

Static Functions

def create_library(description: str, path: str) -> None:

Create a new library JSON file.

ModelLibrarian.create_library("My library", path="path/to/new/library.json")
ParameterTypeDescription
descriptionstrA description of the library.
pathstrThe absolute filepath to the .json records database file.

def get_library_filenames() -> List[str]:

Returns a list of the filenames of the libraries of this type in the tdw module.

filenames = ModelLibrarian.get_library_filenames()

print(filenames) # ['models_core.json', 'models_full.json', 'models_special.json', 'models_flex.json']

def get_default_library() -> List[str]:

Returns the filename of the default library (which is always the first element in the list returned by get_library_filenames().

default_library = ModelLibrarian.get_default_library()

print(default_library) # models_core.json

Functions

def get_record(self, name: str) -> Optional[ModelRecord]:

Returns a record with the specified name. If that record can't be found, returns None.

lib = ModelLibrarian()
record = lib.get_record("arco_lamp")

print(record.name) # arco_lamp
ParameterTypeDescription
namestrThe name of the record.

def search_records(self, search: str) -> List[ModelRecord]:

Returns a list of records whose names include the search keyword.

lib = ModelLibrarian()
records = lib.search_records("lamp")

for record in records:
    print(record.name) # afl_lamp, alma_floor_lamp, etc.
ParameterTypeDescription
searchstrThe string to search for in the model name.

def add_or_update_record(self, record: ModelRecord, overwrite: bool, write: bool = True, quiet: bool = True) -> bool:

Add a new record or update an existing record.

record = define_record() # Provide your own code here.
lib = ModelLibrarian()

lib.add_or_update_record(record, False, write=True, quiet=False)
ParameterTypeDescription
recordModelRecordThe new or modified record.
overwriteboolIf True: If there is a record with the same name as this record, replace it with the new record and return True. Otherwise, return False.
If False: If there is a record with the same name as this record, don't add the model, and suggest a new name.
writeboolIf true, write the library data to disk (overwriting the existing file).
quietboolIf true, don't print out messages to the console.

def remove_record(self, record: Union[str, MaterialRecord], write: bool = True) -> bool:

Remove a record. Returns true if the record was removed.

record = define_record() # Provide your own code here.
lib = ModelLibrarian()

lib.remove_record(record) # Returns False.
lib = ModelLibrarian()

lib.remove_record("arco_lamp") # Returns True.
ParameterTypeDescription
recordModelRecord or strThe record or the name of the record.
writeboolIf true, write the library data to disk (overwriting the existing file).

def write(self, pretty=True) -> None:

Write the library data to disk (overwriting the existing file).

ParameterTypeDescription
prettybool"Pretty print" the JSON data with line breaks and indentations.

def get_valid_record_name(self, name: str, overwrite: bool) -> Tuple[bool, str, List[str]]:

Generates a valid record name. Returns: true if the name is good as-is, the new name, and a list of problems with the old name.

lib = ModelLibrarian()

ok, name, problems = lib.get_valid_record_name("arco_lamp", True)

print(ok) # True
print(name) # arco_lamp
lib = ModelLibrarian()

ok, name, problems = lib.get_valid_record_name("arco_lamp", False)

print(ok) # False
print(name) # arco_lampabcd
print(problems) # ["A record named arco_lamp already exists, and we don't want to overwrite it."]
ParameterTypeDescription
namestrThe name of a record we'd like to add.
overwritestrIf True: raise an exception if a record named name doesn't already exist.
If False: If the record exists, suggest a new name.

def get_model_wnids_and_wcategories(self) -> Dict[str, str]:

Returns a dictionary of all model wnids and categories. Key=wnid Value=wcategory

lib = ModelLibrarian()

wnids_dict = lib.get_model_wnids_and_wcategories()

def get_model_wnids(self) -> List[str]:

Returns a list of all unique wnids in the database, sorted numerically.

lib = ModelLibrarian()
wnids = lib.get_model_wnids()

print(wnids[0]) # n02206856

def get_flex_models(self) -> List[ModelRecord]:

Returns a list of all Flex-compatible models.

lib = ModelLibrarian()
records = lib.get_flex_models()

print(records[0].name, records[0].flex) # alma_floor_lamp True