Skip to content
On this page

Aggregation (Hollow shell) using AggregationProcessor

This example demonstrates how to use the aggregation processor to combine objects and remove interiors using the geometry culling functionality. The selected scene gets exported to file, optimized through the AggregationProcessor, and imported back into Maya.

Hollow shell can also be accomplished using the AggregationPipeline by enabling GeometryCulling.

python
import os
import maya.cmds as cmds
import random
from simplygon10 import simplygon_loader
from simplygon10 import Simplygon
import gc

def AddToSelectionSets(sceneNode, processSet, clippingSet):
    for i in xrange(0, sceneNode.GetChildCount()):
        child = sceneNode.GetChild(i)
        if child.IsA("ISceneMesh"):

            # Add clipping geometry to the clippingSet set. Otherwise to the processing set.
            if child.GetName().startswith("clipgeom"):
                clippingSet.AddItem(child.GetNodeGUID())
            else:
                processSet.AddItem(child.GetNodeGUID())
        AddToSelectionSets(child, processSet, clippingSet)

def RunHollowShell(scene, castMaterials, useClippingTerrain) :
    print("RunHollowShell")
    print("\tcastMaterials=" + str(castMaterials))
    print("\tuseClippingTerrain=" + str(useClippingTerrain))

    aggregationProcessor = sg.CreateAggregationProcessor()
    aggregationProcessor.SetScene(scene)

    aggregatorSettings = aggregationProcessor.GetAggregationSettings()

    # This is the base setting that enables the culling of interiors.
    # All triangles on the insides of watertight meshes will be removed,
    # since they are redundant for rendering. It is possible to manipulate visibility
    # settings to get similar results from the visibility-driven triangle culling
    # functionality, but then you can't use clipping geometries or clipping planes.
    aggregatorSettings.SetEnableGeometryCulling(True)

    # This controls the precision of the culling. Higher values will be more accurate
    # while lower values will be faster. Increase if you're getting bad cracks.
    aggregatorSettings.SetGeometryCullingPrecision(0.2)

    aggregatorSettings.SetMergeGeometries(True)
    aggregatorSettings.SetMergeMaterials(castMaterials)

    if (useClippingTerrain):
        # We can use that terrain to further cull the the asset.

        # Make selection set to put processing and clipping geometry into
        clippingSet = sg.CreateSelectionSet()
        processSet = sg.CreateSelectionSet()

        # Split up the objects so that all meshes that starts with "clipgeom" is placed
        # into the clipping set. The rest of the meshes are assumed as geometry to merge and cut.
        # What is culled and what is removed is determined by the triangle winding of the
        # clipping geometry, so whatever parts of the process geometry is on the positive
        # halfspace of the clipping geometry will remain while everything else will be removed.
        # Since this is determined by triangle winding, the culling will not work if there are
        # culling geometry backfaces in the halfspace you want to remain.
        AddToSelectionSets(scene.GetRootNode(), processSet, clippingSet)
        clippingSetId = scene.GetSelectionSetTable().AddSelectionSet(clippingSet)
        processSetId = scene.GetSelectionSetTable().AddSelectionSet(processSet)

        # Setup the settings for using clipping geom
        aggregationProcessor.GetGeometryCullingSettings().SetUseClippingGeometry(True)
        aggregatorSettings.SetProcessSelectionSetID(processSetId)
        aggregationProcessor.GetGeometryCullingSettings()
            .SetClippingGeometrySelectionSetID(clippingSetId)

    # Run the process
    aggregationProcessor.RunProcessing()

    return scene

def createAssets():
    for i in range(0,40):
        name ="s"+str(i)
        cmds.polySphere(n=name, cuv=True)
        cmds.move(random.randrange(-2,2), random.randrange(0,2), random.randrange(-2,2), name)

    cmds.polyPlane(n='clipgeom', sx=10, sy=15, w=15, h=20)
    cmds.rotate(random.randrange(-20,20), random.randrange(-20,20), random.randrange(-20,20), 'clipgeom')

def optimize_scene(sg, intermediate_file):
    scene = sg.CreateScene()
    scene.LoadFromFile(intermediateFile)

    # Before any specific processing starts, set global variables.
    # Using Orthonormal method for calculating tangentspace.
    sg.SetGlobalDefaultTangentCalculatorTypeSetting(Simplygon.ETangentSpaceMethod_OrthonormalRightHanded)

    # The aggregation processor is used to combine all input meshes into
    # a single output mesh, and a terrain clipping geometry is used to
    # close the concavity at the bottom of the asset, allowing
    # more aggressive culling of inside triangles while looking identical
    # as long as it is rendered along with the clipping terrain.
    optimizedScene = RunHollowShell(scene, False, True)

    scene.SaveToFile(intermediateFile)

cmds.file(f=True, new=True)
createAssets()

# Load the scene from the maya format, export the data into simplygon format and import
# the file into a simplygon scene.
cmds.select(all=True)
intermediateFile = os.path.dirname(__file__)+'/_export.sb'
bResult = cmds.Simplygon(exp = intermediateFile , cte = True)

# Initialize Simplygon
sg = simplygon_loader.init_simplygon()

# Optimize scene
optimize_scene(sg, intermediate_file)

bResult = cmds.Simplygon(imp = intermediateFile)
os.remove(intermediateFile)

# De-initialize Simplygon
sg = None
gc.collect()

:::

Next steps

Get to know how to use the Aggregation Processor: