Camera Gimbal Orbit

Hello There.

This is a procedural Camera Gimbal code. May be useful if anyone wants to redefine Camera and mouse orbit behavior.

Any comments or advice are welcomed.

I reply myself:

Change the code, so it now is a simple class:

from panda3d.core import Vec3
from direct.task import Task
from direct.interval.LerpInterval import LerpPosInterval
from direct.showbase.ShowBase import DirectObject

class gimbal():
    def __init__(self, target_node):
        self.mouse = base.mouseWatcherNode
        self.mouse_enabled = False          # True when mouse2 is pressed, False on button release
        self.gimbal_enabled = True          # If set to False, "Mouse Move" task ends
        self.gimbal = target_node           # Target Node Path to rotate
        self.maxcamfar = -400               # Farest camera can zoom out
        self.mincamnear = -10               # Nearest camera can zoom in

        self.lastH = 0
        self.lastP = 0
        self.lastR = 0
        self.newx =0
        self.newy =0
        self.listener = DirectObject.DirectObject()

        taskMgr.add(self.MouseMove, 'Mouse Move')
        self.listener.accept('mouse2', self.MoveCam, [True])
        self.listener.accept('mouse2-up', self.MoveCam, [False])
        self.listener.accept('wheel_up', self.ZoomCam, [-1])
        self.listener.accept('wheel_down', self.ZoomCam, [1])
        self.listener.accept('mouse3', self.ResetCam)

    # Change target node to be rotated
    def Set(self, newgimbal):
        self.gimbal = newgimbal

    # Stop "Mouse Move" task and clear events listener 
    def Destroy(self):
        self.gimbal_enabled = False
        self.listener.ignoreAll()

    # Update target node rotation values while mouse2 is pressed
    def MoveCam(self,action):
        if not self.gimbal_enabled: return
        self.mouse_enabled = action
        if action:
            self.newx, self.newy = self.mouse.getMouseX(), self.mouse.getMouseY()
            self.lastH, self.lastP, self.lastR = self.gimbal.getH(), self.gimbal.getP(), self.gimbal.getR()

    # Updates target rotation values when mouse2 is pressed
    def MouseMove(self, task):
        if not self.gimbal_enabled: return Task.done
        if not base.mouseWatcherNode.hasMouse(): return Task.cont
        if self.mouse_enabled:
            currentx, currenty = self.mouse.getMouseX(), self.mouse.getMouseY()
            x, y = currentx-self.newx, currenty-self.newy
            self.gimbal.setHpr(0, self.lastP-(360*y*0.5), self.lastR-(360*-x*0.5))
        return Task.cont

    # Zoom in/out in mouse wheel events
    def ZoomCam(self,direction):
        if not self.gimbal_enabled: return
        zoom = 0
        current = base.cam.getY()
        if (direction == 1 and current > self.maxcamfar):
            zoom = (direction*(current))
        if (direction == -1 and current < self.mincamnear):
            zoom = (direction*(current/2))
        new = Vec3(0,current+zoom, 0)
        i = LerpPosInterval(base.cam, 0.3, new, blendType='easeOut').start()

    # Clean target node rotartion
    def ResetCam(self):
        if not self.gimbal_enabled: return
        self.gimbal.setHpr(0,0,0)

2 Likes