Flipping follicles in ribbon IK

rigging

#1

Does anyone have any experience with flipping follicles in Maya?

I have a pretty basic ribbon IK setup, with follicles placed along a nurbsSurface which is skinned to the controllers. I’m experiencing some of my follicles flipping at certain frames of an animation in Maya 2018 and 2019. The flipping happens on the same follicle which is at the opposite side of the ribbon too.

The normals of the surface are fine, and stable. The nurbs surface was created through a loft, but the history is deleted. The V spans go from 0 to 4, for what it’s worth.

The only reference I can find to this is this link. It is marked as “solved”, but the solution is entirely specific to the scene: https://forums.autodesk.com/t5/maya-animation-and-rigging/follicles-flipping-in-maya-2016-sp1/td-p/6678494

Is this a bug? I have never experienced this before 2018.

flipping_follicles


#2

Follicles made by hair system experience the same flipping, so I’m not mucking up my connections.

I also tried lofting the ribbon down it’s length so U and V are flipped.

It doesn’t seem to be related to DG vs. parallel eval. It happens uniformly across multiple artist computers.

I found a Google Groups result with the same bug from 2011, so I am amazed I’ve never ran across this problem before. But it must be affecting all the ribbon-based stuff I’m using.

At this point, I’m thinking of comparing the outTangent of the follicle to a sane controller space, and then flipping it back when it is flipped.

Open to suggestions!


#3

It’s cause the follicles are placed on the edge of surface. Move them to its center.


#4

Nope, I tried that. The flipping occurs down the entire length of the U parameter, evenly.

image


#5

try to normalize surface
it’s always better to work with normalized curves, surfaces


#6

Yeah, my surface was 0 to spans instead of 0 to 1. But I just tried that, and it did not make a difference.

Have you ever experienced this flipping?


#7

Hmm, I’m wondering how low this goes. Maybe try using the api to ask about the point, tangent and normals, and see if it flips there?

from maya import OpenMaya as om

def getSurfaceParams(obj, u, v):
    # Get the api object
    sel = om.MSelectionList()
    sel.add(obj)
    dagPath = om.MDagPath()
    sel.getDagPath(0, dagPath)
    fnLoft = om.MFnNurbsSurface(dagPath)

    # Query the data
    uTan, vTan, point = om.MVector(), om.MVector(), om.MPoint()
    norm = fnLoft.normal(u, v)
    fnLoft.getTangents(u, v, uTan, vTan)
    fnLoft.getPointAtParam(u, v, point)

    # Pull the numbers into python
    pyPoint = (point.x, point.y, point.z)
    pyNorm = (norm.x, norm.y, norm.z)
    pyUTan = (uTan.x uTan.y uTan.z)
    pyVTan = (vTan.x vTan.y vTan.z)
    return pyPoint, pyNorm, pyUTan, pyVTan

#8

Interesting. Thanks for the script! This returns vectors that match a non-flipped state! I set some locators at the returned points during my flipping frames. The follicle flips, but the data does not…

image

My next theory was that, in our production, they decided to use units*0.1 as a world scale. Our models and rigs are quite small. So I was thinking I was hitting tiny value precision errors. But a larger test was flipping too.

So maybe there is a bug in the actual follicle node?


#9

I also never thought to just try a pointOnSurfaceInfo node. That is also working fine.

Then from there, I guess maybe I’ll just use that, along with an aimConstraint.

Though I bet someone smart knows how to use those normal and tangent vectors to calculate the rotation, using a node?

Edit: Diving into this thread to construct a matrix to get rotation from the normalized vectors: https://forums.cgsociety.org/t/rotations-by-surface-normal/1228039/4


#10

So here is a PyMEL script to attach a locator on to a surface using pointOnSurfaceInfo and a 4x4 matrix.

This is going to replace my heavy use of follicles!

Hat tip to Vasil Shotarov who already wrote about this: https://bindpose.com/maya-matrix-nodes-part-3-matrix-rivet/

(edit: changed .local to .worldSpace)

import pymel.core as pm

