Cap All Holes & Inset NGones

Hey there!

 

Here I have two useful ICE-compounds I use quite often. The fist one caps all holes in a Mesh.

cp_and_insng_01

 

 

 

 

 

 

 

 

 

 

 

 

Picture 1: A polymesh with many Holes.

 

cp_and_insng_02

 

 

 

 

 

 

 

 

 

 

 

 

Picture 2: The compound caps all holes on a mesh.

 

ab_cap_hole

 

 

 

Download the compound: AB _ Cap All Holes


 

The second compound checks a polygon mesh for NGones and insets this ones.
cp_and_insng_03

 

 

 

 

 

 

 

 

 

 

 

picture 3: The insert_NGones compound Inserts all polygones with more than 4 points.

 

This compound gets useful when working e.g. with the “Create Extrusion Along Strands” compound.  After doing the extrusion with this compound along stands the top and bottom cap are not-smoothable ngones. When using a Inset-NGones compound after the extrusion, the meshes get flat caps when smoothing them.

Picture 5: Example of use

 

ab_inset_ngone

 

 

 

 

 

 

Download the Compound: AB _ Inset nGons

4Point Surface Constraint in ICE

When rigging swimming or flowting things it’s not the best idea to put the hole object under one null and to rotate that. A better idea is to make a linear surface grid with four points, cluster constrain the four points to nulls and create a fifth null which is surface constrained to the middle of the surface.

As shown in the fist picture, the null moves/rotates nicely between the four control points. The principle is not new. There is also an Rigging solver of Studio Nest out there that does exact this.

Point Surface This solver computes a transform on a iso surface build by 2D bezier curves. These curves are defined by 4 controllers (the corners of the iso surface). 

article: Sixbirds Rigging Solvers
backup: search for “Brigks”

When thinking of this case I asked myself how I would realize this within ICE without a real surface. I came up with a small graph that I try to explain.

4 point surface - picture 2

First of all we need the global positions of the four nulls.

4 point surface - picture 4

With that done we drop two “Bezier 4″ nodes in. For thous of you who don’t know what the node is doing, read this Article on Wikipedia, and/or watch the video-tutorial of Bradley Gabe on Vimeo. That will clarify what this node is doing. Plugin in the Vectors as shown below. The order depents on position of the control nulls.

4 point surface - picture 4

Next we need two “Scalar” nodes for the U and V coordinate, two “Clamp” nodes and one “Linear Interpolate” node. Connect the output of the “Bezier 4″ nodes to the inputs of the “Linear Interpolate” node. Then connect each “Scalar” node to one “Clamp” node and set the clamp-range from 0-1. With this way we make sure that the range is always right. Connect one of the “Clamp” nodes the the “Bezier 4″ nodes (this will be our V coordinate weight), and the other one to the “Linear Interpolate” node weight (this will be our U coordinate weight). Ok, that’s all for the position logic.

4 point surface - picture 5

For visualization purposes I took a “Add Point” node, pluged in in the 3d position vector and initialized the basic particle attributes. Further more I used some linear interpolation nodes to visualize the current u and v on the grid. This ones are not necessary to get the Constraint working.

4 point surface - picture 6

The result of this graph looks like this. The ICE setup aligns perfectly the traditional surface constraint.  The blue points visualize the u coordinate and the red points the v coordinate. The only thing missing here is the proper rotation.

4 point surface - picture 6

The next step is a bit tricky and not THE solution, but I found this one  working best for me. The fist step is to get the vector for the U Coordinate by subtracting and interpolating. Second step is to do the same for the V  Coordinate. With that working we can calculate the third vector we are after with the “Cross Product” node.  For more information about that look at the Wikipedia article. By putting this three vectors in an  “3D Vector to 3×3 Matrix” node we can get an approximation of the rotation. Just resplit the Matrix back to SRT and plug the rotation in the  Particle Orientation Port.

4 point surface - picture 8

As shown below, the result lines up nicely to the traditional surface constraint.

4 point surface - picture 9

In some extreme cases, there are problems with the rotation. But for simple setups, this ICE graph could be an solution. Also it’s possible to drive Objects via ICE Kinematics with this method. I hope you like this small tutorial.

4 point surface - picture 10

Download the Compound: AB _ 4 Point Surface Constraint

Thanks!

