Script in Python
Learn how to use the Python API to automate tasks in Pixyz Studio.
Whether you want to script short helper functions in Pixyz Studio or advanced data preparation scenarios for Pixyz Scenario Processor, this document should help you get started or improve your knowledge.
Tools
In this document, we'll use Pixyz Studio as our main framework and IDE but please note that Pixyz Python API is transversal to all compatible products: Pixyz Studio, Pixyz Scenario Processor, Pixyz Batch (deprecated), etc.
Note
When using your preferred IDE for development you will suffer from lack of autocompletion. Have a look at our custom workaround to generate static autocompletion libraries for Visual Code, Sublime or PyCharm.
All API functions are listed in the API Reference, but also directly in Pixyz Studio Function List. This tool is particularly useful to find methods from keywords, go to their documentation and access parameters and returned types, but also to copy and paste Python code:
Structure
Consider that anything doable via a human interaction in Pixyz Studio is doable through the API.
To understand the logic of Pixyz scripting you must understand the structure behind it:
Pixyz entity structure (simplified)
Entities
Entities are abstract objects defined by an integer ID (meaning that an occurrence, a material or a component will all have an ID). Each ID is unique and most functions take this ID or a list of IDs as input. Some functions such as core.getProperty
, core.setProperty
, or core.listProperties
take all types of entities as input – meaning that you'll use the same function to access an occurrence, a material or a part property:
core.getProperty(3, 'Visible') → 'Inherited'
core.getProperty(15, 'color') → '[0, 1, 1, 1]'
Tip
Use eval(…)
to convert the returned string value of getProperty
into a list (e.g. for the color
property) or a list of lists (e.g. for the Transform
property).
Occurrences
Occurrences are the nodes in the product structure, they can have children and prototypes. Most of the optimization functions take an occurrence or a list of occurrences as input functions. For example:
algo.tessellate([1], …)
will apply on all children of1
.- To retrieve the root occurrence in your scene you can use the
scene.getRoot()
function. - To find occurrences based on a property you can use the
scene.findByProperty(property, regex)
function.
Properties defining occurrences can be visualized in the Inspector (ID, Name, Visible, Material, Transform…).
Tip
A useful way to retrieve all occurrences in your scene, or recursive children of an occurrence is to use the findByProperty
method with the Name
property and .*
as a regex: scene.findByProperty('Name', '.*', [scene.getRoot()])
.
⇒ Find all the Occurrences, with the Property Name= anything, among the Occurrences that compose the Root of the scene (= all the occurrences).
Tip
To only retrieve part occurrences (occurrences containing a part component) use scene.getPartOccurrences(root)
.
Components
Components are behaviors attached to occurrences. Their IDs can be retrieved thanks to the scene.getComponent(occurrence, componentType)
or the scene.getComponentByOccurrence(listOfOccurrences, componentType)
methods (value is 0 if does not exist for the second method). Component types are listed in the scene.ComponentType
enum. You can visualize the components in the Inspector below the occurrence properties:
Metadata
Metadata are components storing basic key/value information retrieved in the imported files. You can add, modify, and delete metadata through the API. You can either use core.listProperties
or core.getProperty
to access this information or directly extract it using scene.getMetadatasDefinitions(listOfMetadataComponents)
. You can also use scene.findByMetadata(property, regex)
to retrieve occurrences based on metadata.
occurrences = scene.findByProperty('Name', '.*')
metadataComponents = scene.getComponentByOccurrence(occurrences, scene.ComponentType.Metadata)
metadataDefinitions = scene.getMetadatasDefinitions(metadataComponents)
for occurrence, definition in zip(occurrences, metadataDefinitions):
print(f'Occurrence {occurrence} contains {len(definition)} metadata')
for propValue in definition:
print(f'{propValue.name}:{propValue.value}')
Part
Part components contain geometry information (CAD, mesh, lines, UVs…). For example, to retrieve mesh definitions from a list of occurrences:
partComponents = scene.getComponentByOccurrence(occurrences, scene.ComponentType.Part)
for occurrence, partComponent in zip(occurrences, partComponents):
if partComponent != 0: # meaning the corresponding occurrence did not have any part attached
mesh = scene.getPartMesh(partComponent)
meshDef = polygonal.getMeshDefinition(mesh)
vertices = meshDef.vertices # MeshDefinition is a structure, its attributes can be found in the documentation: https://www.pixyz-software.com/documentations/html/2022.1/studio/api/#polygonal-types
Materials
Materials are entities containing visual definitions. They can be interactively accessed from the Material Editor. They are defined by a pattern and properties specific to each pattern.
Available patterns
When creating a material from script, a pattern is required: fill it with one of the above ones depending on which type of material you want to create (material.createMaterial("Standard Material", "standard")
).
When modifying from script a material defined by complex properties, it can be hard to understand how to fill the value parameters of core.getProperty
. For example the diffuse value of a standard material:
In this case you can print in the console the diffuse value of an existing material by just executing: print(core.getProperty(49, 'diffuse'))
, which will output COLOR([0.000000, 0.000000, 0.000000])
. So to modify a diffuse texture please proceed as follows: core.setProperty(materialId, 'COLOR(' + str(YOUR_VALUES) + ')')
.
For example, here is a script to assign materials based on a metadata:
def assignMaterialsFromMetadata():
existingMaterials = {core.getProperty(mat, 'Name'):mat for mat in material.getAllMaterials()}
filteredOccurrences = scene.findByMetadata('CAD_MATERIAL', '.*')
filteredMetadata = scene.getComponentByOccurrence(filteredOccurrences, 5, True) # get all metadata components containing the 'CAD_MATERIAL' property
for occurrence, metadata in zip(filteredOccurrences, filteredMetadata):
materialName = scene.getMetadata(metadata, 'CAD_MATERIAL')
if materialName in existingMaterials.keys():
core.setProperty(occurrence, 'Material', str(existingMaterials[materialName]))
else:
newMaterial = material.createMaterial(materialName, 'color') # pattern can be 'standard', 'color', 'PBR', or 'unlittexture'
core.setProperty(newMaterial, 'color', str([0.5, 0.5, 0.5, 1])) # color values could be in another property
core.setProperty(occurrence, 'Material', str(newMaterial))
existingMaterials[materialName] = newMaterial
assignMaterialsFromMetadata()
Tips
- Sample scripts are accessible in the Pixyz Studio installation folder (
doc/Sample Scripts
) or on our Gitlab. - To search the Python API documentation offline, use the pixyz-api-search tool. This tool supports partial matches. This tool has been developed for the 2022.1 version.
- When parsing a large number of occurrences, thousands of logs will be written in the console. It can slow down your process or even freeze Pixyz Studio. You can disable the logs by using the
core.configureInterfaceLogger
function. Don't forget to re-enable them in the end. Generate your own progression steps by using the
core.pushProgression
andcore.stepProgression
methods. For example:allPartOccurrences = scene.getPartOccurrences() core.pushProgression(len(allPartOccurrences)) for occurrence in allPartOccurrences: # ... core.stepProgression() core.popProgression()
When retrieving a structure from a method (e.g.
scene.getAABB(occurrences)
), you can check the documentation to get the attributes names (e.g. AABB.low and AABB.high).aabb = scene.getAABB([scene.getRoot()]) print(f'Higher x values: {aabb.high.x}')
To import custom modules: Import custom Python modules in Studio
Most preferences are shared between Pixyz products. You can find the list of preferences in Pixyz Studio references (Edit > Preferences). To change them from script, use the
core.setModuleProperty
method. For example:core.setModuleProperty('IO', 'PreferLoadMesh', 'True')