Here’s a question that came up on si-community awhile ago. How do I copy vertex attributes to the corresponding polygons?
This answer is the companion to this polygon-to-vertices post. I basically do the same thing, but in the opposite direction.
Here’s a question that came up on si-community awhile ago. How do I copy vertex attributes to the corresponding polygons?
This answer is the companion to this polygon-to-vertices post. I basically do the same thing, but in the opposite direction.
Because of how ICE is optimized, it won’t bother setting data if you never use that data (see Beware of ICE Optimizations here). For example, suppose I have a point cloud where I set a per-point scalar value, but I never use that scalar data (because I just want to cache that value and use it later).
That scalar attribute is never used, so it is optimized away (it makes sense: you’re not using it, so why keep it?). You won’t see that attribute in the Cache Manager, and the Cache on File node won’t write it out (even if you add that attribute to the list).
One way to force ICE to evaluate the attribute so you can cache it is to create an Attribute Display property for the attribute, but disable Show Values.
Another way is to insert a Log Values node, and disable logging.
Yet another way is to use Show Values. Enable Show Values for Tagged Components Only to hide the values (if you’re going to tag components, you could set the Display % to 1).
And last but not least, if you have emTools from Mootzoid, you can use the Force Value Evaluation node, which uses a Show Values on a value that is never set.
hat tips to Stefano, Mathieu, and Vincent on the SItoA list
On the Read tab of the Cache Manager there’s a Dump Header button:
Dump Header dumps the cache header and attribute list to XML and pops up NetView:
If you want to dump the XML and parse it yourself, you can do it with this scripting command:
Application.DumpCacheHeader("[project path]\\Simulation\\scene_root\\pointcloud\\pointcloud_AnimTake1_[1..100].icecache", False)
Last time I tried this, I gave up on JScript (it seemed impossible) and got something to work in Python.
In JScript, I kept getting errors like “# WARNING : 3392 – Invalid offset specified while extracting data from this attributeĆ.
si = Application from win32com.client import constants as C # win32com.client.constants oObj = si.Selection(0) oICEAttrMats = oObj.ActivePrimitive.AddICEAttribute("MyString", C.siICENodeDataString, C.siICENodeStructureArray, C.siICENodeContextSingleton) oICEAttrMats.DataArray2D = [["a", "b", "c", "d"]] x = oICEAttrMats.DataArray2D print x print len(x) print len(x[0]) print len(x[0][0]) for d in x[0][0]: print d # (((u'a', u'b', u'c', u'd'),),) # 1 # 1 # 4 # a # b # c # d
See also this Getting DataArray2D attribute values post.
Degenerate polygons are usually zero-area polygons.
Here’s a script that uses the ICE attribute PolygonArea to find polygons with area less than a specified epsilon:
si = Application epsilon = 0.00001 # Get PolygonArea DataArray (which is a tuple) attr = si.Selection(0).ActivePrimitive.GetICEAttributeFromName( "PolygonArea" ) areaData = attr.DataArray # # Find the indices of the bad polys # bad = [ x for x,y in enumerate( areaData ) if y < epsilon] # Select the degenerates with a string like 'cube.poly[112,114,155]' si.SelectGeometryComponents( 'cube.poly[%s]' % ','.join(str(i) for i in bad) ) ### OR ### # # Get the actual Polygon objects # polys = si.Selection(0).ActivePrimitive.Geometry.Polygons bad = [] for i in range( len(areaData) ): if areaData[i] < epsilon: bad.append( polys(i) ) si.SelectObj( polys )
Here’s the Python way:
Application.SelectObj("Pedestrian_Mesh.Actor_Copies", None, None); o = Application.Selection(0) a = o.ActivePrimitive.Geometry.GetICEAttributeFromName("Materials") print len(a.DataArray2D) print len(a.DataArray2D[0] ) print a.DataArray2D[0][0] for s in a.DataArray2D[0][0]: print s # 1 # 1 # (u'', u'Sources.Materials.PedestrianLib.Shoes', u'Sources.Materials.PedestrianLib.Hair', u'Sources.Materials.PedestrianLib.Legs', u'Sources.Materials.PedestrianLib.Skin', u'Sources.Materials.PedestrianLib.Shirt') # Sources.Materials.PedestrianLib.Shoes # Sources.Materials.PedestrianLib.Hair # Sources.Materials.PedestrianLib.Legs # Sources.Materials.PedestrianLib.Skin # Sources.Materials.PedestrianLib.Shirt
And here’s how to do it in JScript:
o = Selection(0); a = o.ActivePrimitive.Geometry.GetICEAttributeFromName("Materials"); x = new VBArray( a.DataArray2D ).toArray(); y = new VBArray( x[0] ).toArray(); for ( var i = 0; i < y.length; i++ ) { LogMessage( y[i] ) }
I wanted to do this JScript, but I had to do it in Python first, to establish that it was actually possible (with JScript, you’ve got to mess around with VBarrays and such).
# Using one of the CrowdFX sample scenes: Application.SelectObj("Pedestrian_Mesh.Actor_Copies", None, None); o = Application.Selection(0) a = o.ActivePrimitive.Geometry.GetICEAttributeFromName("Materials") print len(a.DataArray2D) print len(a.DataArray2D[0] ) print a.DataArray2D[0][0] for s in a.DataArray2D[0][0]: print s # 1 # 1 # (u'', u'Sources.Materials.PedestrianLib.Shoes', u'Sources.Materials.PedestrianLib.Hair', u'Sources.Materials.PedestrianLib.Legs', u'Sources.Materials.PedestrianLib.Skin', u'Sources.Materials.PedestrianLib.Shirt') # Sources.Materials.PedestrianLib.Shoes # Sources.Materials.PedestrianLib.Hair # Sources.Materials.PedestrianLib.Legs # Sources.Materials.PedestrianLib.Skin # Sources.Materials.PedestrianLib.Shirt
After I had it working in Python, I was able to figure it out in JScript:
// Using one of the CrowdFX sample scenes: SelectObj("Pedestrian_Mesh.Actor_Copies", null, null); o = Selection(0); a = o.ActivePrimitive.Geometry.GetICEAttributeFromName("Materials"); x = new VBArray( a.DataArray2D ).toArray(); y = new VBArray( x[0] ).toArray(); for ( var i = 0; i < y.length; i++ ) { LogMessage( y[i] ); }
Now that there are intrinsic ICE attributes like NbPoints and NbPolygons, there a couple of ways you can check for an empty mesh:
# Assume a polymesh is selected... o = Application.Selection(0) # Check the intrinsic ICE attribute nb = o.ActivePrimitive.ICEAttributes("NbPoints") print nb.IsDefined and nb.DataArray[0] <= 0 # Check using the object model print o.ActivePrimitive.Geometry.Points.Count <= 0
The typical way to package this up for users it to define a filter. Then a user just has to select the filter and press CTRL+A. Here’s the Match callback for a filter that finds empty polygon meshes. Note that I switched to checking the number of polygons. That way, if somehow there was something weird like a mesh with just one point, you’d still find it.
The intrinsic attribute NbPolygons should always exist, but just to be sure I check IsDefined, and if that is False, I fall back to checking Geometry.Polygons.Count.
# Match callback for the EmptyPolygonMesh custom filter. def EmptyPolygonMesh_Match( in_ctxt ): Application.LogMessage("EmptyPolygonMesh_Match called",constants.siVerbose) o = in_ctxt.GetAttribute( 'Input' ) if o.type == 'polymsh': nb = o.ActivePrimitive.ICEAttributes("NbPolygons") return (nb.IsDefined and nb.DataArray[0] <= 0) or o.ActivePrimitive.Geometry.Polygons.Count <= 0 else: return False
I packaged the filter as an addon. Get it here.
Chris Gardner explains how to use an ICE attribute to control instancing when you send a Softimage ICE simulation over to Maya.
Some related discussions from the Softimage mailing list: