setting the camera, pluggable cameras

I am trying to create several different cameras that can be easily plugged in as the base.camera to switch the view of the scene.

I currently have a simple SphereCamera class (see pastebin.com/m81f9713 for full implementation if interested, but probably not necessary) that will follow a model nodepath around as it moves and can rotate around it. I currently handle this by simply calling base.camera.reparentTo(model) in the init method of SphereCamera and having functions like SphereCam.rotateRight() simply call base.camera.setPos and base.camera.setHpr. What I would like is to have SphereCamera extend Camera, change its own properties without any knowledge of base, and then in the main method of some other module be able to do something like

newCamera = SphereCamera(subjectmodel)
base.setCamera(newCamera)

Any idea how I can go about this?

Hmm, I guess you could call base.camNode.setActive(False) first. You could make your class inherit from Camera then and call setActive(True) on the camera node of your choice.
(Note that you can call base.makeCamera in the constructor, and if you do so, it will get attached to base.camera (so if you move around base.camera rather than the individual camera, all cameras will be affected))

Ok, great. Thanks. I think that will do it.

Given a camera object, is there a way to get a node from it? I’m trying to just have SphereCamera hold a camera by calling self.camera = Camera(“CameraName”) in the init method and then changing all of my calls to base.camera.setPos etc to self.camera.setPos etc, but Camera itself doesn’t have a setPos method.

Camera is a kind of PandaNode. setPos is a method of NodePath, not PandaNode. If you have a Camera, you can call setPos() on it just by wrapping it in a NodePath:

myCam = Camera('cam')
myCamNP = NodePath(myCam)
myCamNP.setPos(x, y, z)

It sounds like the behavior you want to modify is the interface of NodePath, not Camera (base.camera is a NodePath, for instance). But it also seems a little weird to be subclassing in order to achieve this.

David

Awesome. Thanks drwr and pro-rsoft! That’s exactly what I needed. And you’re right drwr, I didn’t end up needing inheritance to get the functionality I wanted.

One strange thing though: I tried calling “base.camNode.setActive(False)” in the main method and then “self.cameraNP.setActive(True)” in the SphereCamera class, but I ended up with a grey screen. When I removed the “base.camNode.setActive(False)” call though, everything worked as expected. That’s perfectly fine for me, but I thought I should mention it.

Thanks again!

I think you are again confusing nodes and NodePaths. setActive() is a method on Camera, not on NodePath. I don’t think there even exists a NodePath.setActive() method, so I’m surprised you didn’t get an exception when you called it. Assuming your self.cameraNP object is a NodePath, of course.

David

Sorry. That was a typo. The code block looks like

        self.camera = Camera("Sphere Cam")
        self.camera.setActive(True)
        self.cameraNP = NodePath(camera) 

The rest of what I said still holds.

Well, simply creating a new camera (and setting it active) doesn’t associate it with the screen, or replace the original camera. There might, after all, be many cameras in the world, all of which are viewing different scenes and rendering to different windows or offscreen buffers. (See the manual page on DisplayRegion for more information about connection cameras to windows.)

If you want to replace the main camera and render with your new camera instead, you have to either create a new DisplayRegion as well, or hijack the original DisplayRegion that was created for the main camera. But I’m not sure there’s any real value to that; you can just point at the main camera instead of completely replacing it.

David