View Full Version : xsi rivet [surface constrain]

05 May 2007, 04:18 PM
is there a Rivet script like maya
for xsi.

cluster constrain is not giving the results i am looking for. i need to get pointLocator on a polygon [midPoint of the polygon]
i've been trying with scop to get specific point on a polygon facet [again midpoint, at any given range of deformation], but its not working for me.

05 May 2007, 04:44 PM
Not 100% sure what Rivet plug for Maya does but
check this tool by Kim Aldis ( may be this is what you are looking for.

05 May 2007, 05:33 PM
you can click on the highend link to quickly read what the rivet script does in maya.

kim's plug in is great.

but i want a null to be constrained on a surface [a poly surface, nor nurbsmesh]

05 May 2007, 06:41 PM
I don't know what is rivet but you're confusing terms. It makes difficult to follow.

So you want null to follow center of polygon? You are looking too far, it is right in front of you, no plugs nor scripts. Create clusters for 2 (or more) opposite vertex. Constrain nulls (object to cluster). Next use 2point (3points or npoints) constrain to constraint 3rd null between previous ones.

Nice and easy, constraint ppg gives you something to play with, animatable parameters. More in manual.

05 May 2007, 08:21 PM
thanks Noratio. [sory about confusion... im sorto hoping from app to app right now. maya/xsi]
this was my initial setup.
but im having to deal with a lot of cycle dependency errors [for what im trying to do].
after looking at some sdk examples, im going to use pointLocator to find nearest point on surface at any given time. this is starting to work out a lot better.

05 May 2007, 08:33 AM
I see, scripting examples uses "surface" as in common language, so I take this back to my collection of confusion. I read those SDK examples also and found it interesting aswell. I think getting rid of cycle dependencies with this might give some great possibilites for rigging. Unfortunately my scripting skills are inadequate, but I'll keep in mind.

05 May 2007, 02:36 PM
You dont need a script for that,

you should use "Object to Cluster" Constraint, and use at least 3 points in your cluster.
3 points are the minimum to create a plane, so your constrained object can
inherit it's position and rotation from this plane. if you use less than 3 points, it will
not rotate right with your object.

you have to activate the tangency and normal to make it rotate.

05 May 2007, 12:12 AM
You dont need a script for that,

you should use "Object to Cluster" Constraint, and use at least 3 points in your cluster.
3 points are the minimum to create a plane, so your constrained object can
inherit it's position and rotation from this plane. if you use less than 3 points, it will
not rotate right with your object.

you have to activate the tangency and normal to make it rotate.

and once you've done that, how do you move it around? :)

Kim's script is actually the closest thing to a rivet constraint where the rivet can be moved, it just happens to translate from a UVspace input to the actual geometry space, but it IS a rivet, only deforming geometry.

if you want it as a kine constraint just deform a small triangle with it and constrain the object to a cluster made of all the triangle points.

05 May 2007, 02:42 AM
and once you've done that, how do you move it around? :)

It maybe possible to move around the object if you are not constraining the object directly.
Create a parent null for the object, constraint the null, it will give you 6 DOF of the object itself. You still can move and rotate the object in its parent axis.


05 May 2007, 03:10 AM
no, it's not possible, it won't move across the surface.
what you're talking about is an srt buffering, and that adds freedom of movement in the space of the constrained buffer, NOT movement constrained to a surface (which for the record isn't exclusively parametric surfaces in general terms :) ), which is the point of a rivet.

to explain further:
constraining to an Npoint cluster will place your rivet in the averaged position of those N vertices, and that's it.
constraining with an Npoints constrain allows you to balance the contribution of those N elements.

both are, however, static solutions that limit you to re-creating your set everytime you want to tweak, not to mention add a layer of complexity that isn't easily tracked without a nodal representation of the scene's graph.
both are also screwed as soon as your set of elements isn't planar (which can happen on a poly with 5 points where one of the points isn't adjacent to the others), and both also reference explicit cages, with no options to adapt to the subdivided mesh.

a rivet constraint is convenient because it allows you, by proximity to a locator (which can be external, or the object's pre-rivet transformation), to place an object exactly on the closest point on a surface, which can be the explicit mesh, or the derivated smoothed surface from subDs, all in one op, with no inconvenient layers to maintain.

a rivet constraint IS possible with some trickey and Kim's tool, or with some trivial scripting and the point locator in the API. It is not as easily replicated by just being creative though, not with constraints at least.

if you feel like trying though, stop looking into locking crap to point and srt buffers, and start looking into shrinkwrapping an enveloped tri to the reference object, that will get you A LOT closer then hackish sets of clusters and constraints :)

05 May 2007, 02:09 PM
steven wrote a small article on xsi blog that deals exactly with this.
have a look at it, it might make things easier to understand:

06 June 2007, 10:06 PM
my blog does use constraining to cluster so it is as Raffaele says... "hackish sets of clusters and constraints". but what you get is something that a non script savvy artist can use

this blog is really about the use of the static kinestate to offset the initial position of the second envelope. how you constrain you local deformer is up to you.

we need more context. does the rivet script your referring to allow you to move the object interactively while constraining to the surface? what are you trying to achieve with the 'rivet' tool?

06 June 2007, 12:24 AM
For those that don't have access to maya/rivet script (or understand mel)

It's basically a static op.

the two edges you pre-select are turned into curves then lofted. the locator is then constrained to this suface and the tangency/normal vector is set (with a look at constraint it seems).

mind numbingly simple to emulate in xsi you could even throw in a good old pointLocator pick session (there's a crappy topology script somehwere on these forums if you need an example) and roberts your mothers brother.

of course, this is not to take away from the rivet scripts author in any way :)