Add Closest Surface Constraint

This one is quite Interesting I think. During the Anomalia rigging workshop in Litomyšl (Czech Republic) the instructor Josh Carey from ReelFX has constantly used follicle constraints for all kinds of rigging topics. In Softimage language a follicle constraint is just a simple surface constraint. But that was not what I found interesting. I liked the way Josh was creating the constraints. He had a small script that searched the closest location from locator, read the u and v coordinates of the location and appled a surface constraint with exact this coordinates. With this technique it is quite easy, to get the controllers exact to the point where I want them. In the case of surface constraints, it is not always as easy as you think.

To visualize that, I have rebuild a simple ICE tree that shows exact what my piece of code does.

add closest surface constraint 01

As shown in this picture, I need just four nodes to get the information I want. First: The surface mesh. Second: The global position of the null. Third: A get closest location node. Fourth: a get data node where I select the 2D vector with the UV coordinates.

Ok, that’s clear. Lets port that to python.

from win32com.client import constants as c
xsi = Application
log = Application.LogMessage
collSel = xsi.Selection

def addClosestSurfaceConstraint(inMesh, inObj, inDoParent):
	if inMesh.type == "surfmsh":
		selSurface = inMesh.ActivePrimitive.Geometry
		selObj = inObj
		selObjParent = inObj.Parent.Name
		log(selObjParent)
		CubePositionArray = selObj.Kinematics.Global.Transform.GetTranslationValues2()
		CubeOnSpherePointLocators = selSurface.GetClosestLocations(CubePositionArray)
		PtLocSubSurf = selSurface.GetSubSurfaceIndexArray(CubeOnSpherePointLocators,)
		PtLocUVs = selSurface.GetNormalizedUVArray(CubeOnSpherePointLocators,)
		#Debugging
		#log("Point locator is on subsurface " + str(PtLocSubSurf[0]) + " at {U = " + str(PtLocUVs[0]) + " , V = " + str(PtLocUVs[1]) + "}.")
		constrNull = xsi.GetPrim("Null", inObj.Name + "_SFC", "", "")
		if selObjParent != "Scene_Root":		
			xsi.ParentObj(selObjParent, constrNull.FullName)
		xsi.ApplyCns("Surface", constrNull.FullName, inMesh.FullName, "")
		xsi.SetValue(constrNull.FullName + ".kine.surfcns.posu", PtLocUVs[0], "")
		xsi.SetValue(constrNull.FullName + ".kine.surfcns.posv", PtLocUVs[1], "")
		xsi.SetValue(constrNull.FullName + ".kine.surfcns.tangent", True, "")
		xsi.SetValue(constrNull.FullName + ".kine.surfcns.upvct_active", True, "")
		if inDoParent == True:
			xsi.ParentObj("B:" + str(constrNull.FullName), inObj.FullName)
	else:
		log("debug: 1.Select a Surface Mesh, 2. Select any Object Type")

	return True

addClosestSurfaceConstraint(collSel(0),collSel(1),True)

When running this I get this result

closest_surfaceconstraint_02add closest surface constraint 01

As you could see, it has set the surface constraint to the position that I had calculated in my ICE prototype previously. there is little difference in the values, but that’s the fourth spot after the point. For me the tricky part in this script was, to find the function GetNormalizedUVArray, because all other functions give back not normalized values(0-1) that are needed for the surface constraint.

Usage: The fuction takes three arguments.
1. inMesh – Surface the Null will be constraint to.
2. inObj – Object from witch global position the closest Point on Surface will be calculated.
3. inDoParent – parent boolean – If true, the Input Object is parented to the new Null. Otherwise, this will be ignored.

Create controls in bounding box

Frequently I’m using the “Create Cluster with Center” command to create control objects. After a while I found myself tagging components and running this command, just to get a null in the bounding box center. What’s annoying about that is, it creates also the “cluster center” operator and an cluster on the mesh. Unfortunately this is not my original intention. I just want centered nulls for rigging.

So I made small python function that reads the bounding box information of the tagged components (points, edges or polygons) creates a reset-null plus a control-null and set them to the coordinates of the bounding box.

This makes it super fast to create controls – for example in the middle of lips.

from win32com.client import constants as c
xsi = Application
log = Application.LogMessage
collSel = xsi.Selection

