# camera orbiting around the point

Amazingly i could not find that kind of snippet anywhere. So i cranked up my rusty brain, remembered little trig i learned at school and made this self-contained snippet:

``````from direct.showbase.DirectObject import DirectObject
from math import pi, sin, cos

def clamp(val, minVal, maxVal):
return min(max(val, minVal), maxVal)

class OrbitCameraController(DirectObject):
def __init__(self, camera, distance=10, distance_limits=(5, 50), name='OrbitCameraController'):
self.camera = camera
self.distance = distance
self.distance_limits = distance_limits
self._is_rotating = False
self._rotate_start = (0, 0)
self._h = self._v = 0
self._vertical_limits = (-pi / 2 + 0.1, pi / 2 - 0.1)
self.accept('mouse3', self._setRotating, [True])
self.accept('mouse3-up', self._setRotating, [False])
self.accept('wheel_up', self.zoom, )
self.accept('wheel_down', self.zoom, [-1])
self._orbitCamera(0, 0)                                             # knock camera into orbit

def zoom(self, d):
self.distance = clamp(self.distance + d, *self.distance_limits)
self._orbitCamera(0, 0)

def _setRotating(self, rotating=True):
self._is_rotating = rotating
base.setMouseHidden(rotating)
if not rotating:
base.win.movePointer(0, *self._rotate_start)
else:
md = base.win.getPointer(0)
self._rotate_start = (md.getX(), md.getY())

if not self._is_rotating:

if not base.mouseWatcherNode.hasMouse():

md = base.win.getPointer(0)
old_x, old_y = self._rotate_start
dx = md.getX() - old_x
dy = md.getY() - old_y

if dx or dy:
base.win.movePointer(0, *self._rotate_start)
self._orbitCamera(dx, dy)

def _orbitCamera(self, dx, dy):
distance = self.distance
h = self._h - dx * 0.01
v = self._v + dy * 0.01
v = clamp(v, *self._vertical_limits)
posZ = sin(v) * distance
horizontal_plane_dist = cos(v) * distance
posX = cos(h) * horizontal_plane_dist
posY = sin(h) * horizontal_plane_dist
self._h = h
self._v = v
self.camera.setPos(posX, posY, posZ)
self.camera.lookAt(self.camera.getParent())``````

Camera orbits around it’s parent node. Zooming with mouse wheel works. Comments would be appreciated, especially on code in _orbitCamera(). I went most straight-forward way by using vertical (zy plane) and horizontal (xy plane) angles, and solved two triangles to get correct pos of camera. Maybe there is better way?

Here is what I’m currently using for my player camera. It parents an empty node to the target and sets the compass effect on it, and then parents the camera to that; no trig required! I still need to put in distance limits and implement collision with geometry.

``````class PlayerCamera(DirectObject):
def __init__(self, target, offset=(0,0,0), distance=50, sensitivity=40.0):
self.target = target
self.offset = offset
self.distance = distance
self.sensitivity = sensitivity
base.disableMouse()
self.slave = base.camera
self.origin = target.attachNewNode('Camera Orbit Center')
self.origin.setCompass()
self.origin.setPos(offset)

def enable(self):
base.win.requestProperties(HIDE_POINTER)
base.win.movePointer(0, base.win.getXSize()//2, base.win.getYSize()//2)

self.slave.setHpr(0, 0, 0)
self.slave.setPos(0, -self.distance, 0)
self.slave.reparentTo(self.origin)
self.slave.lookAt(self.origin)

self.accept('wheel_up',   self.slave.setY, [self.slave, 2])
self.accept('wheel_down', self.slave.setY, [self.slave, -2])

def disable(self):
base.win.requestProperties(SHOW_POINTER)
self.slave.wrtReparentTo(render)
self.ignoreAll()
thats really neat! i wasnt ware of setCompass(), thanks 