Last active
March 17, 2017 17:09
-
-
Save thirstydevil/817c335c356e8c231d35fc013f654bfd to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def locatorOnPoly(name=""): | |
""" | |
Requires a single poly selection. The script will then create a locator of the polygon normal and then orient it | |
to the tangent of the longest edge on the polygon using a aim constraint and and a couple of locators that finally | |
get cleaned up. Probably a nice way to do this by building a world space rotation matrix from the vector of | |
point A and B on the longest edge and the normal of the poly. | |
:param name: str(Locator Name) | |
:return: pCore.dt.transform() | |
""" | |
face = pCore.selected(fl=True)[0] | |
if len(face) == 1: | |
if isinstance(face, pCore.MeshFace): | |
with pCore.UndoChunk(): | |
# Create the locator of the poly normal using the moveTool manipulator to do that | |
currentTool = pCore.currentCtx() | |
pCore.setToolTo("moveSuperContext") | |
pos = pCore.dt.Vector(pCore.manipMoveContext("Move", q=1, p=1)) | |
pCore.setToolTo(currentTool) | |
loc = pCore.spaceLocator(n="Average#") | |
loc.setTranslation(pos) | |
normal = face.getNormal(space="world") | |
# reselect the face and get the perimeter edges | |
pCore.select(face) | |
pCore.mel.ConvertSelectionToEdgePerimeter() | |
edgeList = pCore.selected(fl=True) | |
# get the longest edges and pull out the world position of the start and end of that edge | |
lengths = [] | |
for edge in edgeList: | |
lengths.append((edge.getLength(), edge)) | |
longestEdge = sorted(lengths)[-1][1] | |
posA = longestEdge.getPoint(0, space="world") | |
posB = longestEdge.getPoint(1, space="world") | |
# Aim the locator using the some dummy locators | |
locTemp = pCore.spaceLocator(n="tmp#") | |
locTemp.setTranslation(posA) | |
locTempB = pCore.spaceLocator(n="tmp#") | |
locTempB.setTranslation(posB) | |
# Make sure the Z Axis is the Primary Axis pointing along the normal. | |
pCore.delete(pCore.aimConstraint(locTemp, locTempB, loc, aimVector=(1, 0, 0), upVector=(0, 0, -1), worldUpVector=normal)) | |
pCore.delete([locTemp, locTempB]) | |
if name: | |
loc.rename(name) | |
return loc | |
def rivetLocatorToSelectedPoly(name=""): | |
""" | |
Quick locator constrained to a Follicle. Must have a single face selected | |
:param name: str | |
:return: None | |
""" | |
face = pCore.selected()[0] | |
if len(face) == 1: | |
if isinstance(face, pCore.MeshFace): | |
rivetLoc = locatorOnPoly(name) | |
pCore.select(rivetLoc) | |
pCore.move((0, 0, -0.005), r=1, os=1) # moving off the surface doesn't improve. | |
# Why does getUVAtPoint not work consistently? This has started in Many scripts or even the closestPointOnMesh node | |
# Running it once will return [0,0]. Noticed that when I ran it several times it returns the correct value, | |
# eventually. I though perhaps it was choosing a random direction + or - if one isn't given. | |
u, v = [0, 0] | |
for x in range(0): | |
u, v = face.getUVAtPoint(rivetLoc.getRotatePivot(space="world"), "world", "map1") | |
if any([u, v]): | |
break | |
pCore.select([]) | |
pCore.select([rivetLoc, face]) | |
fTrans, fShape = createFollicle(rivetLoc.shortName(), poly_surface=face.node().name(), u=u, v=v) | |
pCore.parentConstraint(fTrans, rivetLoc, mo=True) | |
def createFollicle(name, nurbs_surface=None, poly_surface=None, u=0, v=0): | |
""" | |
Simple follicle creation wrapper. | |
:param name: str | |
:param nurbs_surface: str | |
:param poly_surface: str | |
:param u: int | |
:param v: int | |
:return: str(transform), str(follicleShape) | |
""" | |
# create a follicle node and connect it | |
follicle_transform = cmds.createNode("transform", n=(name + "follicle")) | |
follicle = cmds.createNode("follicle", n=(name + "follicleShape"), p=follicle_transform) | |
cmds.connectAttr((follicle + ".outTranslate"), (follicle_transform + ".translate"), f=1) | |
cmds.connectAttr((follicle + ".outRotate"), (follicle_transform + ".rotate"), f=1) | |
if nurbs_surface: | |
cmds.connectAttr((nurbs_surface + ".local"), (follicle + ".is"), f=1) | |
cmds.connectAttr((nurbs_surface + ".worldMatrix[0]"), (follicle + ".inputWorldMatrix"), f=1) | |
if poly_surface: | |
cmds.connectAttr((poly_surface + ".outMesh"), (follicle + ".inm"), f=1) | |
cmds.connectAttr((poly_surface + ".worldMatrix[0]"), (follicle + ".inputWorldMatrix"), f=1) | |
cmds.setAttr((follicle + ".parameterU"), u) | |
cmds.setAttr((follicle + ".parameterV"), v) | |
return follicle_transform, follicle |
I'm happy to hear it somehow works now and thanks for sharing the code. Funny that the one method call has 3 different possible modules that it comes from, my mistake! I wrote an API 2.0 version just in case you're interested (I know this was an issue that came from just having to update some scripts so I'm sure it's not retroactively helpful, but maybe going forward.):
https://gist.github.com/AndresMWeber/27ff60f361627d8bed1fa962929c37b8
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks Andres, I've updated the code so you can see the complete picture.
Regards
David