# Find the BBox Center and Create an Ctrl Object
def createCtrlInBBox():
	oSelChecker = False
	if collSel(0):
		#Get Selection Center
		list = xsi.GetValue( "SelectionList" )
		#Set Checker for reselection
		oSelChecker = True
		#Get BBox of the Selection
		oBB = xsi.GetBBox(list, False)
		#Get Coordiates
		xmin = oBB.Value( "LowerBoundX" )
		ymin = oBB.Value( "LowerBoundY" )
		zmin = oBB.Value( "LowerBoundZ" )
		xmax = oBB.Value( "UpperBoundX" )
		ymax = oBB.Value( "UpperBoundY" )
		zmax = oBB.Value( "UpperBoundZ" )
		#Calculate the center postion
		xcenter = (xmax + xmin) / 2
		ycenter = (ymax + ymin) / 2
		zcenter = (zmax + zmin) / 2
	else:
		#Set Coordiates
		xcenter = 0
		ycenter = 0
		zcenter = 0
	#UserFeedback
	log("debug: world center of selection: x:" + str(xcenter) + " y: " + str(y  center) + " z: " + str(zcenter))
	#Tansform Grp & CtrlObj	
	xsi.DeselectAll()
	oTransGrp = xsi.GetPrim("Null", "CenterPNT_REST_1","")
	oCtrlNull = xsi.GetPrim("Null", "CenterPnt_CON_1", "", "")
	xsi.CopyPaste(oCtrlNull, "", oTransGrp, 1)
	#Look
	xsi.SetValue(str(oTransGrp.Name) + ".null.primary_icon", 1, "")
	xsi.SetValue(str(oCtrlNull.Name) + ".null.primary_icon", 0, "")
	xsi.SetValue(str(oCtrlNull.Name) + ".null.shadow_icon", 2, "")
	xsi.SetValue(str(oCtrlNull.Name) + ".null.shadow_colour_custom", True, "")
	xsi.SetValue(str(oCtrlNull.Name) + ".null.R", 0.998, "")
	xsi.SetValue(str(oCtrlNull.Name) + ".null.G", 1, "")
	xsi.SetValue(str(oCtrlNull.Name) + ".null.B", 0, "")
	#Translate
	xsi.SetValue(str(oTransGrp.Name) + ".kine.local.posx", xcenter, "")
	xsi.SetValue(str(oTransGrp.Name) + ".kine.local.posy", ycenter, "")
	xsi.SetValue(str(oTransGrp.Name) + ".kine.local.posz", zcenter, "")
	#RestoreSelection if available
	if oSelChecker == True:
		xsi.SelectObj(list, "", True)

createCtrlInBBox()

Deinstance PointClouds

When distributing object-instances across the scene, it’s most oft the time, the fastest way to do this within the ice framework of Softimage. The problem comes across if the director want’s to move objects manually. There are may solutions for that. In our last project, the most effective and time efficient way was to deinstance the pointcloud and to move the objects by hand.

I have programmed a small function in Python, that makes instances of models, clones of objects and new primitives plus clones from ice primitives.

Usage:
* Just select a pointcloud and run the script.

Known Issues:
* It’s getting slow with >250 particle Instances.
* When there is no per-point rotation data is set, the script will crash. Workaround: Set a particle orientation during the emission. For example with the “randomize rotation by cone” node.

Deinstance Pointcloud 2

from win32com.client import constants as c
xsi = Application
log = Application.LogMessage
collSel = xsi.Selection

