User Normals
You cannot interactively create User Normal properties in XSI. You either import objects with user normals, or you create the User Normal property through scripting. For example:
var oGeom = Selection(0).ActivePrimitive.Geometry; var oCls = oGeom.AddCluster( siSampledPointCluster, "User Normal" ); var oProp = oCls.AddProperty( "User Normal Property" );
You can create a user normal property under any sampled point cluster (not only "User_Normal_Cluster), and the cluster can be a partial clustes (a cluster that does not contain all sampled points).
In addition, there can be more than one user normal property under the same mesh, in which case the priority order in overlapping parts will be arbitrary (if a sampled point is in more than one User Normal property).
Some notes about User Normals (from a 2002 post (http://www.softimage.com/community/xsi/discuss/archives/xsi.archive.0211/msg00283.htm) on the XSI mailing list).
- Hard edges and geom approx autodisc settings are always overriden by UserNormals property.
- User Normals always override the XSI automatic normals, unless you delete the UserNormals property.
- UserNormals don't follow the surface deformations (they are fixed in object's local space).
An example.
'User normal demo
Newscene, false
'Create a grid, shrink wrap it to a sphere
CreatePrim "Grid", "MeshSurface"
CreatePrim "Sphere", "MeshSurface"
SetValue "sphere.sphere.radius", 6.809
SetValue "sphere.polymsh.geom.subdivu", 24
SetValue "sphere.polymsh.geom.subdivv", 24
SelectObj "grid", , True
ApplyOp "ShrinkWrap", "grid;sphere;", 3, siPersistentOperation
SetValue "grid.polymsh.shrinkwrap.rev", True
SetValue "grid.polymsh.shrinkwrap.proj", 2
SetValue "grid.polymsh.shrinkwrap.alongy", True
SetValue "grid.polymsh.shrinkwrap.ampl", -1.047
FreezeObj
DeleteObj "sphere"
SelectObj "grid", , True
Translate , 0, -6.93717227456021, 0, siRelative, siView, siObj, siXYZ
'Copy geometric normals to user normals
set obj = GetValue("grid.polymsh")
nodesarray = obj.Geometry.Nodes.NormalArray
'Create user normals on all sample points
SelectGeometryComponents "grid.sample[*]"
CreateCluster
AddProp "User Normal Property", , siDefaultPropagation
'Access prop OM object
set obj = GetValue("grid.polymsh.cls.sample.clslist.Sample.User_Normal_Property")
arr = obj.elements.array
obj.elements.array = nodesarray
'Planarize the grid
SelectObj "grid", , True
Scale , 1, 0, 1, siAbsolute, siParent, siObj, siY
Translate , 0, 8, 0, siRelative, siView, siObj, siXYZ
ResetTransform , siCtr, siSRT, siXYZ
FreezeObj
SetValue "Camera.camvis.attrselnorm", True
SetValue "Views.ViewA.TopCamera.camvis.attrselnorm", True
'Split all polygons, to show that we propagate correctly user normals
SelectGeometryComponents "grid.poly[*]"
ApplyTopoOp "SubdividePolygon", "grid.poly[*]", siUnspecified, siPersistentOperation
SelectObj "grid", , True
SetDisplayMode "Camera", "shaded"
//////////////////////////////////////////////////////////
'Script that projects subdivision surface's normals onto the hull of a mesh.
'The created normals are stored in a UserNormals property.
function ProjectSubdivNormalsOnMesh()
Set in_InputObjs = GetValue( "SelectionList" )
set l_InputObjs = SIFilter( in_InputObjs, "polygon_mesh" )
if IsEmpty(l_InputObjs) Or TypeName(l_InputObjs) = "Nothing" Then
logmessage "You need to select one or more polygon meshes first."
Exit function
end if
'Build the Dialog to know the subd level
Dim l_Pset
AddProp "Custom_parameter_list", "Scene_Root", , "Project subdiv normals on hull", l_Pset
SIAddCustomParameter l_Pset, "Subdiv_Level" , siInt2, 2, 1, 4, siSilent, 4, 0, ParamUIRange, "Subdiv_Level"
l_PsetFullName = "Scene_Root." & l_Pset
l_result = InspectObj(l_PsetFullName,,"Project subdiv normals on hull",siModal,False)
if l_result = false then
in_SubdivLevel = GetValue( l_PsetFullName & ".Subdiv_Level")
for each l_obj in l_InputObjs
'Create a dummy one because of a bug in OM with name "Sample"
set dummyallnodecls = CreateCluster(l_obj.fullname & ".sample[*]")
set allnodecls = CreateCluster(l_obj.fullname & ".sample[*]")
set normalpropname = SIAddProp("User Normal Property", allnodecls(0).fullname, siDefaultPropagation)(0)
set prop = GetValue( normalpropname(0) )
DeleteObj dummyallnodecls(0).fullname
arr = prop.elements.array
total = prop.elements.count
'Subdivide at level in_SubdivLevel
MeshSubdivideWithCenter , l_obj.fullname, , siPersistentOperation
set subdobj = GetValue( "SelectionList" )(0)
SetValue subdobj.fullname & ".polymsh.MeshSubdivideWithCenter.SubdivisionDepth", in_SubdivLevel
nodesarray = subdobj.ActivePrimitive.Geometry.Nodes.NormalArray
for iIndex=0 to total-1
arr(0,iIndex) = nodesarray(0,iIndex)
arr(1,iIndex) = nodesarray(1,iIndex)
arr(2,iIndex) = nodesarray(2,iIndex)
next
prop.elements.array = arr
DeleteObj subdobj.fullname
next
end if
DeleteObj l_PsetFullName
SelectObj in_InputObjs
End function
ProjectSubdivNormalsOnMesh()