nurbs = pm.PyNode('ribbon_geo')
uPos = 0.2
vPos = 0.6

pointOnSurface = pm.createNode('pointOnSurfaceInfo')
nurbs.getShape().worldSpace.connect(pointOnSurface.inputSurface)
pointOnSurface.parameterU.set(uPos)
pointOnSurface.parameterV.set(vPos)

result = pm.spaceLocator(n='result')

# Compose a 4x4 matrix
mtx = pm.createNode('fourByFourMatrix')
outMatrix = pm.createNode('decomposeMatrix')
mtx.output.connect(outMatrix.inputMatrix)
outMatrix.outputTranslate.connect(result.translate)
outMatrix.outputRotate.connect(result.rotate)

'''
Thanks to kiaran at https://forums.cgsociety.org/t/rotations-by-surface-normal/1228039/4
# Normalize these vectors
[tanu.x, tanu.y, tanu.z, 0]
[norm.x, norm.y, norm.z, 0]
[tanv.x, tanv.y, tanv.z, 0]
# World space position
[pos.x, pos.y, pos.z, 1]
'''

pointOnSurface.normalizedTangentUX.connect(mtx.in00)
pointOnSurface.normalizedTangentUY.connect(mtx.in01)
pointOnSurface.normalizedTangentUZ.connect(mtx.in02)
mtx.in03.set(0)

pointOnSurface.normalizedNormalX.connect(mtx.in10)
pointOnSurface.normalizedNormalY.connect(mtx.in11)
pointOnSurface.normalizedNormalZ.connect(mtx.in12)
mtx.in13.set(0)

pointOnSurface.normalizedTangentVX.connect(mtx.in20)
pointOnSurface.normalizedTangentVY.connect(mtx.in21)
pointOnSurface.normalizedTangentVZ.connect(mtx.in22)
mtx.in23.set(0)

pointOnSurface.positionX.connect(mtx.in30)
pointOnSurface.positionY.connect(mtx.in31)
pointOnSurface.positionZ.connect(mtx.in32)
mtx.in33.set(1)

#11

I know follicles can flip when you put them under 0 and 1 coordinarse bit it doesnt seem yo be your case.

If you wanna put some follicles under a surface you should try “Rivet” script. I Dont remember who scripted that one, sorry


#12

Also, here’s a c++ plugin I know of that handles all that, plus length preservation:


#13

It looks like your ribbon is quads. Triangulate the mesh for reliable follicle behavior. FYI - it doesn’t work to triangulate a rigged mesh - that just triangulates it as a post deformation step. You’d need to freeze history, triangulate, transfer skin cluster. That works much better in my experience. What’s happening with a deforming quad mesh is that maya triangulates it differently as it deforms around. This flips the follicle.


#14

hi Chris, Vasil Shotarov method is the way to go if you want clean en stable rivets.
I had this problem too and solved it my uising matrix rivets.

It’s not relative to the scale, the “rivet” script has a bug on tiny scale, the point en surface and 4*4 could be a good solution too, but less stable.

You can try ‘surface attach" node, it’ s a little graph in muscle sys. It does the job sometimes.


#15

Hi skky, Surface Attach nodes are FAR too slow. Losses of 5 to 20 FPS. I do not recommend using them to anyone if they can be avoided. (Tested in Maya 2016 and 2017, maybe they are more parallel-friendly now, but I just avoid them completely.)


#16

Depending of the number, but yeah generaly speaking i use matrix script now. Fast and robust.


#17

Chipping in to say surface rivets can also be applied to meshes as well, circumventing the dreaded geometry constraint: Find the closest face on mesh, make a nurbs plane, and drive its control points with the face’s vertices. It won’t be absolutely rock stable, but unless the driver face flips, your constraint will be stable and very fast.


#18

Hum, need to give a try :D! Seems to be a good idea!


#19

That may work, but PLEASE don’t do that.
Just get Maya 2016 or later and use the PointOnPoly constraint.


#21

I just did a brief test, and this seems to flip around like crazy. (Anyway, I won’t spend any more time on that. I’m not trying to pin things, personally. I’m animating parametrically along surfaces.)