Object Hierarchy | Related C++ Class: PointLocatorData
v5.0
A PointLocatorData object represents a collection of point
locators. A point locator is a geometric surface coordinate, and
represents a precise location on a geometry. Point locators are
topologically defined, so they are not dependent on the position or
the deformation of the geometry (they "stick" to the surface). The
actual data defining a point locator is abstracted and depends on
the geometry type.
Point locators are a generalization of Points. As points, point locators can be processed
independently from the geometry type. Like point indices, point
locators are not related to a particular geometry instance. You can
query any geometry having the same topology with the same
PointLocatorData. For instance, you can use point locators to
evaluate positions of an animated geometry at different
times.
Because point locators don't apply to a particular geometry
instance, the PointLocatorData object has no functionality by
itself. Most methods related to PointLocatorData are defined in
Geometry, PolygonMesh and NurbsSurfaceMesh. PointLocatorData can
be created by methods Geometry.GetClosestLocations,
Geometry.GetClosestLocationsWithinRadius,
Geometry.GetRaycastIntersections,
Geometry.GetSurfacePointLocatorsFromPointsPolygonMesh.ConstructPointLocators
and NurbsSurfaceMesh.ConstructPointLocators.
Other examples of PointLocatorData usage can be found in various
related methods such as PointLocatorData.Count and
PolygonMesh.ConstructPointLocators.
Note: Point locators are currently only supported by NurbsSurfaceMesh and PolygonMesh objects.
# # This example uses PointLocatorData to shrink-wrap a sphere to a cube, # and then pushes the sphere along cube's normals. # app = Application app.NewScene( "", 0 ) root = app.ActiveSceneRoot CubeGeom = root.AddGeometry("Cube", "MeshSurface").ActivePrimitive2.Geometry SphereObj = root.AddGeometry("Sphere", "MeshSurface") SphereObj.subdivv = 24 SphereObj.subdivu = 24 # Freeze it, otherwise its position array cannot be set: app.FreezeObj(SphereObj) SphereGeom = SphereObj.ActivePrimitive2.Geometry SphereOnCubePointLocators = CubeGeom.GetClosestLocations(SphereGeom.Points.PositionArray) SphereOnCubePositions = CubeGeom.EvaluatePositions(SphereOnCubePointLocators) SphereOnCubeNormals = CubeGeom.EvaluateNormals(SphereOnCubePointLocators) SphereNewPositions = [] i = 0 while i < len(SphereOnCubePositions) : j = 0 tmplist = [] while j < len(SphereOnCubePositions[i]) : tmplist.append( SphereOnCubeNormals[i][j]*3 ) j = j + 1 SphereNewPositions.append(tmplist) i = i + 1 SphereGeom.Points.PositionArray = SphereNewPositions; |
/* This example uses PointLocatorData to deform a polygon mesh based on the closest weight map value of a NURBS surface mesh. */ // Scene creation: // Polygon mesh grid and a NURBS surface grid. // On the NURBS grid, a weight map having a radial gradient NewScene( null, false ); var root = Application.ActiveSceneRoot; var MeshGridObj = root.AddGeometry("Grid", "MeshSurface"); MeshGridObj.subdivu = 24; MeshGridObj.subdivv = 24; // We must freeze it, otherwise setting its position array will be forbidden: FreezeObj(MeshGridObj); var MeshGridGeom = MeshGridObj.ActivePrimitive.Geometry; var NURBSGridObj = root.AddGeometry("Grid", "NurbsSurface"); NURBSGridObj.subdivu = 2; NURBSGridObj.subdivv = 2; var NURBSGridGeom = NURBSGridObj.ActivePrimitive.Geometry; var NURBSWeightMap = CreateWeightMap(null, NURBSGridObj, "Weight_Map").item(0); SetValue(NURBSWeightMap + ".weightmapop.type", 5); SetValue(NURBSWeightMap + ".weightmapop.weight", 1); SetValue(NURBSWeightMap + ".weightmapop.invert", true); NURBSWeightMap = GetValue(NURBSWeightMap); // Get the weight map again to have an updated copy // Applying the deformation var MeshGridPos = MeshGridGeom.Points.PositionArray.toArray(); var MeshGridOnNURBSGridPointLocators = NURBSGridGeom.GetClosestLocations(MeshGridPos); var WeightMapValuesForMesh = NURBSGridGeom.EvaluateClusterProperty( MeshGridOnNURBSGridPointLocators, NURBSWeightMap.Parent, NURBSWeightMap ).toArray(); // Push mesh vertices along Y, modulated by NURBS grid's closest surface's weight map value for(i = 0; i < MeshGridPos.length; i+=3) MeshGridPos[i+1] += WeightMapValuesForMesh[i/3]*5; MeshGridGeom.Points.PositionArray = MeshGridPos; |
// The following example is more complex but shows the PointLocatorData // at work in the context of a relatively complex scripted operator. // // This example creates a "skinning" custom operator, which a kind // of shrink wrap-based cage deform operator. This operator // wraps a deformed "body" object with a "skin" object having a different // topology. In order to create the surface correspondance between // the skin and the body, it uses a static copy of the "body", which // is not animated and stands as a reference. The operator supports, // too, arbitrary poses on each object. // // Since the skin and the reference body are not animated, the // custom operator can create the point locators only once, // at the first evaluation, and then only need to evaluate // them on the deformed body at each frame. This improves a lot // the performance since creating point locators from spatial // proximity is much more costly than simply evaluating their // positions or normals. // // Additionally, in order to improve the skinning result, the // operator pushes the sking along the normals of the body, // and the amplitude of this push can be controlled by a parameter. NewScene( null, false ); var root = Application.ActiveSceneRoot; Translate("Camera", 0, 0, 50.0, siRelative, siView, siObj, siXYZ); // Create the reference body object, non-animated object (a cube), // and move it to a non-trivial pose var ReferenceCubeObj = root.AddGeometry("Cube", "MeshSurface"); Translate(ReferenceCubeObj, -25.0, 0, 0, siRelative, siView, siObj, siXYZ); // Create the skin object (a sphere with more resolution), // and move it to a non-trivial pose var ShrinkWrappedSphereObj = root.AddGeometry("Sphere", "MeshSurface"); ShrinkWrappedSphereObj.subdivu = 25; ShrinkWrappedSphereObj.subdivv = 25; Rotate(ShrinkWrappedSphereObj, 0, 0, -60.0, siRelative, siLocal, siObj, siXYZ); Scale(ShrinkWrappedSphereObj, 1.5, 1.5, 1.5, siRelative, siLocal, siObj, siXYZ); Translate(ShrinkWrappedSphereObj, -25.0, 0, 0, siRelative, siView, siObj, siXYZ); // Create the animated target body object. // In order to show the scripted op at work, add kinematic and // shape animation. var TargetCubeObj = root.AddGeometry("Cube", "MeshSurface"); Translate(TargetCubeObj, 10.0, 10.0, 0, siRelative, siView, siObj, siXYZ); SetValue("Context.constructionmode", 1); Scale("cube1.pnt[2,3,6,LAST]", 0.3, 0.3, 0.3, siRelative, siLocal, siObj, siXYZ); SaveShapeKey("cube1.pnt[2,3,6,LAST]", null, null, 1); Scale("cube1.pnt[2,3,6,LAST]", 10.0, 10.0, 10.0, siRelative, siLocal, siObj, siXYZ); SaveShapeKey("cube1.polymsh.cls.Shape", null, null, 100); SaveKey("cube1.kine.local.posx,cube1.kine.local.posy,cube1.kine.local.posz"); SaveKey("cube1.kine.local.rotx,cube1.kine.local.roty,cube1.kine.local.rotz"); Rotate(TargetCubeObj, 50.0, 0, 50.0, siRelative, siLocal, siObj, siXYZ); SetValue("PlayControl.Current", 100); SaveKey("cube1.kine.local.rotx,cube1.kine.local.roty,cube1.kine.local.rotz", 100); Translate(TargetCubeObj, -15.0, -15.0, 0.0, siRelative, siView, siObj, siXYZ); SaveKey("cube1.kine.local.posx,cube1.kine.local.posy,cube1.kine.local.posz", 100); SetValue("PlayControl.Current", 1); // Apply the scripted op to the skin. var SkinOp = ApplySkinOp( ShrinkWrappedSphereObj, ReferenceCubeObj, TargetCubeObj ); SetValue("PlayControl.Loop", true); PlayForwardsFromStart(); InspectObj(SkinOp); function ApplySkinOp( inSkinObj, inReferenceBody, inTargetBody ) { var op = XSIFactory.CreateScriptedOp( "MySkinOp", MySkinOp_Update.toString(), "JScript" ); // Define connections var skin_group = op.AddPortGroup( "SkinGroup" ); op.AddIOPort( inSkinObj.ActivePrimitive, "Geom", skin_group.Index ); op.AddInputPort( inSkinObj.Kinematics.Global, "Pose", skin_group.Index ); var ref_group = op.AddPortGroup( "ReferenceBodyGroup" ); op.AddInputPort( inReferenceBody.ActivePrimitive, "Geom", ref_group.Index ); op.AddInputPort( inReferenceBody.Kinematics.Global, "Pose", ref_group.Index ); var tgt_group = op.AddPortGroup( "TargetBodyGroup" ); op.AddInputPort( inTargetBody.ActivePrimitive, "Geom", tgt_group.Index ); op.AddInputPort( inTargetBody.Kinematics.Global, "Pose", tgt_group.Index ); // Define a parameter for the push amplitude var pdef = XSIFactory.CreateParamDef2( "PushAmplitude", siDouble, 2, -1, 5 ); op.AddParameter(pdef); // Connect operator op.Connect(inSkinObj + ";" + inReferenceBody + ";" + inTargetBody); return op; } // This function contains the implementation of the scripted operator. function MySkinOp_Update( ctx, out, InSkinGeom, InSkinPose, InReferenceBodyGeom, InReferenceBodyPose, InTargetBodyGeom, InTargetBodyPose ) { // TransformPositionArray: transforms in place an array of packed XYZ vectors function TransformPositionArray( array, transfo ) { for (i = 0; i < array.length; i+=3) { var TempVector3 = XSIMath.CreateVector3() TempVector3.Set(array[i], array[i+1], array[i+2]); TempVector3.MulByTransformationInPlace(transfo); var XYZArray = TempVector3.Get2().toArray(); array[i] = XYZArray[0]; array[i+1] = XYZArray[1]; array[i+2] = XYZArray[2]; } } var SkinGeom = InSkinGeom.Value.Geometry; var ReferenceBodyGeom = InReferenceBodyGeom.Value.Geometry; ///////////////////////////////////////////////////////// //1) Create skin point locators relatively to the surface // proximity to the reference body. We intentionally keep // a snapshot of the point locators to speed up the // next evaluations; we assume that InSkinGeom, InSkinPose, // InReferenceBodyGeom and InReferenceBodyPose are not // animated. var SkinPointLocators = ctx.UserData; if(SkinPointLocators == null) // No user data means that this is the first evaluation of the operator { // The skin object and the reference may have different poses, so we // will compute the surface proximity computation in global space. // We will use the closest smoothed surface method (2==siClosestSmoothedSurface). ReferenceBodyGeom.SetupPointLocatorQueries(2, InReferenceBodyPose.Value.Transform); // Transform the skin positions in global space var SkinGeomPosArray = SkinGeom.Points.PositionArray.toArray(); // TransformPositionArray: transforms in place an array of packed XYZ vectors TransformPositionArray( SkinGeomPosArray, InSkinPose.Value.Transform ); SkinPointLocators = ReferenceBodyGeom.GetClosestLocations(SkinGeomPosArray); ctx.UserData = SkinPointLocators; } ///////////////////////////////////////////////////////// //2) Evaluate the point locators on the target body, and // displace them along target body's normals, with the // amplitude given by the scirted op parameter. var TargetBodyGeom = InTargetBodyGeom.Value.Geometry; var SkinOnTargetBodyPositions = TargetBodyGeom.EvaluatePositions(SkinPointLocators).toArray(); var SkinOnTargetBodyNormals = TargetBodyGeom.EvaluateNormals(SkinPointLocators).toArray(); var SkinToTargetTransform = XSIMath.MapWorldPoseToObjectSpace(InSkinPose.Value.Transform, InTargetBodyPose.Value.Transform); var dPushAmplitude = ctx.Parameters("PushAmplitude").Value for (i = 0; i < SkinOnTargetBodyPositions.length; i++) SkinOnTargetBodyPositions[i] += SkinOnTargetBodyNormals[i]*dPushAmplitude; // TransformPositionArray: transforms in place an array of packed XYZ vectors TransformPositionArray( SkinOnTargetBodyPositions, SkinToTargetTransform ); SkinGeom.Points.PositionArray = SkinOnTargetBodyPositions; } |
Geometry Geometry.GetClosestLocations Geometry.GetClosestLocationsWithinRadius Geometry.GetRaycastIntersections Geometry.SetupPointLocatorQueries Geometry.GetSurfacePointLocatorsFromPoints Geometry.EvaluatePositions Geometry.EvaluateNormals Geometry.EvaluateClusterProperty PolygonMesh.GetPolygonIndexArray PolygonMesh.GetTriangleVertexIndexArray PolygonMesh.GetTriangleNodeIndexArray PolygonMesh.GetTriangleWeightArray PolygonMesh.ConstructPointLocators NurbsSurfaceMesh.GetSubSurfaceIndexArray NurbsSurfaceMesh.GetNormalizedUVArray NurbsSurfaceMesh.ConstructPointLocators