[solved] Basic First Person camera controls

Hello, I am fairly new to panda, however have some experience with openGL and other 3D engines. I am trying to set up a basic walk function that simply moves the camera forward in whatever direction it is facing.

    def walk(self):
        dir = base.camera.getMat().getRow3(1)
        dir.setZ(0)
        dir.normalize()
        self.pos += dir * self.speed
        base.camera.setPos(self.pos)    

Theoretically this should work, the problem seems to be with the first line, it does not correctly return the camera’s direction vector, it always returns (0,1,0). Am I using the getMat() function incorrectly? or is there a better way to retrieve the camera’s current direction? Any help would be appreciated!

The line you need is:

base.camera.getNetTransform().getMat().getRow3(1)

The line you are using is fetching the local transform, which is not combined with all the other transforms of all the parent nodes of the camera.

I actually tried that already yielding the same results of (0,1,0) for the direction vector

In that case, I don’t know what to tell you. That’s the same code I use in the roaming ralph tutorial, and it works fine.

I’ve used another way to get my direction vector:

I reparented a node in front of the camera, and calculated the vector from the camera to the node in world space.

This way, the node always stays in front of the cam, so does your vector.

Simple, but effective…

It seems that the camera’s position is getting reset each time through the loop, however, my mouse controls work fine, I can look around freely. I just cannot walk forward.

Here is all of my code for mouse and keyboard controls

########################################
##  Handles Mouse Input and Controls  ##
########################################
class Controls(DirectObject):
    def __init__(self):
        self.mouseChangeX = 0
        self.mouseChangeY = 0
        self.windowSizeX = base.win.getXSize()
        self.windowSizeY = base.win.getYSize()
        self.centerX = self.windowSizeX / 2
        self.centerY = self.windowSizeY / 2
        self.H = base.camera.getH()
        self.P = base.camera.getP()
        self.pos = base.camera.getPos()
        self.sensitivity = .5
        self.speed = .2
        
    def movement(self, task):
        mouse = base.win.getPointer(0)
        x = mouse.getX()
        y = mouse.getY()
        if base.win.movePointer(0, self.centerX, self.centerY):
            self.mouseChangeX = self.centerX - x
            self.mouseChangeY = self.centerY - y
            self.H += self.mouseChangeX * self.sensitivity
            self.P += self.mouseChangeY * self.sensitivity
            base.camera.setHpr(self.H , self.P, 0)
            
        self.accept("w", self.walk)
        return Task.cont

    def startMovement(self):
        base.win.movePointer(0, self.centerX, self.centerY)
        taskMgr.add(self.movement, 'movement')

    def stopMovement(self):
        taskMgr.remove('movement')
        
    def walk(self):
        dir = base.camera.getNetTransform().getMat().getRow3(1) 
        dir.setZ(0)
        dir.normalize()
        self.pos += dir * self.speed
        base.camera.setPos(self.pos)
        
controls = Controls()
controls.startMovement()

For some reason when I print the cameras position in the walk function, it is always (0,0,0) and its direction is always (0,1,0). Am I resetting something somewhere that I am unaware of?

Thanks for all your help by the way!

Did you call

base.disableMouse( )

when setting up Panda3D?
If not Panda3D will use a default mouse or trackball interface which makes it impossible to move camera from your code.

More information is here:
http://panda3d.org/manual/index.php/Mouse_Support
http://panda3d.org/manual/index.php/The_Default_Camera_Driver

enn0x

Thank you so much! That fixed it!