Layerstack edition

The layerstack module allows the insertion and deletion of layers and effects.

Example

import substance_painter as sp

# Get the currently displayed stack
stack = sp.textureset.get_active_stack()

# Get all Layer nodes at the root of the stack
stack_root_nodes = sp.layerstack.get_root_layer_nodes(stack)
# Find the layer at the very bottom
bottom_layer = stack_root_nodes[len(stack_root_nodes) - 1]

# Create the position where to insert the Group
# Get the very bottom Layer Position
position_stack_bottom = sp.layerstack.InsertPosition.below_node(bottom_layer)

# Insert the Group Layer
my_group = sp.layerstack.insert_group(position_stack_bottom)
my_group.set_name("My Group")
my_group.set_collapsed(False)

# Insert a Fill Layer into the group and assign a Material from the starter asset library
position_group_content = sp.layerstack.InsertPosition.inside_node(
    my_group, sp.layerstack.NodeStack.Substack)
# Insert Fill Layer
my_fill_layer = sp.layerstack.insert_fill(position_group_content)
my_fill_layer.set_name("My Fill Layer")
# Search and isolate a Substance material
fill_layer_resource = sp.resource.search("s:starterassets "
                                         "u:substance "
                                         "n:Paper\\ Grainy=")[0]
# Apply material from the library Substance ID in the Fill Layer
my_fill_layer.set_material_source(fill_layer_resource.identifier())

# Insert Fill effect into the "my_fill_layer"'s effect stack
position_effect_stack = sp.layerstack.InsertPosition.inside_node(
    my_fill_layer, sp.layerstack.NodeStack.Content)

my_fill_effect = sp.layerstack.insert_fill(position_effect_stack)
my_fill_effect.set_name("My Fill Effect")

# Insert Fill effect into the "my_fill_layer"'s mask effects stack
if not my_fill_layer.has_mask():  # If Layer has no Mask, create it
    mask_background = sp.layerstack.MaskBackground.White  # Create Background Color for the mask
    my_fill_layer.add_mask(mask_background)  # Add a mask to the Fill Layer
position_mask_effect_stack = sp.layerstack.InsertPosition.inside_node(
    my_fill_layer, sp.layerstack.NodeStack.Mask)

my_mask_fill_effect = sp.layerstack.insert_fill(position_mask_effect_stack)
my_mask_fill_effect.set_name("My Mask Fill Effect")

# We can notice, in the lines above, that the same 'insert_fill()' method
# is called to create either a Fill Layer, a Fill Effect or a mask fill effect.
# Paint Layers insertion will work the same using 'insert_paint()'

# Insert a Blur Filter Effect in "my_fill_layer" stack
filter_resource = sp.resource.search("s:starterassets "
                                     "u:filter "
                                     "n:Blur=")[0]
sp.layerstack.insert_filter_effect(position_effect_stack, filter_resource.identifier())

# Insert a Smart Material from the library into "My Group"
# Get the first Smart Material named 'Bronze Armor' in the starter asset library
smart_mat_resource = sp.resource.search("s:starterassets "
                                        "u:smartmaterial "
                                        "n:Bronze\\ Armor=")[0]
# Insert smart material in the group and connect a resource found into the library
sp.layerstack.insert_smart_material(position_group_content, smart_mat_resource.identifier())

Insertion

Insertion of a layer or an effect can be done by using one of the following functions.
For more details, see Layers and effects.

class substance_painter.layerstack.InsertPosition(node_id: int, node_stack: int | None) substance_painter.layerstack.InsertPosition

InsertPosition is the object used by all the insert methods to express
where you want the insertion to happen in the layer stack hierarchy.

Create instances using the appropriate static methods depending on what
you want to do. See the following examples.

Example

import substance_painter as sp

# Insert at the top of the given textureset layer stack
insert_position = sp.layerstack.InsertPosition.from_textureset_stack(
    sp.textureset.get_active_stack())
new_layer = sp.layerstack.insert_fill(insert_position)
new_layer.set_name("First layer")

# Insert a layer above new_layer
insert_position = sp.layerstack.InsertPosition.above_node(new_layer)
sp.layerstack.insert_fill(insert_position)

# Insert an effect in the content stack of new_layer
insert_position = sp.layerstack.InsertPosition.inside_node(
    new_layer, sp.layerstack.NodeStack.Content)
new_effect = sp.layerstack.insert_fill(insert_position)
new_effect.set_name("First effect")

# Insert an effect below new_effect
insert_position = sp.layerstack.InsertPosition.below_node(new_effect)
sp.layerstack.insert_fill(insert_position)

Parameters:

  • node_id (int)
  • node_stack (int | None)

static from_textureset_stack(stack: Stack) -> InsertPosition substance_painter.layerstack.InsertPosition.from_textureset_stack

Generate an InsertPosition on the top of a stack.

Only a LayerNode can be inserted at the top of the stack.
For more details, see Insertion rules when node is a LayerNode.