def deinstancePointCloud():
	if collSel(0).Type == "pointcloud":
		#Turn Off Logging
		xsi.SetValue("preferences.scripting.cmdlog", False, "")

		pointShape=collSel[0].ActivePrimitive.GetICEAttributeFromName("Shape")
		pointPosition=collSel[0].ActivePrimitive.GetICEAttributeFromName("PointPosition")
		pointOrientation=collSel[0].ActivePrimitive.GetICEAttributeFromName("Orientation")
		pointSize=collSel[0].ActivePrimitive.GetICEAttributeFromName("Size")
		pointScale=collSel[0].ActivePrimitive.GetICEAttributeFromName("Scale")


		#Get Shape Type (0-9 Ice Shapes, 129 RealObj)
		InstanceType = pointShape.DataArray[0].Type
		log(pointShape.DataArray[0].Type)
		
		#Progessbar
		oProgressBar = XSIUIToolkit.ProgressBar 
		oProgressBar.Maximum = pointShape.ElementCount 
		oProgressBar.Step = 1
		oProgressBar.Caption = "Creating Instances/Clones"
		oProgressBar.CancelEnabled = True 
		oProgressBar.Visible = True

		#Loop through all elements
		for oElements in range(0,pointShape.ElementCount):
			#Check if the shape is one of the defaults:  Point, Box, Sphere...
			if InstanceType > 9:
				if oProgressBar.CancelPressed != True:
					objectID=pointShape.DataArray[oElements].ReferenceID
					instance=xsi.GetObjectFromID(objectID)
					ppos = pointPosition.DataArray[oElements]
					prot = pointOrientation.DataArray[oElements]
					psize = pointSize.DataArray[oElements]
					pscl = pointScale.DataArray[oElements]					
					if str(instance.Type) == "polymsh":
						currInst = xsi.Clone(str(instance), "", 1, 0, 0, 0, 1, 0, 1, "", "", "", "", "", "", "", "", "", "")
					if "model" in str(instance.Type):
						currInst = xsi.Instantiate(str(instance), "", 1, 1, 0, 1, "", "", "", "", "", "", "", "", "", "")
					xsi.Translate(str(currInst), ppos.X, ppos.Y, ppos.Z, "siAbsolute", "siPivot", "siObj", "siXYZ", "", "", "", "", "", "", "", "", "", 0, "")
					xsi.Rotate(str(currInst), prot.RotX, prot.RotY, prot.RotZ, "siAbsolute", "siPivot", "siObj", "siXYZ", "", "", "", "", "", "", "", 0, "")
					xsi.Scale(str(currInst), (pscl.X * psize), (pscl.Y * psize), (pscl.Z * psize), "siAbsolute", "siPivot", "siObj", "siXYZ", "", "", "", "", "", "", "", 0, "")
					log(oProgressBar.Value)
					oProgressBar.Increment()
				else:
					#Turn On Logging
					xsi.SetValue("preferences.scripting.cmdlog", True, "")
					break
			else:
				if oProgressBar.CancelPressed != True:
					#Check if the Instances are Points, Segments or Blobs
					if int(InstanceType) == 0:
						pass
					elif int(InstanceType) == 1:
						pass
					elif int(InstanceType) == 9:
						pass
					else:
						#Create a Master Disc
						if int(InstanceType) == 2:
							if oElements == 0:
								instance = xsi.CreatePrim("Disc", "MeshSurface", str(collSel[0].Name) + "_Master", "")
								xsi.SetValue(instance.Name + ".disc.innerradius", 0.01, "")
								xsi.SetValue(instance.Name + ".disc.outerradius", 1, "")
								xsi.SetValue(instance.Name + ".polymsh.geom.subdivv", 3, "")
						#Create a Master Disc
						if int(InstanceType) == 3:
							if oElements == 0:
								instance = xsi.CreatePrim("Grid", "MeshSurface", str(collSel[0].Name) + "_Master", "")
								xsi.SetValue(instance.Name + ".grid.ulength", 2, "")
								xsi.SetValue(instance.Name + ".grid.vlength", 2, "")
								xsi.SetValue(instance.Name + ".polymsh.geom.subdivu", 1, "")	
								xsi.SetValue(instance.Name + ".polymsh.geom.subdivv", 1, "")						
						#Create a Master Sphere
						if int(InstanceType) == 4:
							if oElements == 0:
								instance = xsi.CreatePrim("Sphere", "MeshSurface", str(collSel[0].Name) + "_Master", "")
								xsi.SetValue(instance.Name + ".sphere.radius", 1, "")
						#Create a Master Cube
						if int(InstanceType) == 5:
							if oElements == 0:
								instance = xsi.CreatePrim("Cube", "MeshSurface", str(collSel[0].Name) + "_Master", "")
								xsi.SetValue(instance.Name + ".cube.length", 2, "")
						#Create a Master Cylinder
						if int(InstanceType) == 6:
							if oElements == 0:
								instance = xsi.CreatePrim("Cylinder", "MeshSurface", str(collSel[0].Name) + "_Master", "")
								xsi.SetValue(instance.Name + ".cylinder.height", 2, "")
								xsi.SetValue(instance.Name + ".cylinder.radius", 1, "")
						#Create a Master Sphere
						if int(InstanceType) == 7:
							if oElements == 0:
								instance = xsi.CreatePrim("Sphere", "MeshSurface", str(collSel[0].Name) + "_Master", "")
								xsi.SetValue(instance.Name + ".sphere.radius", 1, "")
						#Create a Master Cone
						if int(InstanceType) == 8:
							if oElements == 0:
								instance = xsi.CreatePrim("Cone", "MeshSurface", str(collSel[0].Name) + "_Master", "")
								xsi.SetValue(instance.Name + ".cone.height", 2, "")
								xsi.SetValue(instance.Name + ".cone.radius", 1, "")
								xsi.SelectObj(instance, "", "")
								xsi.ActivateVertexSelTool("")
								xsi.SelectAllUsingFilter("Vertex", "siCheckComponentVisibility", "", "")
								xsi.Translate("", 0, -0.2917, 0, "siRelative", "siView", "siObj", "siY", "", "", "", "", "", "", "", "", "", 0, "")
								xsi.ActivateObjectSelTool("")
								xsi.ActivateObjectSelTool("")
								xsi.DeselectAll()
						ppos = pointPosition.DataArray[oElements]
						prot = pointOrientation.DataArray[oElements]
						psize = pointSize.DataArray[oElements]
						pscl = pointScale.DataArray[oElements]						
						currInst = xsi.Clone(str(instance), "", 1, 0, 0, 0, 1, 0, 1, "", "", "", "", "", "", "", "", "", "")
						xsi.Translate(str(currInst), ppos.X, ppos.Y, ppos.Z, "siAbsolute", "siPivot", "siObj", "siXYZ", "", "", "", "", "", "", "", "", "", 0, "")
						xsi.Rotate(str(currInst), prot.RotX, prot.RotY, prot.RotZ, "siAbsolute", "siPivot", "siObj", "siXYZ", "", "", "", "", "", "", "", 0, "")
						xsi.Scale(str(currInst), (pscl.X * psize), (pscl.Y * psize), (pscl.Z * psize), "siAbsolute", "siPivot", "siObj", "siXYZ", "", "", "", "", "", "", "", 0, "")
						tempName = str(currInst)
						tempName = tempName.replace("Master", "Instance")				
						xsi.SetValue(str(currInst) + ".Name", str(tempName), "")
						log(oProgressBar.Value)
						oProgressBar.Increment()
				else:
					#Turn On Logging
					xsi.SetValue("preferences.scripting.cmdlog", True, "")
					break

		#Turn On Logging
		xsi.SetValue("preferences.scripting.cmdlog", True, "")

