wrong base.camera.getPos() values returned?[solved]

hi all.

i sort of hit a strange problem. i have a set of nodes in my world. every 16 panda units one one in all 3 directions. the camera’s position is always relative to the node nearest. so if the cam’s distance to a node center is >16 it’s reparented to the next node.
it’s a little bit difficult but it works fine so far.
i run all this in a task. and when it changes the block the camera is getting reparented and everything is fine. but when the tasks runs for the next time and asks for base.camer.getPos() it returns the wrong value, even if you explicitly tell him which node he should use as parent. (where camera.getParent() returns the right value, the position of the parent is correct and the position of the camera relative to render seems to be right,too).
did i do anything wrong or can anyone tell what’s wrong?
code-> home.arcor.de/positiveelectron/f … 8online.py
the relevant code should be between the lines 70-80 and near the end.

thx for any hints =)
ps: please excuse the somewhat un-estetically coding style

Yes, this camera stuff annoyed me too, but that’s history. I have my camera animated using an interval, and the interval must be able to be replayed at anytime. Actually, I animate base.cam, I reserve base.camera to move base.cam using the standard mouse controlled camera movement, so that the camera interval and mouse input camera movements can be done simultaneously and seamlessly, and moreover, after any mouse controlled camera movement happened, the camera interval starts exactly at the correct position.
Being annoyed, I did a little search, and I found something kind of stabbed my back, it’s base.mouseInterfaceNode.
I’ve implemented it in my new code https://discourse.panda3d.org/viewtopic.php?p=10863. Yes, you’ve seen that before, but at the time you read it, I haven’t use any camera interval. I know, it’s not actually the same case, but if you’re interested, check that out.

it’s not about animating it. it’s about the position reported from the camera after it reeing reparented.

In my code on the link, before using base.mouseInterfaceNode.reset(), I used base.camera.setPos(0,0,0) to reset it’s pos before starting the interval, but… guess what ? it was back to the last pos, which the movement is done by mouseInterfaceNode.
Now I’m sure, base.camera is the node used by mouseInterfaceNode to grab base.cam, and it’s position is reset to (0,0,0) after you call run(). So, as long as there is not any pointing device controlled camera movement take place, it will always remain (0,0,0). You may want to directly move base.cam instead.
Oh, try this :

import direct.directbase.DirectStart
from pandac.PandaModules import Camera
from direct.task import Task

def camTask(task):
    print base.camera.getPos()
    return Task.cont
smiley=loader.loadModel('smiley')
smiley.reparentTo(render)

base.camera.setZ(200)
base.camera.setP(-90)
# now you should be able to see the smiley, but camera pos is reset after call run(), try to zoom out !

print base.camera.getPos()

taskMgr.add(camTask, '')

run()

same problem. thought the behavior is a little bit different.
could it be that getPos() gets the position of the previous frame instead of the current one?

Doesn’t make any sense.
In line 81 (before reparenting) :

print base.camera.getPos(render)

and
in line 144 (after reparenting) :

a = base.camera.getPos()
print a

You print your cam pos in render coord system before you reparent it ?

Try :

import direct.directbase.DirectStart
from direct.showbase.DirectObject import DirectObject
from pandac.PandaModules import Camera, CardMaker
from direct.task import Task

class World(DirectObject):
  def __init__(self):
      cm=CardMaker('')
      cm.setFrame(-1,1,-1,1)
      floor=render.attachNewNode(cm.generate())
      floor.setScale(20)
      floor.setP(-90)
      floorTex=loader.loadTexture('maps/envir-ground.jpg')
      floor.setTexture(floorTex)

      taskMgr.add(self.camTask, '')
      self.smiley=loader.loadModel('smiley')
      self.smiley.reparentTo(render)

      base.camera.reparentTo(self.smiley)
      base.cam.setPos(0,-4,2)
      base.cam.lookAt(0,0,0)

  def camTask(self,task):
      self.smiley.setY(task.time*.5)
      print '=============================='
      print 'smiley:',self.smiley.getPos()
      print 'camera:',base.camera.getPos(render)
      return Task.cont


World()
run()

was just for debugging to see what’s going on there.
hm. and about your code… i see it’s working but the problem with my code is: i reparent the camera during the game, based on it’s position. if the position is not correct in the next frame it will be reparented again and again and and and… so i thought about running my function/task every n-th frame… but i have no real idea how to do that, those tasks things irritates me… any way to call a function every n-th frame?

