Problem when loading a scene after Panda MainLoop

I’m working on my own scene viewer/editor program and lately added Qt4 MainWindow so that I can Open a Scene file (xml file) and load a scene.

My problem now is that if I load a scene after a call to the Panda MainLoop framework.do_frame(current_thread) then my water plane (part of my scene, lakes on the terrain) is rendered incorrectly and I get these prints repeated as if a task is running:

Assertion failed: !mat.is_nan() at line 286 of :\panda3d-1.7.0\panda\src\pgraph\transformState.cxx
Assertion failed: has_mat() at line 585 of c:\panda3d-1.7.0\built\include\transformState.I
Assertion failed: has_mat() at line 585 of c:\panda3d-1.7.0\built\include\transformState.I
Assertion failed: has_mat() at line 585 of c:\panda3d-1.7.0\built\include\transformState.I
Assertion failed: has_mat() at line 585 of c:\panda3d-1.7.0\built\include\transformState.I

… and it continuously repeats like those messages above …

The call that causes this is: region->set_camera(mWaterCamera);

here is that area of code:

    // reflection plane
    Planef waterPlane(LVector3f(0.,0.,1.),LPoint3f(mPos.get_x(),mPos.get_y(),mPos.get_z()));
    mWaterPlane = waterPlane;
    PT(PlaneNode) planeNode = new PlaneNode( "WaterPlane" );
    planeNode->set_plane(mWaterPlane);


    CPT(RenderAttrib) cfa = CullFaceAttrib::make_reverse();

    CPT(RenderAttrib) cpa = ClipPlaneAttrib::make(ClipPlaneAttrib::O_add,planeNode);

    CPT(RenderState) rs = RenderState::make(cfa,cpa);

    PT(Camera) cam = new Camera("WaterCamera"); 
    cam->get_lens()->set_fov(mCamera->get_lens()->get_fov());
    cam->set_initial_state(rs);

    mWaterCamera = rootNode.attach_new_node(cam);

    // Buffer and reflection camera
    GraphicsOutput *buffer = window->get_graphics_output()->make_texture_buffer("WaterBuffer", mNumPix, mNumPix); 
    buffer->set_clear_color(Colorf(0.,0.,0.,1.));

    DisplayRegion *region = buffer->make_display_region();
    region->set_camera(mWaterCamera);
    region->set_active(true);

Everything works file if I load a scene before the MainLoop.

Thanks for any help,

tim

The error message means that someone somewhere deep within the render call has been fed a bogus LMatrix4f value; this usually happens due to an invalid pointer somewhere.

One trick that may help diagnose it is to put the line:

assert-abort 1

in your Config.prc file, then run your program within the debugger. This config setting will make the assertion reporting code trigger an exception, which will invoke the debugger and allow you to get a stack trace at the time of the exception. From the stack trace, you may be able to determine what matrix, in particular, has gone bad; and that may help you to figure out the bigger cause.

David

Wow, Thanks for the quick reply.

Added the assert-abort 1 which cause things to stop and display the popup, when I bring up the debug I only see the assembly ( since I compiled in release )
021EDFCC mov dword ptr [eax],1
is the line that it flags.

I’ve read on the forum that one needs to compile all of Panda to get a debug stack. Is that the next step for me ?

I’ve been weeding down my scene to just terrain, water, and viewer controls.

Thanks again,

tim

Hmm, you should be able to see the stack in your own code, even if you compile in release mode, because debugging symbols are available to you. But it’s true, you won’t see the stack in Panda code, unless you compile Panda yourself, because we don’t provide the debugging symbols as part of the Panda installation (they’re really big files). That’s a bit unfortunate.

But maybe it’s not too bad. If you’re already working in C++, you shouldn’t be afraid of compiling Panda, and it’s pretty much automatic. And you still don’t have to compile in debug mode, you’ll get debug symbols even in release mode. So why not give this a try?

David

I continued to reduce my code to see if I could find where it went wrong ( before trying the debug compile)
I found something interesting involving the camera lens field of view. If I set the camera’s FOV before a call to framework.do_frame(current_thread); and then do a get_fov on the lens, the vertical or y part of the FOV gets set to zero some how, then this caused a problem when I got this FOV and set it in my water camera that got set into the region.

below is a simple main program that will print the FOV before and after the call to do_frame:

#include <pandaFramework.h>
#include <pandaSystem.h>

int main(int argc, char *argv[]) {

  PandaFramework framework;

  framework.open_framework(argc, argv);

  WindowFramework *window = framework.open_window();

  Camera *mCamera = window->get_camera(0);

  PT(Lens) lens = mCamera->get_lens();

  lens->set_fov(60.,60.);

  LVecBase2f fov = lens->get_fov();
  printf("before do_frame fov:%f %f\n",fov.get_x(),fov.get_y());

  // Causes a problem if these two are done after lens->set_fov(60.,60.);
  Thread *current_thread = Thread::get_current_thread();
  framework.do_frame(current_thread);

  fov = lens->get_fov();
  printf("after do_frame fov:%f %f\n",fov.get_x(),fov.get_y());

  while (framework.do_frame(current_thread)) {
  }

  framework.close_framework();

  return (0);

}

I didn’t follow everything you described, but could this be the fault of the auto aspect-ratio adjustment that is called when the window opens, and attempts to match your camera FOV to the actual window shape?

You can disable this automatic behavior by putting the line:

aspect-ratio 1

in your Config.prc file.

David

I just tried aspect-ratio 1 in config file but still prints out a zero value for the fov.get_y().

in a nut shell:

lens->set_fov(60.,60.);

LVecBase2f fov = lens->get_fov();
printf(“before do_frame fov:%f %f\n”,fov.get_x(),fov.get_y());

it prints 60. 60. for the FOV