a more dynamic soloution, although tricky, is definately do-able. Jaco is definately bang on target with the barycentric approach that Kim's plugin uses (a presumtion here) in my opinion.

over to you kim :D

/edit - 1:30am..for some reason UV's and barycentric space have merged ;)

06 June 2007, 02:36 AM
/edit - 1:30am..for some reason UV's and barycentric space have merged ;)

it's still likely that barycentric coordinates are being used for intersample values anyway. A forgivable slip ;)

06 June 2007, 01:52 PM
a slip nonetheless ;)

as pennance, i had a little play with the whole shrinkwrap idea.

suprisingly, it works rather well.
// Jon Swindells

// quick and dirty implementation of some ideas expressed
// on the cgtalk xsi forum (maya rivet)

var oRoot = Application.ActiveSceneRoot;
var sel = Application.Selection;

if( checkSel(sel) )
var edgeCmp = sel(0).SubComponent;
var edgeColl = edgeCmp.ComponentCollection;

var parX3Dobj = edgeCmp.Parent3DObject;

var rvtStripMasterNull = oRoot.AddNull("RivetStripMaster");

// always nice to collect params as you go :)
var paramColl = new ActiveXObject( "XSI.Collection" );

var strEdge1 = parX3Dobj + ".edge[" + edgeColl.item(0).index + "]";
var strEdge2 = parX3Dobj + ".edge[" + edgeColl.item(1).index + "]";

var elOp_1 = ApplyGenOp("ExtractEdgeLoopOp", "", strEdge1, siUnspecified ,siPersistentOperation,siKeepGenOpInputs, null)(0);
var elOp_2 = ApplyGenOp("ExtractEdgeLoopOp", "", strEdge2, 3, siPersistentOperation, siKeepGenOpInputs, null)(0);

// get the parent3dObj of the ops
var crv1 = elOp_1.OutputPorts(0).Target2.Parent;
ParentObj(rvtStripMasterNull, crv1);

var crv2 = elOp_2.OutputPorts(0).Target2.Parent;
// parent stuff as we go
ParentObj(rvtStripMasterNull, crv2);

// loft a new surface
var loftInputsStr = crv1 + "," + crv2;
var loftOp = ApplyGenOp("Loft", null, loftInputsStr, 3, siPersistentOperation, siKeepGenOpInputs, null)(0);

// rather than messing about trying to get the edges that span the (possible) gap i'm just using an arbitrary amount
loftOp.subdivtype.Value = 1; // absoloute

var surfaceResoloutionV = loftOp.subdivv; // the important one
var surfaceResoloutionU = loftOp.subdivu;
surfaceResoloutionV.Value = 10;
surfaceResoloutionU.Value = 4; // to be safe

var surf1 = loftOp.OutputPorts(0).Target2.Parent;

ParentObj(rvtStripMasterNull, surf1);

// might need this
var invNormalsOp = ApplyTopoOp("Inverse", surf1, 3, siPersistentOperation, null)(0);


var swString = surf1 + ";" + parX3Dobj + ";"; // get the edges parentx3dobj
var shrinkWrapOp = ApplyOp("ShrinkWrap", swString, 3, siPersistentOperation, null, 0)(0);
shrinkWrapOp.proj.Value = 6; // closest smoothed surf
//paramColl.Add(shrinkWrapOp.proj); <-- was just asking for a crash :)

var oNull = rvtStripMasterNull.AddNull("RivetStripNull");

var srfCns = ApplyCns("Surface", oNull, surf1, null)(0); // needs to be siApplyConstraint

// no messing around here, if the user wants to set these then a inspectParam button is simpler
srfCns.tangent.Value = true;
srfCns.upvct_active.Value = true;

//-- you would probably start a pickPos session here and use pointLocator
// i couldn't be arsed so i set it to the center
srfCns.posu.Value = 0.5;
srfCns.posv.Value = 0.5;

// offset in y looks to be a good tweakage param (probably need to invert the val though)
paramColl.Add(srfCns.offy );

// build a simple prop set
var cpset = oNull.AddCustomProperty("RivetStrip", false);

var oGrp = CreateGroup("Gubbins",[crv1, crv2,surf1,rvtStripMasterNull] );
oGrp.Parameters("viewvis").Value = 0;
oGrp.Parameters("rendvis").Value = 0;

// scruffy and extremely ugly
oEnum = new Enumerator( paramColl ) ;
for (;!oEnum.atEnd();oEnum.moveNext() )

SelectObj(oNull, null, null);
InspectObj( cpset, "", "", siLock, false );

function checkSel(sel)
if( sel.Count && sel(0).Type == "edgeSubComponent")
var subcmp = sel(0).SubComponent;
var edges = subcmp.ComponentCollection;
return (edges.count == 2)
return false;

:: you need two edges selected on your mesh..bear in mind, the greater the topolgy changes between these edges, the more chance of it sucking.

the proxy param set contains (in order)
the Lofting divisions (use these if you're shrinkwrap isn't 'happening' too well)

the surface mesh invert - xsi isn't as forgiving as maya when it comes to surface lofting, use this when you see a black loft surface

the position u and v of the rivet null - do i really need to explain this ?

the offset in y of the null - useful for a surface offset type deal.

it sucks badly on teeny tiny meshes (as does shrinkwrap in general).

feel free to bin/mock/rejoice/change/claim this script in any way.


//edit - unhide and move the master null about and the rivet will follow on the surface of you mesh...bonus
// doh, the offsetY needs to be local to the surface. ignore it for now

If you are getting a twisted loft then just invert one of the crvlist's.

CGTalk Moderation
06 June 2007, 01:52 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.