deinstancePointCloud()

Select every Nth Component

When modeling things, it’s often needed to select every Nth Component. To make this selections more easy, I have made a temporary PPG that helps you to deselect components.

The PPG has two parameters (start and pattern) and two options (restore selection and apply new selection).

Parameter – Start: Defines the start component
Parameter – Pattern: Defines the the numbers of unselected components – 1. An example: if pattern is set to 4 every fourth component will be selected.

Option – Restore Selection: Restores the start-selection
Option – Apply New Selection: Applies the new selection with the chosen parameters

Usage:
1. Save the script somewhere.
2. Change this line to the file location:”oPPGLayout.SetAttribute(c.siUILogicFile, “\\\\Server\\Scripts\\select_components.py”)”
3. Select one object, tag some components:”Points, Edges, Polygons” and run the script

from win32com.client import constants as c
xsi = Application
log = Application.LogMessage
collSel = xsi.Selection

def selectEveryNth_createPSet(oInObjName, oInComponents, oTypecheck):
	oPSet = XSIFactory.CreateObject("CustomProperty")
	oPSet.Name = "AB_SelectEveryNthComponent"
	oPSet.AddParameter3( "Start", c.siInt4, 0)
	oPSet.AddParameter3( "Pattern", c.siInt4, 2)
	oPSet.AddParameter3( "oObjName", c.siString, str(oInObjName))	
	oPSet.AddParameter3( "oInSelection", c.siString, str(oInComponents))	
	oPSet.AddParameter3( "oTypeCheck", c.siString, str(oTypecheck))	
	return oPSet	