I bet you’re still using base.camera. For your scene, you’re not gonna need it. Have you tried to use base.cam instead ? It must be working, because it’s the direct path to the camera itself. You can use doMethodLater to repeat itself every n-th seconds, at the end of the method, call itself using doMethodLater, it’s simple recursion.

I think I can duplicate your problem, more or less :

import direct.directbase.DirectStart
from direct.showbase.DirectObject import DirectObject
from pandac.PandaModules import Camera, CardMaker, Point3
from direct.showbase import PythonUtil as PU
from direct.task import Task
import random

class World(DirectObject):
  def __init__(self):
      cm=CardMaker('')
      cm.setFrame(-1,1,-1,1)
      floor=render.attachNewNode(cm.generate())
      floor.setScale(10)
      floorTex=loader.loadTexture('maps/envir-ground.jpg')
      floor.setTexture(floorTex)

      self.smileyList=[]
      self.parent=0
      for x in range(7):
          for z in range(7):
              smiley=loader.loadModelCopy('smiley')
              smiley.reparentTo(render)
              smiley.setScale(.5)
              smiley.setPos(random.randint(-3,3),0,random.randint(-3,3))
              self.smileyList.append(smiley)

      self.smileyList[0].setPos(0,0,0)
      self.smileyList[0].setColor(1,0,0,1)
      base.cam.reparentTo(self.smileyList[0])
      base.cam.setY(-40)

      taskMgr.add(self.smileyTask, '')
      taskMgr.add(self.camTask, '')

  def camTask(self,task):
      minDist=1000
      parent=-1
      for i in range(len(self.smileyList)):
          dist=(self.smileyList[i].getPos()-base.cam.getPos(render)-Point3(0,20,0)).length()
          if i!=self.parent and dist<.7 and dist<minDist:
             minDist=dist
             parent=i
      if parent>=0:
         self.smileyList[self.parent].setColor(1,1,1,1)
         self.parent=parent
         base.cam.wrtReparentTo(self.smileyList[parent])
         self.smileyList[parent].setColor(1,0,0,1)
      taskMgr.doMethodLater(.3,self.camTask,'')

  def smileyTask(self,task):
      for i in range(len(self.smileyList)):
          posX=self.smileyList[i].getX()+random.gauss(0,.03)
          posZ=self.smileyList[i].getZ()+random.gauss(0,.03)
          posX=PU.clampScalar(posX,-2.5,2.5)
          posZ=PU.clampScalar(posZ,-2.5,2.5)
          self.smileyList[i].setPos(posX,0,posZ)
      return Task.cont

World()
run()

The red one is the current parent.

i tried .cam too. and it’s not as bad as .camera. it doesnt jump to infinity but it jumps for and backwards. maybe i can use my playermodel in place of the camera, dunno if same occurs.
btw,… all the random stuff in your code… confuses me^^ actually reproducing the error wont be that usefull^^ knowing how to get the correct values would be ways better (and it should work if one or two frames passed between my updating stuff).
so again. any idea how to execute a function every n-th frame?

hm… just tried the do later task… well i dont really know how to set them up. as far as i can see they are for one-time usage. and calling a the own do-later task in the task causes a error after a while. i tried messing around with time.sleep() but this seems to lock panda.
:confused: it cant be that hard can it??
sight heeeeeeelp

thx a lot IPKnightly!
now my code runns only twice a second which is by far enough and the reported values are correct. my code is still buggy but one big problem less.
your code will be used quite a lot in the network stuff,too :slight_smile:

Do you guys know about:

base.disableMouse()

? This turns off the MouseInterfaceNode, which by default will attempt to reset the position of base.camera every frame if you don’t turn it off.

David

it RESETS the mouse!?.. omg. no wonder^^. i always thought it would juse change it’s position . thx for the hint!

No, that’s what I mean. It changes the position and orientation of the base.camera node every frame–back to where it thinks it ought to be, regardless of where you try to put it. Then when you query its position, depending on the point in the frame at which you queried it, you may get the value you put in there, or you may get the value the MouseWatcherNode set it back to.

David

hm… but what happens if i dont change the camera’s position but only it’s parent? i mean the parent is reported correctly… anyway. in case it’s using the position of the previous frame i now execute the code only a few times per second. and the camera resets should be no problem after i disabled the default camera. or at lest i hope so :stuck_out_tongue:
ok =) after cleaning up a few lines and disabling the default camera it works now =)
thx for all your help&efforts!