Announcements

Between mid-October and November, the content on AREA will be relocated to the Autodesk Community M&E Hub and the Autodesk Community Gallery. Learn more HERE.

Getting click position in world coordinates?

Getting click position in world coordinates?

Anonymous
Not applicable
4,239 Views
2 Replies
Message 1 of 3

Getting click position in world coordinates?

Anonymous
Not applicable

Hi 

 

I have a question regarding obtainng the location of mouse click in world coordinates in Maya.

I am using Maya 2016 and Python API 2.0

 

So I know I can use the cmds.draggerContext() Python command to get the location of the mouse click in world space coordinates by setting space = "world" in cmds.draggerContext().

 

Here is how I am doing it:

 

 

import maya.cmds as cmds

draggerContextName = "myDragger"

def dragger_onPress():
    pos = cmds.draggerContext(draggerContextName, query = True, anchorPoint = True)
    print("init:", pos[0], pos[1], pos[2])
    
def dragger_onDrag():
    pos = cmds.draggerContext(draggerContextName, query = True, dragPoint = True)
    print("drag pos:", pos[0], pos[1], pos[2])
    

if (cmds.contextInfo(draggerContextName, exists = True)):
    cmds.deleteUI(draggerContextName, toolContext = True )
    
cmds.draggerContext(draggerContextName, pressCommand = dragger_onPress, dragCommand = dragger_onDrag, cursor = "crossHair", space="world")
cmds.setToolTo(draggerContextName)



 

I am also aware that I can use the Maya Python 2.0 API to get the position of the mouse click in world space coordinates as follows:

 

import maya.cmds as cmds

import maya.api.OpenMaya as om
import maya.api.OpenMayaUI as omui2

draggerContextName = "myDragger"

def viewToWorld(screenX, screenY):
    worldPos = om.MPoint() # out variable
    worldDir = om.MVector() # out variable
    
    activeView = omui2.M3dView().active3dView()
    activeView.viewToWorld(int(screenX), int(screenY), worldPos, worldDir)
    
    return worldPos, worldDir
        

def dragger_onPress():
    pos = cmds.draggerContext(draggerContextName, query = True, anchorPoint = True)
    pos = viewToWorld(pos[0], pos[1])[0]
    
    print("init:", pos[0], pos[1], pos[2])
    

def dragger_onDrag():
    pos = cmds.draggerContext(draggerContextName, query = True, dragPoint = True)
    pos = viewToWorld(pos[0], pos[1])[0] # get the first value of the tuple
    
    print("drag pos:", pos[0], pos[1], pos[2])    
    

if (cmds.contextInfo(draggerContextName, exists = True)):
    cmds.deleteUI(draggerContextName, toolContext = True )
    
cmds.draggerContext(draggerContextName, pressCommand = dragger_onPress, dragCommand = dragger_onDrag, cursor = "crossHair")
cmds.setToolTo(draggerContextName)

Note that I have not set the space flag in cmds.draggerContext() command here so I am getting the mouse click coordinates in screen space which I am then converting to world space using the M3dView.active3dView.viewToWorld() function.

 

Though I would expect similar output on mouse click in both the approaches, the result however is not the same.

While I get consistent coordinates in the first approach, using the Maya API the coordinates differ when zooming or translating the viewport.

Even with same zoom and translation  of the viewport, the ouput is different in both the scenarios.

 

Can somebody please tell me why is there such a difference between the two cases?

Using the first approach seems preferable but the Maya API also gives the wordDir MVector() which can then be used for hit testing with an object. 

 

 

0 Likes
Accepted solutions (1)
4,240 Views
2 Replies
Replies (2)
Message 2 of 3

cheng_xi_li
Autodesk Support
Autodesk Support
Accepted solution

Hi,

 

draggerContext will do ray tracing for you instead, so you'll get a position of objectPlane or viewPlane by default which your draggerContext command does. 

 

M3dView returns a ray source and ray direction, so you'll need to do ray tracing yourself. You could use intersect related APIs(e.g. MFnMesh::anyIntersection) to do it, or you could implement your own ray tracing code.

 

You could refer to the Wikipedia page, it is pretty plain and simple. Here is my modified version, it doesn't support object plane, but it should be fairly easy to replace origin position with dag object's world position.

 

import maya.cmds as cmds

import maya.api.OpenMaya as om
import maya.api.OpenMayaUI as omui2

draggerContextName = "myDragger"

def viewToWorld(screenX, screenY):
    worldPos = om.MPoint() # out variable
    worldDir = om.MVector() # out variable
    
    activeView = omui2.M3dView().active3dView()
    activeView.viewToWorld(int(screenX), int(screenY), worldPos, worldDir)
    
    return worldPos, worldDir
 
def getCameraWorldViewDirection():
    activeView = omui2.M3dView().active3dView()
    cameraPath = activeView.getCamera()
    fnCamera = om.MFnCamera(cameraPath)
    return fnCamera.viewDirection(om.MSpace.kWorld)

def doIntersect(pos):
    #Raysource rs, Raydirection rd
    rs = pos[0]
    rd = pos[1]
          
    print("Ray source:", rs[0], rs[1], rs[2])
    print("Ray direction:", rd[0],rd[1],rd[2])
    
    #position should be transform of selected object, if nothing selected it is 0 0 0, otherwise it should be selected dag object's world position to create object plane. I'll just implement view plane here 
    position = om.MPoint(0,0,0)

#View direction in world space is our plane's normal vector nPlane = getCameraWorldViewDirection() dl = rd * nPlane #Ray is on the plane or parallel to the plane, shouldn't be possible if dl == 0: dl = (position - rs)*nPlane if dl == 0: print "On the plane" else: print "Parallel" else: d = (position -rs) * nPlane / dl point = rs + d*rd print("Intersect with view plane at:",point[0],point[1],point[2]) def dragger_onPress(): pos = cmds.draggerContext(draggerContextName, query = True, anchorPoint = True) print("pos", pos[0],pos[1]) pos = viewToWorld(pos[0], pos[1]) doIntersect(pos) def dragger_onDrag(): pos = cmds.draggerContext(draggerContextName, query = True, dragPoint = True) print("pos", pos[0],pos[1]) pos = viewToWorld(pos[0], pos[1]) # get the first value of the tuple doIntersect(pos) if (cmds.contextInfo(draggerContextName, exists = True)): cmds.deleteUI(draggerContextName, toolContext = True ) cmds.draggerContext(draggerContextName, pressCommand = dragger_onPress, dragCommand = dragger_onDrag, cursor = "crossHair") cmds.setToolTo(draggerContextName)

Yours,

Li

 

Message 3 of 3

Anonymous
Not applicable

Hi Cheng!

 

Thank you for the detailed reply.

It wasnt clear to me earlier but I understand the difference now.

0 Likes