# 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 Max.
Hollow shell can also be accomplished using the AggregationPipeline by enabling GeometryCulling.
import os
from pymxs import runtime as rt
import random
from simplygon import simplygon_loader
from simplygon 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, useClippingTerrain) :
print('RunHollowShell')
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)
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():
print 'Create assets here!'
# create sphere named s0
# create plane named clipgeom that intersects the sphere
def optimize_scene(sg, intermediate_file):
scene = sg.CreateScene()
scene.LoadFromFile(intermediate_file)
# Before any specific processing starts, set global variables.
# Using 3ds Max tangent space calculation.
sg.SetGlobalDefaultTangentCalculatorTypeSetting(Simplygon.ETangentSpaceMethod_Autodesk3dsMax)
# 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, True)
scene.SaveToFile(intermediate_file)
# Reset scene and create assets
rt.resetMaxFile(rt.Name('noPrompt'))
createAssets()
# Load the scene from the Max format, export the data into simplygon format and import
# the file into a simplygon scene.
rt.select(rt.objects)
intermediate_file = os.path.dirname(__file__)+'/_export.sb'
bResult = rt.sgsdk_ExportToFile(intermediate_file, True)
# Initialize Simplygon
sg = simplygon_loader.init_simplygon()
# Optimize scene
optimize_scene(sg, intermediate_file)
# Format import string
rt.sgsdk_SetInitialLODIndex(1)
rt.sgsdk_SetMeshNameFormat('{MeshName}_LOD{LODIndex}')
# Import optimized scene
bResult = rt.sgsdk_ImportFromFile(intermediate_file)
os.remove(intermediate_file)
# De-initialize Simplygon
sg = None
gc.collect()
# Next steps
Get to know how to use the Aggregation Processor: