Trouble with my spin camera code

Hi,
I’m trying to write a program that will spin/rotate the camera to the left when I press the left arrow, and spin it to the right when I press the right arrow.

But for now, all I’m trying to do is get the camera to spin left when I press the left arrow. This is what I’ve come up with:

# spincameraclass.py
import direct.directbase.DirectStart
from pandac.PandaModules import*
from direct.showbase.DirectObject import DirectObject # To listen for events
from direct.task import Task # To use tasks
from direct.actor import Actor # To use animated actors 
import math # To use math 

class World(DirectObject):
    #Constructor
    def __init__(self): 
       # Reposition the camera
       base.disableMouse()
       camera.setPos(0,-15,7) # X = left & right, Y = zoom, Z = up & down
       camera.setHpr(0,-15,0) # Heading, Pitch, Roll
       
       self.loadModels() # Declare/name the new class methods you're going to use.
       # Setup key controls
       self.accept("escape", sys.exit)
       self.accept("arrow_left", self.SpinCamLeft)
       # end __init__

    def loadModels(self): # Define the new class method. Define what it does.
        # Load a model
        self.box = loader.loadModel("MODELS/box2")
        self.box.reparentTo(render)
        self.box.setPos(0,0,0)
        # Load an environment
        self.environ = loader.loadModel("MODELS/grassplain")
        self.environ.reparentTo(render)
        self.environ.setPos(0,0,0)
        # end loadModels
        
    def SpinCamLeft(self): # Define SpinCamLeft
        angledegrees = 1 * 50.0 # speed of rotation & direction
        angleradians = angledegrees * (math.pi / 180.0) 
        base.camera.setPos(30*math.sin(angleradians),-30.0*math.cos(angleradians),3) 
        base.camera.setHpr(angledegrees, 0, 0) 
        SpinCamLeft.start() 
        
# end class World

world = World()

run()

Now, when I run this code, the Panda window opens, but it closes the instant I press the left arrow. This message is then displayed on the command prompt:

Originally, I was using a task from the tutorials:

def SpinCameraTask(self,task): # Define the SpinCamera task 
        angledegrees = task.time * -50.0 # speed of rotation & direction
        angleradians = angledegrees * (math.pi / 180.0) 
        base.camera.setPos(30*math.sin(angleradians),-30.0*math.cos(angleradians),3) 
        base.camera.setHpr(angledegrees, 0, 0) 
        return Task.cont 

But it seems wrong to use a task for this, so I’ve tried to change it. Frustratingly, I have no idea what task.time represents, so I just made up a number for it.

I’m really struggling here, the tutorials just don’t go far enough to teach you how to control the camera. So any help would be most welcome.

Cheers

I think its that line:

SpinCamLeft.start()

if im correct you don’t needit and there is no module or object named SpinCamLeft.
This

 File "cameraspinleft.py", line 39, in SpinCamLeft
SpinCamLeft.start()
NameError: global name 'SpinCamLeft' is not defined

is telling you that that he doesn’t found something
Read errors carefull;)

Ok if tested the code:

  • i can run it
  • but i think there i a problem with the math afther the first call the coordinates are the same.

Thanks heaps Martin for taking the time to test this for me. I did what you suggested and removed the:


SpinCamLeft.start() 

And it now runs for me too :smiley:. But you’re quite right about the math, there’s something terribly wrong with it. You see, I have no idea what I’m doing, so I just copied the code from the ‘SpinCameraTask’ in the first tutorial. That task uses this line:


angledegrees = task.time * 50.0 

But because I’m not using a task for this, I can’t use ‘task.time’, and because I don’t know what ‘task.time’ represents (I can’t find anything about it in the API) I’m just trying different numbers instead of ‘task.time’ in a futile effort to make it work. Which of course, it doesn’t grrrr.

Anyway, this is what the code does now:
The Panda window opens normally, but the camera is zoomed up really close to my model. When I press the left arrow key, the camera positions itself at the correct distance from the model, but sadly it doesn’t spin or do anything else :imp:

So if somebody knows what I’m doing wrong, please point me in the right direction.

Cheers

task.time is the time of a task. How long it has been running.
You don’t have have it in a normal function.
Sorry im really bad in maths im not able to help you, but i guess Rainbow, Yellow,… are able to help you. Ask in the IRC there are many good people

IRC? Is it some kind of chat? How do I use it? And what is the best time to go on?

Sorry, but I’ve never used an IRC before :blush:.

Cheers

IRC is a chat protocoll. If you use Linux you probably have XChat installed.
XChat is aviable for Windows too. another popular irc program is MIRC.
Just start your program.
Connect to irc.freenode.net
type /join #Panda3D
and you are in the Panda chanel
then you can type your messages

Ah, I see. Thanks for explaining, I might have to give that a try if nobody here can help me.

Anyway, I’ve been experimenting with this some more, I tried getting rid of the number that replaced task.time, but still no luck.

# spincameraclass.py
# Use the Up & Down Arrow keys to zoom the camera In & Out.
# Use the Left & Right Arrow keys to rotate the camera.
import direct.directbase.DirectStart
from pandac.PandaModules import*
from direct.showbase.DirectObject import DirectObject # To listen for events
from direct.task import Task # To use tasks
from direct.actor import Actor # To use animated actors 
import math # To use math 

class World(DirectObject):
    #Constructor
    def __init__(self): 
       # Reposition the camera
       base.disableMouse()
       camera.setPos(0,-15,7) # X = left & right, Y = zoom, Z = up & down
       camera.setHpr(0,-15,0) # Heading, Pitch, Roll
       self.loadModels() # Declare/name the new class methods you're going to use.
       # Setup key controls
       self.accept("escape", sys.exit)
       self.accept("arrow_left", self.SpinCamLeft)
       # end __init__

    def loadModels(self): # Define the new class method. Define what it does.
        # Load a model
        self.box = loader.loadModel("MODELS/box2")
        self.box.reparentTo(render)
        self.box.setPos(0,0,0)
        # Load an environment
        self.environ = loader.loadModel("MODELS/grassplain")
        self.environ.reparentTo(render)
        self.environ.setPos(0,0,0)
        # end loadModels
        
    def SpinCamLeft(self): # Define SpinCamLeft
        angledegrees = 50.0 # speed of rotation & direction
        angleradians = angledegrees * (math.pi / 180.0) 
        camera.setPos(30*math.sin(angleradians),-30.0*math.cos(angleradians),7) 
        camera.setHpr(angledegrees, -15, 0) 
        
# end class World

world = World()

run()

Also it seems to me that:

camera.setPos(0,-15,7) # X = left & right, Y = zoom, Z = up & down
camera.setHpr(0,-15,0) # Heading, Pitch, Roll

and:

camera.setPos(30*math.sin(angleradians),-30.0*math.cos(angleradians),7) 
camera.setHpr(angledegrees, -15, 0) 

Are conflicting with each other. The program starts out with the camera zoomed in really close to the model, then when I press the arrow key, it seems like the second lot of camera code overwrites the first and the camera resets its position. But the darn thing still won’t spin :cry:.

I’d also like it if the camera codes matched each other, so that the camera stayed at the same coordinates it was originally set to. I just want the stupid thing to rotate on a fixed axis around my model.

Sorry, I’ve been struggling with this all day and I’m tired and frustrated. I just wish to Heaven somebody would write a proper ‘Camera’ tutorial.

Cheers

I don’t know if it works correct someone other told me that this is the math to do it.

from pandac.PandaModules import*
from direct.showbase.DirectObject import DirectObject # To listen for events
from direct.task import Task # To use tasks
from direct.actor import Actor # To use animated actors
import math # To use math
import sys

class World(DirectObject):
    #Constructor
    def __init__(self):
			# Reposition the camera
			base.disableMouse()
			camera.setPos(0,-15,7) # X = left & right, Y = zoom, Z = up & down
			camera.setHpr(0,-15,0) # Heading, Pitch, Roll
			
			self.loadModels() # Declare/name the new class methods you're going to use.
			
			self.angle= 0
			
			# Setup key controls
			self.accept("escape", sys.exit)
			self.accept("arrow_left", self.SpinCamLeft)
			# end __init__

    def loadModels(self): # Define the new class method. Define what it does.
				# Load a model
				self.box = loader.loadModel("panda")
				self.box.reparentTo(render)
				self.box.setScale(0.1)
				self.box.setPos(0,0,0)
				# Load an environment
				self.environ = loader.loadModel("MODELS/grassplain")
				self.environ.reparentTo(render)
				self.environ.setPos(0,0,0)
				# end loadModels
       
    def SpinCamLeft(self): # Define SpinCamLeft
				base.camera.setPos(math.sin(self.angle)*10, math.cos(self.angle)*10,3)
				self.angle+= 10
				if self.angle > 360:
					self.angle= 0
				#end SpinCamLeft
		
# end class World

world = World()

run()

Hope it helps
Martin

Thankyou so much for all the effort you’ve put into this Martin. It’s really great of you to try and help people like this.

I’ve just tested this code, but sadly, it still won’t work, and I got a really strange error message:

This one really has me baffled, how can base not be defined? Does anybody know what it means?

Cheers

*)do you run it via ppython
*)have you import Direct.DirectBase.DirectStart
maybe this will fix it

Oh! I am so stupid :blush: . I just copy and pasted your code from here, I didn’t even notice that ’ import Direct.DirectBase.DirectStart ’ was missing.