def selectEveryNth_createLayout(oPSet):
	oPPGLayout = oPSet.PPGLayout
	oPPGLayout.AddGroup( "Start/Pattern" ) 
	oPPGLayout.AddItem( "Start", "", "" )
	oPPGLayout.AddItem( "Pattern", "", "" )
	oPPGLayout.EndGroup() 
	
	oPPGLayout.AddGroup( "Selection" )
	oPPGLayout.AddRow() 
	oPPGLayout.AddButton( "ButtonRestore", "Restore Selection" )
	oPPGLayout.AddButton( "ButtonSelectNew", "Apply New Selection" )
	oPPGLayout.EndRow() 
	oPPGLayout.EndGroup()
	oPPGLayout.Language="Python"
	oPPGLayout.SetAttribute(c.siUILogicFile, "\\\\Server\\Scripts\\select_components.py")
	return True
	
def selectEveryNth_Execute(inSelection):
	oMyComponentSel = []
	oTypeCheck = 0
	if inSelection.Count > 0:
		log('debug: Ok, you have selected something')
		if inSelection.Count == 1:
			log('debug: right, one object selected')
			if inSelection(0).Type == 'polySubComponent':
				oTypeCheck = 1
			elif inSelection(0).Type == 'pntSubComponent':
				log('debug: pntSubComponent')
				log(inSelection(0).SubElements2)
				oTypeCheck = 2
			elif inSelection(0).Type == 'edgeSubComponent':
				oTypeCheck = 3
			else:
				log('debug: please select some components')
			if oTypeCheck != 0:
				oParent = inSelection[0].SubComponent.Parent.Parent.Parent.FullName
				oParentSplit = oParent.split(".",1)
				if oParent[0] != "Scene_Root":
					log(oParent)
					oPSet = selectEveryNth_createPSet(str(oParent), inSelection(0).SubElements2,oTypeCheck )										
				else:
					log(oParent)
					oPSet = selectEveryNth_createPSet(str(inSelection[0].Name), inSelection(0).SubElements2,oTypeCheck )					
				selectEveryNth_createLayout(oPSet)
				xsi.InspectObj( oPSet, "", "", c.siLock, False )

		else:
			log('debug: please select just one object')
	else:
		log(' debug: please select something')
	return True
	
def selectEveryNth_selectNew():
	if 'PPG' in globals():
		oPattern = xsi.GetValue(str(PPG.InspectedObjects)+".Pattern")
		oStart = xsi.GetValue(str(PPG.InspectedObjects)+".Start")
		oObjName = xsi.GetValue(str(PPG.InspectedObjects)+".oObjName")
		oInSelection = xsi.GetValue(str(PPG.InspectedObjects)+".oInSelection")
		oTypeCheck = xsi.GetValue(str(PPG.InspectedObjects)+".oTypeCheck")
	xsi.DeselectAll()
	xsi.SelectObj(oObjName, "", True)
	oMyComponentSel = str(oInSelection).replace(')','')
	oMyComponentSel = oMyComponentSel.replace('(','')
	oMyComponentSel = oMyComponentSel.split(',')
	oNewComponentSel = oMyComponentSel[int(oStart)::int(oPattern)]
	oNewComponentSelStr = str(oNewComponentSel).replace(']','')
	oNewComponentSelStr = oNewComponentSelStr.replace('[','')	
	oNewComponentSelStr = oNewComponentSelStr.replace("'",'')	
	if int(oTypeCheck) == 1:
		xsi.SetSelFilter("Polygon")
		xsi.SelectGeometryComponents(str(oObjName) + '.poly[' + oNewComponentSelStr + ']')
	elif int(oTypeCheck) == 2:
		xsi.SetSelFilter("Vertex")
		xsi.SelectGeometryComponents(str(oObjName) + '.pnt[' + oNewComponentSelStr + ']')
	elif int(oTypeCheck) == 3:
		xsi.SetSelFilter("Edge")
		xsi.SelectGeometryComponents(str(oObjName) + '.edge[' + oNewComponentSelStr + ']')

