Layerstack navigation
The layerstack module allows to query layers and effects and their content.
Examples
Search and Select a specific node
# This example shows how to recursively navigate into the layerstack to search for a specific
# substance resource and select the node containing it.
import substance_painter as sp
def match_resource_name(source: sp.source.Source, resource_name: str):
if type(source) is sp.layerstack.SourceSubstance:
return source.resource_id.name == resource_name
return False
def find_node_with_substance(
node: sp.layerstack.Node, resource_name: str):
# If the node is a Group, iterate over its sub-layers
if type(node) is sp.layerstack.GroupLayerNode:
for child in node.sub_layers():
result = find_node_with_substance(child, resource_name)
if result:
return result
# If the node is a Layer, iterate over its content stack and mask stack
if isinstance(node, sp.layerstack.LayerNode):
for content_effect in node.content_effects():
result = find_node_with_substance(content_effect, resource_name)
if result:
return result
for mask_effect in node.mask_effects():
result = find_node_with_substance(mask_effect, resource_name)
if result:
return result
# Check if the node itself contains the resource
if type(node) is sp.layerstack.FillLayerNode or type(node) is sp.layerstack.FillEffectNode:
# Check if the Fill is in material mode (the source write to multiple channels)
if node.source_mode == sp.source.SourceMode.Material:
if match_resource_name(node.get_material_source(), resource_name):
return node
# Check if the Fill is in split mode (each source write to a single channel)
elif node.source_mode == sp.source.SourceMode.Split:
# Iterate over the active channels of the Fill
for channel in node.active_channels:
if match_resource_name(node.get_source(channel), resource_name):
return node
# This case happens only in the mask stack, where there is no channel
else:
source = node.get_source(None) # There is no channel in the mask stack
if match_resource_name(source, resource_name):
return node
elif (type(node) is sp.layerstack.GeneratorEffectNode
or type(node) is sp.layerstack.FilterEffectNode):
if match_resource_name(node.get_source(), resource_name):
return node
return None
def find_substance_in_layerstack(resource_name: str):
# Retrieve the list of all texture sets
texture_sets = sp.textureset.all_texture_sets()
# Iterate over all texture sets
for texture_set in texture_sets:
# Iterate over all stacks in the texture set
for stack in texture_set.all_stacks():
# Get all Layer nodes at the root of the stack
stack_root_nodes = sp.layerstack.get_root_layer_nodes(stack)
# Iterate over the layers to find the one containing the substance
for layer in stack_root_nodes:
# Check if the layer contains the substance
node = find_node_with_substance(layer, resource_name)
if node:
return node
# Open the French Restaurant Table sample
# Note: you should replace <PATH_TO_PAINTER> with the path where
# Substance 3D Painter is installed on your machine
sp.project.open("<PATH_TO_PAINTER>/resources/samples/FrenchRestaurantTable.spp")
resource_name = "fabric_linen/fabric_linen"
node = find_substance_in_layerstack(resource_name)
if node:
# Ensure the stack containing the node is active
stack = node.get_stack()
if stack != sp.textureset.get_active_stack():
sp.textureset.set_active_stack(stack)
# Select the node
sp.layerstack.set_selected_nodes([node])
Geometry mask manipulation
# This example shows how to manipulate Geometry Masks in the layerstack
import substance_painter as sp
# Open the French Restaurant Table sample
# Note: you should replace <PATH_TO_PAINTER> with the path where
# Substance 3D Painter is installed on your machine
sp.project.open("<PATH_TO_PAINTER>/resources/samples/FrenchRestaurantTable.spp")
# Select the 'Table' texture set
for textureset in sp.textureset.all_texture_sets():
if textureset.name() == "Table":
stack = textureset.get_stack()
break
sp.textureset.set_active_stack(stack)
# Get the root layers from the stack
stack_root_layers = sp.layerstack.get_root_layer_nodes(stack)
# Get the layer at the top of the stack
first_layer = stack_root_layers[0]
# Get the layer's texture set
first_layer_texture_set = first_layer.get_texture_set()
# Avoid error checking if Layer has UDIM (UV Tiles)
if first_layer_texture_set.has_uv_tiles():
# Define which UV Tile should be activated (will deactivate the other ones)
first_layer.set_geometry_mask(
sp.layerstack.GeometryMaskUVTilesParams(
inclusion_list=True,
uv_tiles=[
first_layer_texture_set.uv_tile(0, 0), # UDIM 1001
first_layer_texture_set.uv_tile(1, 0), # UDIM 1002
]
)
)
# Create a Fill Layer at the top of the stack
fill_layer_position = sp.layerstack.InsertPosition.from_textureset_stack(stack)
fill_layer = sp.layerstack.insert_fill(fill_layer_position)
plant_group_meshes = []
# Get the Fill layer's texture set
plant_group_texture_set = fill_layer.get_texture_set()
# List all meshes where name contains 'flower'
for mesh in plant_group_texture_set.all_mesh_names():
if "flower" in mesh:
plant_group_meshes.append(mesh)
# Enable Meshes into the Geometry Mask
fill_layer.set_geometry_mask(
sp.layerstack.GeometryMaskMeshParams(
inclusion_list=True,
meshes=plant_group_meshes,
)
)
# Activate Base Color (to see the result)
fill_layer.active_channels = {sp.textureset.ChannelType.BaseColor}
# Select the modified layers
sp.layerstack.set_selected_nodes([first_layer, fill_layer])
Get nodes
substance_painter.layerstack.get_root_layer_nodes(stack: Stack) -> List[LayerNode | GroupLayerNode | PaintLayerNode | InstanceLayerNode | FillLayerNode] substance_painter.layerstack.get_root_layer_nodes
Get the root layers of a stack, ordered like in the layer stack.
Parameters: stack (Stack) – Stack to query.
Raises: ValueError – If stack is invalid.
Returns: The root layers of the stack.
Return type: List[LayerNode | GroupLayerNode | PaintLayerNode | InstanceLayerNode | FillLayerNode]
substance_painter.layerstack.get_node_by_uid(node_id: int) -> List[LayerNode | GroupLayerNode | PaintLayerNode | InstanceLayerNode | FillLayerNode | GeneratorEffectNode | PaintEffectNode | FillEffectNode | LevelsEffectNode | CompareMaskEffectNode | FilterEffectNode | ColorSelectionEffectNode | AnchorPointEffectNode] substance_painter.layerstack.get_node_by_uid
Get a node by its internal identifier.
Parameters: node_id (int) – The node uid.
Raises: ValueError – If the given uid doesn’t correspond to a valid node.
Returns: The node with the given uid.
Return type: List[LayerNode | GroupLayerNode | PaintLayerNode | InstanceLayerNode | FillLayerNode | GeneratorEffectNode | PaintEffectNode | FillEffectNode | LevelsEffectNode | CompareMaskEffectNode | FilterEffectNode | ColorSelectionEffectNode | AnchorPointEffectNode]
Node Objects
class substance_painter.layerstack.Node(uid) substance_painter.layerstack.Node
Abstract class to manipulate common properties of a layer stack node.
Each node is identified by a node uid.
Calling methods of a Node with an incorrect uid throws a ValueError.
This could happen when instanciating a Node providing its uid by hand, or when the Node no
longer refers to existing data in the Layer Stack.
get_type() -> NodeType substance_painter.layerstack.Node.get_type
Check the type of the node.
Returns: The node type.
Return type: NodeType
get_texture_set() -> TextureSet substance_painter.layerstack.Node.get_texture_set
Get the TextureSet this node belongs to.
Returns: the TextureSet this node belongs to.
Return type: TextureSet
is_visible() -> bool substance_painter.layerstack.Node.is_visible
Check whether this node is rendered.
Returns: Whether this node is rendered.
Return type: bool
set_visible(visible: bool) substance_painter.layerstack.Node.set_visible
Enable this node for rendering.
Parameters: visible (bool) – Whether to enable this node for rendering.
get_name() -> str substance_painter.layerstack.Node.get_name
Get the name assigned to this Node.
Returns: The Node name.
Return type: str
set_name(name: str) substance_painter.layerstack.Node.set_name
Change this node name.
Parameters: name (str) – New name to use.
is_in_mask_stack() -> bool substance_painter.layerstack.Node.is_in_mask_stack
Check whether this node is part of a mask stack.
Returns: Whether this node is part of a mask stack.
Return type: bool
has_blending() -> bool substance_painter.layerstack.Node.has_blending
Check whether this node supports blending information (blending mode + opacity).
The blending might be per Channel Type for regular nodes, or monochannel for nodes
inside a mask stack.
Returns: Whether this node supports blending information.
Return type: bool
get_blending_mode(channel: ChannelType | None = None) -> BlendingMode substance_painter.layerstack.Node.get_blending_mode
Get the blending mode for a Node.
If the node is not in a mask stack, a Channel Type must be provided.
If the node is in a mask stack, Channel Type must be None.
Parameters: channel (ChannelType | None) – Channel Type to query or None for mask nodes.
Raises:
ValueError – If the node has blending information per Channel Type and no Channel
Type is provided, or if the node has blending information without Channel Type and
a Channel Type is provided.
Returns: The blending mode of this node for the given Channel Type or for the mask.
Return type: BlendingMode
set_blending_mode(blending_mode: BlendingMode, channel: ChannelType | None = None) substance_painter.layerstack.Node.set_blending_mode
Set the blending mode for a Node.
If the node is not in a mask stack, a Channel Type must be provided.
If the node is in a mask stack, Channel Type must be None.
Parameters:
- blending_mode (BlendingMode) – New blending mode to apply.
- channel (ChannelType | None) – Channel type to update or None for mask nodes.
Raises:
ValueError – If the node has blending information per Channel Type and no Channel
Type is provided, or if the node has blending information without Channel Type and
a Channel Type is provided.
get_opacity(channel: ChannelType | None = None) -> float substance_painter.layerstack.Node.get_opacity
Get the opacity for a Node.
If the node is not in a mask stack, a Channel Type must be provided.
If the node is in a mask stack, Channel Type must be None.
Parameters: channel (ChannelType | None) – Channel Type to query or None for mask nodes.
Raises:
ValueError – If the node has blending information per Channel Type and no Channel
Type is provided, or if the node has blending information without Channel Type and
a Channel Type is provided.
Returns: The opacity of this node for the given Channel Type or for the mask.
Return type: float
set_opacity(opacity: float, channel: ChannelType | None = None) substance_painter.layerstack.Node.set_opacity
Set the opacity for a node.
If the node is not in a mask stack, a Channel Type must be provided.
If the node is in a mask stack, Channel Type must be None.
Parameters:
- opacity (float) – New opacity to apply, value between 0.0 and 1.0.
- channel (ChannelType | None) – Channel Type to update or None for mask nodes.
Raises:
ValueError – If the node has blending information per Channel Type and no Channel
Type is provided, or if the node has blending information without Channel Type and
a Channel Type is provided.
get_stack() -> Stack substance_painter.layerstack.Node.get_stack
Get the stack that contains this node.
Returns: The stack that contains this node.
Return type: Stack
get_parent() -> Node substance_painter.layerstack.Node.get_parent
Get the parent of this node.
Returns: The parent of this node, or None if this node is a root layer.
Return type: Node
get_next_sibling() -> Node substance_painter.layerstack.Node.get_next_sibling
Get the next sibling of this node.
Returns: The next sibling of this node, or None if this node is the first sibling.
Return type: Node
get_previous_sibling() -> Node substance_painter.layerstack.Node.get_previous_sibling
Get the previous sibling of this node.
Returns: The previous sibling of this node, or None if this node is the last sibling.
Return type: Node
uid() -> int substance_painter.layerstack.Node.uid
Get the object internal uid.
Returns: The internal identifier of the object as an integer.
Return type: int
class substance_painter.layerstack.LayerNode(uid) substance_painter.layerstack.LayerNode
Bases: Node
A Node that is part of the main hierarchy. Every Layer such as a paint or fill layer, as well as
groups, are organized into this hierarchy.
As such, you can query sub layers (in the case the LayerNode is a group), but also associate
content effects and mask effects (such as levels and filters and so on).
content_effects() -> List[GeneratorEffectNode | PaintEffectNode | FillEffectNode | LevelsEffectNode | CompareMaskEffectNode | FilterEffectNode | ColorSelectionEffectNode | AnchorPointEffectNode] substance_painter.layerstack.LayerNode.content_effects
Query the content effects of this node, ordered like in the layer stack.
Returns: The content effects of this node.
Return type: List[GeneratorEffectNode | PaintEffectNode | FillEffectNode | LevelsEffectNode | CompareMaskEffectNode | FilterEffectNode | ColorSelectionEffectNode | AnchorPointEffectNode]
mask_effects() -> List[GeneratorEffectNode | PaintEffectNode | FillEffectNode | LevelsEffectNode | CompareMaskEffectNode | FilterEffectNode | ColorSelectionEffectNode | AnchorPointEffectNode] substance_painter.layerstack.LayerNode.mask_effects
Query the mask effects of this node, ordered like in the layer stack.
Returns: The mask effects of this node.
Return type: List[GeneratorEffectNode | PaintEffectNode | FillEffectNode | LevelsEffectNode | CompareMaskEffectNode | FilterEffectNode | ColorSelectionEffectNode | AnchorPointEffectNode]
instances() -> List[LayerNode] substance_painter.layerstack.LayerNode.instances
Return the list of instances of this layer.
See the documentation on layer instancing if you are not familiar with the
concept: Layer instancing documentation.
Returns: The instances of this node.
Return type: List[LayerNode]
get_geometry_mask_type() -> GeometryMaskType substance_painter.layerstack.LayerNode.get_geometry_mask_type
Query the geometry mask type currently applied to this node.
Returns: The type of geometry mask for this layer node.
Return type: GeometryMaskType
Geometry mask documentation
set_geometry_mask_type(geometry_mask_type: GeometryMaskType) substance_painter.layerstack.LayerNode.set_geometry_mask_type
Set the geometry mask type to apply to this node.GeometryMaskType.UVTile is only
supported when the corresponding Texture Set uses UV Tiles.
Parameters: geometry_mask_type (GeometryMaskType) – The type of geometry mask for this layer node.
Raises:
ValueError – When GeometryMaskType.UVTile is requested and the project does not
support UV Tiles.
use
substance_painter.layerstack.LayerNode.set_geometry_mask() instead.get_geometry_mask_enabled_meshes() -> List[str] substance_painter.layerstack.LayerNode.get_geometry_mask_enabled_meshes
Get the list of enabled meshes for the geometry mask. Meshes that are not in this list are
disabled.
To get the complete list of meshes, seesubstance_painter.textureset.TextureSet.all_mesh_names().
Returns: The list of enabled meshes for the geometry mask.
Return type: List[str]
Geometry mask documentation
set_geometry_mask_enabled_meshes(mesh_names: List[str]) substance_painter.layerstack.LayerNode.set_geometry_mask_enabled_meshes
Set the list of enabled meshes for the geometry mask. Meshes that are not in this list will
be disabled. To get the complete list of meshes, seesubstance_painter.textureset.TextureSet.all_mesh_names().
Parameters: mesh_names (List*[str]*) – The list of meshes to enable for the geometry mask.
Raises: ValueError – If a mesh name does not belong to any texture set in the project.
use
substance_painter.layerstack.LayerNode.set_geometry_mask() instead.Geometry mask documentation
get_geometry_mask_enabled_uv_tiles() -> List[UVTile] substance_painter.layerstack.LayerNode.get_geometry_mask_enabled_uv_tiles
Get the list of enabled UV Tiles for the geometry mask. UV Tiles that are not in this list
are disabled. To get the complete list of UV Tiles, seesubstance_painter.textureset.TextureSet.all_uv_tiles().
Returns: The list of enabled UV Tiles for the geometry mask.
Return type: List[UVTile]
Geometry mask documentation
set_geometry_mask_enabled_uv_tiles(uv_tiles: List[UVTile]) substance_painter.layerstack.LayerNode.set_geometry_mask_enabled_uv_tiles
Set the list of enabled UV Tiles for the geometry mask. UV Tiles that are not in this list
will de disabled. To get the complete list of UV Tiles, seesubstance_painter.textureset.TextureSet.all_uv_tiles().
Parameters: uv_tiles (List*[UVTile]*) – The list of UV Tiles to enable for the geometry mask.
Raises: ValueError – If a UV Tile does not belong to this texture set.
use
substance_painter.layerstack.LayerNode.set_geometry_mask() instead.Geometry mask documentation
get_geometry_mask() -> GeometryMaskMeshParams | GeometryMaskUVTilesParams substance_painter.layerstack.LayerNode.get_geometry_mask
Get geometry mask current settings.
Returns: Geometry mask parameters including type, list mode and listed elements.
Return type: GeometryMaskMeshParams | GeometryMaskUVTilesParams
Geometry mask documentation
set_geometry_mask(params: GeometryMaskMeshParams | GeometryMaskUVTilesParams) substance_painter.layerstack.LayerNode.set_geometry_mask
Set geometry mask settings.
Parameters: params (GeometryMaskMeshParams | GeometryMaskUVTilesParams) – Geometry mask parameters.
Raises: ValueError – If parameters are inconsistent or contain invalid elements.
Geometry mask documentation
has_mask() -> bool substance_painter.layerstack.LayerNode.has_mask
Check whether this node has a mask.
Returns: Whether this node has a mask.
Return type: bool
add_mask(background: MaskBackground) substance_painter.layerstack.LayerNode.add_mask
Add a mask on this node with the specified background.
Raises:
ValueError – If a mask is already set on this node.
Use has_mask() to check if the node has a mask.
Parameters: background (MaskBackground)
remove_mask() substance_painter.layerstack.LayerNode.remove_mask
Remove this node mask, including all its effects.
Raises:
ValueError – If no mask exists on this node.
Use has_mask() to check if the node has a mask.
get_mask_background() -> MaskBackground substance_painter.layerstack.LayerNode.get_mask_background
Query the type of mask used by this node.
Raises:
ValueError – If no mask exists on this node.
Use has_mask() to check if the node has a mask.
Returns: The mask background applied to this node.
Return type: MaskBackground
set_mask_background(background: MaskBackground) substance_painter.layerstack.LayerNode.set_mask_background
Set the mask background on this node.
Parameters: background (MaskBackground) – The mask background to be applied on this node mask.
Raises:
ValueError – If no mask exists on this node.
Use has_mask() to check if the node has a mask.
is_mask_enabled() -> bool substance_painter.layerstack.LayerNode.is_mask_enabled
Query whether the mask is currently enabled.
Raises:
ValueError – If no mask exists on this node.
Use has_mask() to check if the node has a mask.
Returns: Whether the mask is currently enabled.
Return type: bool
enable_mask(enabled: bool) substance_painter.layerstack.LayerNode.enable_mask
Set whether the mask is currently enabled.
Parameters: enabled (bool) – Whether to enable the mask.
Raises:
ValueError – If no mask exists on this node.
Use has_mask() to check if the node has a mask.
substance_painter.layerstack.HierarchicalNode substance_painter.layerstack.HierarchicalNode
alias of LayerNode | GroupLayerNode | PaintLayerNode | InstanceLayerNode | FillLayerNode
substance_painter.layerstack.EffectNode substance_painter.layerstack.EffectNode
alias of GeneratorEffectNode | PaintEffectNode | FillEffectNode | LevelsEffectNode | CompareMaskEffectNode | FilterEffectNode | ColorSelectionEffectNode | AnchorPointEffectNode
Enums
class substance_painter.layerstack.NodeType(value) substance_painter.layerstack.NodeType
For more information about layers and effects, see Layers and effects.
Members:
PaintLayerPaintEffectFillLayerFillEffectGeneratorEffectFilterEffectLevelsEffectCompareMaskEffectColorSelectionEffectGroupLayerInstanceLayerAnchorPointEffectclass substance_painter.layerstack.MaskBackground(value) substance_painter.layerstack.MaskBackground
Members:
BlackWhiteclass substance_painter.layerstack.BlendingMode(value) substance_painter.layerstack.BlendingMode
Blending Modes allow to mix the result of a layer with the other layers below in different manners.
For more information, see the Blending modes documentation.
Members:
NormalPassThroughDisableReplaceMultiplyDivideInverseDivideDarkenLightenLinearDodgeSubtractInverseSubtractDifferenceExclusionSignedAdditionOverlayScreenLinearBurnColorBurnColorDodgeSoftLightHardLightVividLightLinearLightPinLightTintSaturationColorValueNormalMapCombineNormalMapDetailNormalMapInverseDetailclass substance_painter.layerstack.GeometryMaskType(value) substance_painter.layerstack.GeometryMaskType
Members:
MeshUVTile