Thank Heavens you’re here Martin, I’d be completely lost without your help. Anyway, I’ve just run the code again and it WORKS!!! I can’t thankyou enough for this :smiley:.

The only problem now, is that the camera is spinning in place, making it seem like the ‘model’ is rotating around the camera (spinning in and out of view). What I’d like to do, is make the ‘camera’ rotate on an axis around the model.

I’ve done my best to illustrate what I’m talking about. This is what the code is doing now (camera rotates in place):

And this is what I’m trying to achieve (camera rotates on a fixed axis around the model):

This is much, much harder than I ever thought it would be, so thankyou again for all your help. I’m slowly getting there, little by little.

Cheers

Thats not as hard as it looks, simply create a dummy node on the models position, attach the camera to it and rotate the dummy node. Make sure you make the camera look at the model each frame ( camera.lookAt(self.model) ) by adding it you your rotation task.


from pandac.PandaModules import *
from direct.directbase import DirectStart
from direct.gui.DirectGui import *
from direct.interval.IntervalGlobal import *

class Viewer(DirectObject):

    def __init__(self):
        base.disableMouse()
        self.accept('escape',sys.exit)
        self.accept('o', base.oobe)

        self.model = loader.loadModel('panda-model.egg')
        self.model.reparentTo(render)
        self.model.setScale(0.05)
        
        self.dummy = NodePath('')
        self.dummy.reparentTo(render)

        camera.reparentTo(self.dummy)
        camera.setPos(0,-150,70)

        taskMgr.add(self.task,'task')

        rotate = LerpHprInterval(self.dummy, 60, Point3(360, 0, 0), startHpr=Point3(0, 0, 0))
    	rotate.loop()

    def task(self,task):
        camera.lookAt(self.model)
        

v = Viewer()
run()
1 Like

Oh wow!!! I think at last I’ve got it. I’ve finally got my camera to rotate around my model.

I looked through the solar system tutorial again for some ideas. This is what I came up with (it works!!! :smiley:):

# Test.py
import direct.directbase.DirectStart # Start Panda
from pandac.PandaModules import* # Import the Panda Modules
from direct.showbase.DirectObject import DirectObject # To listen for events
from direct.task import Task # To use tasks
from direct.actor import Actor # To use animated actors 
import math # To use math (angles, degrees..etc)
import sys 

class World(DirectObject):
    #Constructor
    def __init__(self): 
       # Reposition the camera
       base.disableMouse() # Must be called before any camera code will work.
       camera.setPos(0, -30, 3) # X = left & right, Y = zoom, Z = Up & down.
       camera.setHpr(0, 0, 0) # Heading, pitch, roll.
       
       # Declare/name the new global variables you're going to use.
       #Number of seconds a full rotation of the camera should take
       self.time = 10
       self.orbit = 0
       self.loadModels() 
       
       # Setup key controls
       self.accept("escape", sys.exit)
       
       #Finally, we call the rotateCamera function.
       self.rotateCamera()
       
       # end __init__

    def loadModels(self): # Define the global variable. Define what it does.
        #Create the dummy node
        self.camera_dummy_node = render.attachNewNode("camera_dummy_node")
        #Offest the camera dummy node so that it is positioned properly
        self.camera_dummy_node.setPos( self.orbit, 0, 0) 
        # Load a model
        self.player = loader.loadModel("MODELS/ralph")
        self.player.reparentTo(render) # Make it display/render on the screen.
        self.player.setPos(0, 0, 0) # Position it at the center of the world.
        camera.reparentTo(self.camera_dummy_node) # Attach the camera to the dummy node.
        # end loadModels
        
    def rotateCamera(self): # Define the rotateCamera function.
        self.leftRotate = self.camera_dummy_node.hprInterval((0.241 * self.time), Vec3(-360, 0, 0))
        self.leftRotate.loop()
        # end rotateCamera
        
# end class World

world = World()

run()

Note: I came up with this before I saw Yellow’s post. But I’m going to use Yellow’s code instead, because I think it’s much better than mine. Thanks very much Yellow.

Phew big sigh of relief it’s taken me days to figure this out. But I’ve learned more in these past few days than I could ever have imagined.

I can’t thank both of you enough. Without your help, I think I’d have given up by now. Martin and Yellow, you guys are terrific.

Thankyou heaps.

I know this thread is many years old, but I was having a similar issue. I wanted the camera to orbit around a model and I was doing it by changing the position and HPR of the camera (using lookAt). But then the camera was suffering from gimbal lock, which was a major nuisance. I’ve just implemented your method (which is far simpler than all the various methods I conjured up!) and it works like a dream!

Even 13 years on, you are still helping people, thank you very much!