ClosestPointOnMesh in a specified axis direction

ClosestPointOnMesh in a specified axis direction

adnanmg
Advocate Advocate
724 Views
3 Replies
Message 1 of 4

ClosestPointOnMesh in a specified axis direction

adnanmg
Advocate
Advocate

Hi,

 

I'm trying to come up with some python code to take a given joint, and find the closest point (and UV coordinate value) on a mesh in both the Y+ and Y- axis direction based on the local pivot of the joint. I wondered if it is possible to use the direction vector from the code at the bottom with closestPointOnMesh or some such method to get the point in the positive and negative Y axis from the joint in a straight line to the mesh surface and return the UV coordinate as we normally would with that node.

 

Some code towards this effort without the direction part figured out yet:

        mult_val = -1
        follShapeB = cmds.createNode('follicle', name=current_joint+'_follicleB')
        if cmds.listRelatives(follShapeB, p=1):
            follB = cmds.rename(cmds.listRelatives(follShapeB, p=1)[0], follShapeB + '_xform')

        cmds.connectAttr(source_mesh_shape + '.outMesh', follShapeB + '.inputMesh')
        cmds.connectAttr(source_mesh_shape + '.worldMatrix[0]', follShapeB + '.inputWorldMatrix')
        cmds.connectAttr(follShapeB + '.outTranslate', follB + '.translate', f=1)
        cmds.connectAttr(follShapeB + '.outRotate', follB + '.rotate', f=1)

        #create locator    
        current_locB = current_joint+'B_loc'
        cmds.spaceLocator(n=current_locB)
        current_locB_shape = cmds.listRelatives(current_locB, s=1)[0]
        cmds.parentConstraint(current_joint, current_locB, mo=0, n='deleteCon')
        cmds.delete('deleteCon')
        cmds.parent(current_locB, locator_group)
    
        # closest point on mesh
        cpmNodeB = cmds.createNode('closestPointOnMesh')
        cmds.connectAttr(source_mesh_shape + '.outMesh', cpmNodeB + '.inMesh')
        cmds.connectAttr(current_locB + '.center', cpmNodeB + '.inPosition', f=1)
        #cmds.setAttr(cpmNodeB + '.ip.ipx', ray_dir[0]*mult_val)
        #cmds.setAttr(cpmNodeB + '.ip.ipy', ray_dir[1]*mult_val)
        #cmds.setAttr(cpmNodeB + '.ip.ipz', ray_dir[2]*mult_val)

        curU = cmds.getAttr(cpmNodeB + '.parameterU')
        curV = cmds.getAttr(cpmNodeB + '.parameterV')
        cmds.setAttr(follShapeB + '.parameterU', curU)
        cmds.setAttr(follShapeB + '.parameterV', curV)

 

I came up with this code to get the direction ray for a given axis on a joint:

# based on https://stackoverflow.com/questions/63041048/get-the-direction-an-objects-axis-is-pointing-in-maya
def get_axis_dir(object = '', axis = 'y', world_space = 0):
    object_position = cmds.xform(object, q=True, m=True, ws=world_space)
    x_axis = om.MVector(object_position[0:3])
    y_axis = om.MVector(object_position[4:7])
    z_axis = om.MVector(object_position[8:11])
    
    if axis == 'x':
        return x_axis
    if axis == 'y':
        return y_axis
    if axis == 'z':
        return z_axis

  

Thank you,

 

Adnan Hussain

0 Likes
725 Views
3 Replies
Replies (3)
Message 2 of 4

jmreinhart
Advisor
Advisor
import maya.api.OpenMaya as om2
def get_axis_dir(object = '', axis = 'y', world_space = 0):
    object_position = cmds.xform(object, q=True, m=True, ws=world_space)
    x_axis = om2.MVector(object_position[0:3])
    y_axis = om2.MVector(object_position[4:7])
    z_axis = om2.MVector(object_position[8:11])
    
    if axis == 'x':
        return x_axis
    if axis == 'y':
        return y_axis
    if axis == 'z':
        return z_axis

def getPointOnMesh(object, mesh, axis = 'y', worldSpace = 0, direction = 1):            
    projAxis = get_axis_dir(object, axis, worldSpace)
    projAxis *= direction
    projAxis = om2.MFloatVector(projAxis)

    objectPos = cmds.xform(object, q=True, t=True, ws=worldSpace)
    objectPos = om2.MFloatPoint(objectPos[0],objectPos[1],objectPos[2])

    sel = om2.MSelectionList()
    sel.add(mesh)
    mFnMesh = om2.MFnMesh(sel.getDagPath(0))

    hitPoint, hitRayParam, hitFace, hitTriangle, hitBary1, hitBary2 = mFnMesh.closestIntersection(
        objectPos,#raySource
        projAxis,#rayDirection,
        om2.MSpace.kWorld,
        100,#maxParam
        False#testBothDirections
    )
    
    return hitPoint
    
    
resPoint = getPointOnMesh('joint1','pCubeShape1', direction = -1)
x = cmds.spaceLocator()[0]
cmds.setAttr(x + '.t', resPoint[0], resPoint[1], resPoint[2])

 

You'll need to use the MFnMesh.closestIntersection method from the Maya API. Above is an example.

Message 3 of 4

adnanmg
Advocate
Advocate

Thanks so much! I'm digging into your example. It looks like it takes the direction, with an option to be positive or negative. It gets the dagNode (I'm assuming that is the shape node) of the mesh and the position of the joint. It creates the locator, but it creates it at the origin instead of finding an intersection point on the mesh. It seems to work if I set worldspace to world and not local. Any idea what I am missing?

 

Thanks,

 

Adnan

0 Likes
Message 4 of 4

jmreinhart
Advisor
Advisor

The code uses the xform command to get the matrix of the object. If it has a hierarchy above it then the worldSpace matrix may be very different from the local matrix. It just depends on your situation.

0 Likes