Pararm stack: Stack in which you wish to insert.

Parameters: stack (Stack)

Return type: InsertPosition

static above_node(node: Node) -> InsertPosition substance_painter.layerstack.InsertPosition.above_node

Generate an InsertPosition to insert above the given node.

Only a LayerNode can be inserted above a LayerNode.
Only an EffectNode can be inserted above an EffectNode.
For more details, see Insertion rules when node is a LayerNode and Insertion rules when node is an EffectNode.

Parameters: node (Node) – the node.

Return type: InsertPosition

static below_node(node: Node) -> InsertPosition substance_painter.layerstack.InsertPosition.below_node

Generate an InsertPosition to insert below the given node.

Only a LayerNode can be inserted above a LayerNode.
Only an EffectNode can be inserted above an EffectNode.
For more details, see Insertion rules when node is a LayerNode and Insertion rules when node is an EffectNode.

Parameters: node (Node) – the node.

Return type: InsertPosition

static inside_node(node: Node, node_stack: NodeStack) -> InsertPosition substance_painter.layerstack.InsertPosition.inside_node

Generate an InsertPosition to insert inside the given stack of a node.

Only a LayerNode can be inserted inside a GroupLayerNode if node_stack
is NodeStack.Substack.
Only an EffectNode can be inserted inside a LayerNode if node_stack
is NodeStack.Content or NodeStack.Mask.
For more details, see Insertion rules when node is a LayerNode and Insertion rules when node is an EffectNode.

Parameters:

  • node (Node) – the node.
  • node_stack (NodeStack) – indicate in which layer’s stack you want
    to insert (Only valid for nodes which are layers).

Return type: InsertPosition

Insertion rules when node is a LayerNode

Node type
From textureset stack Above node Below node Inside node (Substack)
Inside node (Content)
Inside node (Mask)
Paint
x
x
x
Fill
x
x
x
Generator
x
x
Filter
x
x
Levels
x
x
Compare Mask
x
Color Selection
x
Group
x
Anchor Point
x
x
Smart Mask
x
Smart Material
x
Instance
x

Insertion rules when node is an EffectNode

Node type
From textureset stack Inside node
Node in Content stack: Above node Below node
Node in Mask stack: Above node Below node
Paint
x
x
Fill
x
x
Generator
x
x
Filter
x
x
Levels
x
x
Compare Mask
x
Color Selection
x
Group
Anchor Point
x
x
Smart Mask
x
Smart Material
Instance

class substance_painter.layerstack.ScopedModification(name) substance_painter.layerstack.ScopedModification

ScopedModification can be used to group many layerstack modification calls
in a single undoable command.

name will be displayed in the software history.

  • The computation will only happen when we leave the with statement
    meaning that we don’t waste time computing intermedietary result that we
    don’t need.

This object is a context manager usable with the python with statement

Example

import substance_painter as sp

def insert_many_fills():
    # Insert many layers inside the current texture set layer stack
    # and set their projection mode to tri-planar
    insert_position = sp.layerstack.InsertPosition.from_textureset_stack(
        sp.textureset.get_active_stack())
    fill = sp.layerstack.insert_fill(insert_position)
    fill.set_projection_mode(sp.layerstack.ProjectionMode.Triplanar)
    fill = sp.layerstack.insert_fill(insert_position)
    fill.set_projection_mode(sp.layerstack.ProjectionMode.Triplanar)
    fill = sp.layerstack.insert_fill(insert_position)
    fill.set_projection_mode(sp.layerstack.ProjectionMode.Triplanar)

# Calling this method will generate many history entries (1 for each
# inserted fill and 1 for each projection mode update) and
# Substance Painter will compute the textures each time a modification
# happens.
#
# Expected history:
#   * Add fill
#   * Update projection mode
#   * Add fill
#   * Update projection mode
#   * Add fill
#   * Update projection mode
#
# Potential texture update in the viewport: 6 (one for each modification)
insert_many_fills()

# With the ScopedModification below, only one entry will be added to Painter
# history. A single undo will remove all the fill inserted inside the

# Calling this method inside a ScopedModification will only generate one history
# entry and Substance Painter will compute the textures only once.
#
# Expected history:
#   * Insert many layers
#
# Potential texture update in the viewport: 1
with sp.layerstack.ScopedModification("Insert many layers"):
    insert_many_fills()

class substance_painter.layerstack.NodeStack(value) substance_painter.layerstack.NodeStack

Indicate which node stack you want to insert in.

Members:

Name
Description
Substack
Insert in the substack of a node (only valid for a Folder node).
Content
Insert in the content stack of the node.
Mask
Insert in the mask stack of the node.
NOTE
The name used to define members is available as a string via the .name attribute (see python enum.Enum).

Deletion

substance_painter.layerstack.delete_node(node: Node) substance_painter.layerstack.delete_node

Delete the given node.

Parameters: node (Node) – Node to delete.

recommendation-more-help
substance-3d-dev-help-painter-python-guide