Thread *current_thread = Thread::get_current_thread();
framework.do_frame(current_thread);

fov = lens->get_fov();
printf(“after do_frame fov:%f %f\n”,fov.get_x(),fov.get_y());

now it prints 60. 0. for the FOV

Ah, I just tracked this down; there is indeed a bug within the two-parameter form of lens->set_fov(). It is setting some internal flags incorrectly, leading to a subsequent error in get_fov().

As a workaround, use the one-parameter form of lens->set_fov() instead, e.g. lens->set_fov(60.). You’ll still want to set “aspect-ratio 1” in your Config.prc to avoid the aspect ratio getting reset to match the window shape in any case.

David

okay, thanks for the update.
I was actually setting the FOV to 60.,45. in my SceneViewer program, but I can just save that in a member LVecBase2f in a class and use that when setting the water camera FOV, or maybe I’ll make the water camera be square and get the FOV like you said.

Thanks for all your help again :slight_smile:

tim

Or you can put “aspect-ratio 1.3938” in your Config.prc, which is the aspect ratio that corresponds to 60,45.

In general, if you do not have an explicit aspect ratio set in your Config.prc file, then Panda’s default behavior is to set the aspect ratio automatically whenever the window is resized (or when the window is initially opened). Thus, if you try to set the aspect ratio in code, via e.g. a two-parameter setFov() call, that setFov() setting will be modified automatically whenever the window changes (especially if you try to do this before the window is first opened).

If you do set an explicit aspect ratio, then Panda won’t automatically adjust the lens, and will leave it however you set it.

So another answer is to set “aspect-ratio 1” in your Config.prc file and replace your two-parameter setFov() call with:

lens.setFov(60)
lens.setAspectRatio(1.3938)

which is equivalent to lens.setFov(60,45), and also avoids this bug.

Though 60,45 is an unusual choice for lens FOV, but I assume you have some reason to set such an unusual aspect ratio. :slight_smile:

David

Hi guys,

I think you just pin pointed one of the issue I’ve been encountering for the past few weeks.

The symptom is similar, although not totally identical.
Here it is :

I have set two cameras with specific lens :

lens1 =DCAST(PerspectiveLens,cam1->get_lens());
lens1->set_film_size(Width,Height);   // set film size

lens2 = DCAST(PerspectiveLens,cam2->get_lens());
lens2->set_film_size(Width,Height);   // set film size

Then later on, in the main loop I use depending on some conditions…

	
lens1->set_focal_length(f);      // set focal
lens1->set_film_offset(dx,dy);	 // set film offset
lens1->set_near(d_near);	 // set near plane

lens2->set_focal_length(f);      // set focal
lens2->set_film_offset(dx,dy);	 // set film offset
lens2->set_near(d_near);	 // set near plane

Note that my FOV is hence supposed to be defined by film_size and focal.

The issue and weird behaviour is that although this seems to work fine BUT as soon as I click on a non Panda Windows on my desktop, the whole lens set-up is changed and the perpective is shrinked (actually it seems that the focal value is changed…)

After reading your post, I tried David’s suggestion to include in config my aspect ratio which by the way is 1.272727 ie (140/110).
But this doesn’t solve the issue!

So the point is How to stabilize the lens set-up and avoid it to be sporadically screwed up by moving the mouse outside the main window???

Hmm, the only thing Panda will change automatically is the aspect ratio, and that only if you don’t have aspect-ratio set explicitly. Since that didn’t solve the problem, it must be something else.

Is the focal length number actually changing? That is, if you query lens->get_focal_length() after the apparent change, does it return a different number?

David

Just checked => the focal value doesn’t change !!

But the screen aspect is such that it looks like the focal would have increased.

I’m juszt thinking: maybe the focal doesn’t change but the film size does!

I will have a look later on.

Well, checked too the film size with an AsyncTask :

std::cout << "f_M:" << lens_0->get_focal_length() << " f_L:" << lens1->get_focal_length() << "\n";
std::cout << "s_M:" << lens_0->get_film_size() << " s_L:" << lens1->get_film_size() << "\n";

On my 2 cameras 1 & 2 neither the film_size or the focal change. (ie focal: 240 screen_size:140x110)

on camera0 (which happen to be the default Panda3D camera), I originally set up with the same values as the 2 others ones (f:240 and film_size: 140x110),
I have the same focal, but the film_size has moved to a value which is 908x742 (ie 1.2237 ratio). I don’t have a clue on where this comes from??

just for reference my window size (screen not film!) as defined in config is

load_prc_file_data("", "win-size 1024 768");

BTW.I just realized that in order to see the print out I shrinked the main window so the 908x742 could well be the new window size on my pc screen. (EDIT: ok just checked: the value seems to be the screen window size!)

If this is the case, it looks like the main camera is changing its film size to the window size (just guessing), which should be somewhat unrelated…

Second part of the story: Once this first change has occured, then none of the lenses values (for the 3 lenses) change, but on the main camera I have the clear feeling that everytime I click on a window outside the main panda window the perspective is getting deeper. (maybe ‘y’ is changing?)

Ah, hmm, it appears that the C++ framework code is indeed setting the aspect ratio by setting the film size (but only if you didn’t set aspect-ratio). So perhaps you didn’t quite set the config variable in the right place? You can put code like:

cerr << ConfigVariableDouble("aspect-ratio") << endl;

to print out the values that it is reading.

But in any case, you can avoid this whole window callback altogether by changing the window event on your window:

wf->get_graphics_window()->set_window_event("custom_event");

David

Thanks David,

I just included the suggested change, ie

	
window = framework.open_window();			 // open the window
window->get_graphics_window()->set_window_event("custom_event");// block callback side effect on film size...

And the film_size is now kept constant!

Thanks (once again) for your help.