def selectionRestore_selectNew():
	if 'PPG' in globals():
		oPattern = xsi.GetValue(str(PPG.InspectedObjects)+".Pattern")
		oStart = xsi.GetValue(str(PPG.InspectedObjects)+".Start")
		oObjName = xsi.GetValue(str(PPG.InspectedObjects)+".oObjName")
		oInSelection = xsi.GetValue(str(PPG.InspectedObjects)+".oInSelection")
		oTypeCheck = xsi.GetValue(str(PPG.InspectedObjects)+".oTypeCheck")
	xsi.DeselectAll()
	xsi.SelectObj(oObjName, "", True)
	oMyComponentSel = str(oInSelection).replace(')','')
	oMyComponentSel = oMyComponentSel.replace('(','')
	if int(oTypeCheck) == 1:
		xsi.SetSelFilter("Polygon")
		xsi.SelectGeometryComponents(str(oObjName) + '.poly[' + oMyComponentSel + ']')
	elif int(oTypeCheck) == 2:
		xsi.SetSelFilter("Vertex")
		xsi.SelectGeometryComponents(str(oObjName) + '.pnt[' + oMyComponentSel + ']')
	elif int(oTypeCheck) == 3:
		xsi.SetSelFilter("Edge")
		xsi.SelectGeometryComponents(str(oObjName) + '.edge[' + oMyComponentSel + ']')

def ButtonRestore_OnClicked():
	Application.LogMessage("Restore Selection")
	selectionRestore_selectNew()

def ButtonSelectNew_OnClicked():
	Application.LogMessage("Apply New Selection")
	selectEveryNth_selectNew()
	
selectEveryNth_Execute(collSel)

Find all relevant FCurve information

Some days ago, I had an interesting problem. I needed to find all relevant FCurve information (keys+bézier-points). Here is a example that finds all keys, bézier-tangent-information and the keytypes for the TranslateX Axis of the selected object. Quite cool is, that it gives the exact time and value for the tangents – what disciples the fcurve the best way. It also works with related values.

from win32com.client import constants as c
xsi = Application
log = Application.LogMessage

# Convenience function to get the user-friendly string describing the contraint type
def GetConstraintType( in_fcrvkey ) :
        ConstraintTypes = {
                c.siParameterConstraint:"LockParameter", 
                c.siLeftRightValuesConstraint:"LeftRightParameter", 
                c.siG1ContinuousConstraint:"G1Continuous", 
                c.siLeftRightTangentDirectionConstraint:"LeftRightTangentDirection", 
                c.siLeftRightTangentLengthConstraint:"LeftRightTangentLength", 
                c.siLockConstraint:"LockAll", 
                c.siHorizontalTangentConstraint:"HorizontalTangent", 
                c.siExtremumHorizontalTangentConstraint:"ExtremumHorizontalTangent", 
                c.siAdjustedTangentConstraint:"AdjustedTangent", 
                c.siZeroLengthTangentConstraint:"ZeroLengthTangent", 
                c.siSameLengthTangentConstraint:"SameLengthTangent",
                c.siNeighborTangentConstraint:"NeighborTangent",
                c.siMirrorTangentConstraint:"MirrorTangent",
                c.siAutoPlateauTangentConstraint:"AutoPlateauTangent"
        }
        str = ""
        for k in ConstraintTypes.keys() :
                if ( in_fcrvkey.Constraint(k) ) :
                        str += ConstraintTypes[k] + " "
        return str

# Convenience function to print the FCurveKeys
def PrintKeys( in_fcrv ) :
        for fckey in in_fcrv.Keys :
				log("------------------------------------------------------")
				log("key\t\t:\t" + str(fckey.Index))
				log("frame\t\t:\t" + str(fckey.Time))
				log("value\t\t:\t" + str(fckey.Value))		
				log("tangents:\t\t" + str(fckey.LeftTanX) + " | " + str(fckey.LeftTanY) +  " | " + str(fckey.RightTanX) + " | " + str(fckey.RightTanY))	
				log("constraints\t:\t" + str(GetConstraintType( fckey )))		
        return None

fc = xsi.Selection[0].posx.Source

if fc:
	if fc.type == "Expression":
		fc_Expression = fc.Parameters[4].Source
		log(fc_Expression.Keys.Count	)
		PrintKeys( fc_Expression )
	else:
		log(fc.Keys.Count)
		PrintKeys( fc )
else:
	log("No Key!")

Welcome!

Hey, this is my fist entry. I hope I can stay posting interesting articles about my work. Stay tuned. I’m looking forward to your comments.