Rotating A Node Via Mouse Position

I’m attempting to implement a function which rotates a node based on how far the mouse is moved while the right mouse button is down.

My initial attempt is as follows (self.cameraLook is the node I’m attempting to rotate):

def rotateBoard(self, task):
     if base.mouseWatcherNode.hasMouse():
         currentMouseX = base.mouseWatcherNode.getMouseX()
         currentMouseY = base.mouseWatcherNode.getMouseY()
         
         if self.mouse3down is True:
             if self.mousePosX != currentMouseX \
                and self.mousePosY != currentMouseY:
                 
                 xVal = (self.mousePosX + currentMouseX) * self.mSensitivity
                 yVal = (self.mousePosY + currentMouseY) * self.mSensitivity
                 
                 self.cameraLook.setH(xVal)
                 self.cameraLook.setP(yVal)
                 
         self.mousePosX = currentMouseX
         self.mousePosY = currentMouseY
                 
     return Task.cont

However there are a few problems, the first being that when the mouse is moved slowly, the rotation is very choppy and sometimes doesn’t rotate at all until I speed up the movement. The second problem is that it seems to be taking the mouse position into consideration rather than just the distance between the last position and the current, because its rotation varies depending upon where on the screen you start.

I realize the proper way to do this would be with rotation matrices but unfortunately I dont know anything about that sort of math. There may even be a higher level way of doing this built into Panda but its my first time using it as well as programming in Python and I haven’t found anything in the manual. Any help would be appreciated, thanks!

After briefly looking at your code it looks ok. I imagine you’d want to reset the mouse position each frame when the middle button is held down though, and then get the delta? That might eliminate your position dependacy issues. I got a feel for using mouse interaction in panda by manipulating the mouse code in the normalmapping sample (check your smaples folder) - that may help you.

Thanks for the pointer to the NormalMapping demo, that does get me a good bit closer to what I’m looking for and I’ve stripped down their camera control function to remove the stuff I didn’t need and now I’ve got a question.

In this part of the code:

        md = base.win.getPointer(0)
        x = md.getX()
        y = md.getY()
        
        if base.win.movePointer(0, 100, 100):
            self.heading = self.heading - (x - 100)*0.2
            self.pitch = self.pitch - (y - 100)*0.2
        
        self.cameraLook.setHpr(self.heading,self.pitch,0)

I think I just have a basic misunderstanding of this code, I’m not really sure why the pointer needs to be moved away from its current position. The problem is that I only run this code when the right mouse button is down and then whenever they lift the mouse button, the cursor starts back up at 100,100 rather than where the cursor was when they first started the orbit. I’ve tried putting:

base.win.movePointer(0, x, y)

at the end of the function to move the pointer back to where it was but it just sends the camera into a rapid spin.

I’ve done a model viewer kind of thing where you rotate the model around to look at it from different angles. I’m using quaternions and it rotates pretty smoothly.

    def viewTask(self, task):
        if not base.mouseWatcherNode.hasMouse():
            return task.cont
        
        if self.click:
            mpos = base.mouseWatcherNode.getMouse()
            
            cursor = base.win.getPointer(0)
            mouseX = cursor.getX()
            mouseY = cursor.getY()
            
            moveX = self.cursorPos[0] - mouseX
            moveY = self.cursorPos[1] - mouseY
            
            base.win.movePointer(0, *self.cursorPos)
            
            multiplier = -1
            
            newPitch = Quat()
            newPitch.setFromAxisAngle(moveY * multiplier, Vec3(1, 0, 0))
            newHeading = Quat()
            newHeading.setFromAxisAngle(moveX * multiplier, Vec3(0,0,1))
            
            self.modelControl.setQuat(self.modelControl.getQuat(render) * newPitch * newHeading)
        
        return task.cont

Nice, ZeroByte :stuck_out_tongue: I’m sure this will help out Oleyb

ZeroByte, if I understand it, “self.cursorPos” should be set to an arbitrary point on the screen, correct?

Your solution is really close to what I’m looking for but I’m still having the problem that once self.Click is false, the cursor is forced to whatever point you set “self.cursorPos” due to the calling of “movePointer()”. Is it at all possible to do this without forcing the pointer away from wherever the user had it when they first clicked?

I solved my problem. In the function where I set self.click to true I record the current X and Y of the cursor and use that as the arbitrary point to move the mouse to in the actual rotating function and it works like a charm.

Thanks for the help everyone!