Get p3d_ModelViewProjectionMatrix in Python

Hello all!

I’m implementing a deferred rendering pipeline in Panda and for the anti aliasing I’m implementing this technique. For that I need a velocity buffer and therefore the modelviewprojection matrix of the previous frame in my shader.

Now from what I read I should be able to get the modelview matrix by using node.getTransform(base.cam).getMat() and I should be able to get the projection matrix from a Lens.

I started by testing if I can replace this node.getTransform(base.cam).getMat() modelview matrix with p3d_ModelViewMatrix in my shader. Everything seems to be in the right place except that the shadows are reversed/ mirrored. It must have something to do with the z component but by playing around with that I can’t get it to work.

My question:

  • Is there a way to simply store the generated glsl p3d_ModelViewProjectionMatrix in Python so I can input it to the shader the next frame?
  • If not: How can I get the p3d_ModelViewMatrix and p3d_ProjectionMatrix in Python exactly as they are in glsl?

Note 2 configurational aspects:

  • I use gl-coordinate-system default #t in my config.prc
  • I use trans_view_of_cam_to_clip_of_light instead of ShadowViewMatrix for the deferred shader.

Any help is appreciated,
thanks!

Hi there! Good to hear from you again.

I’m afraid there is no way to obtain the matrix in Python, however, the method you’ve used should be sufficient to get the same matrix.

p3d_ModelViewMatrix is the same as trans_model_to_apiview, where apiview is view but with the coordinate system transformation for the API applied.

To make sure there is no difference between view and apiview, you can use the gl-coordinate-system as you have found, but you do need to use the correct syntax, which is this:

gl-coordinate-system default

However, I think Panda might still accept the syntax you’ve used, so this may not be the problem, but it’d be good to rule this out by using the correct syntax. Also, you need to be sure that this variable is set before the renderer is initialized (usually when the first window opens).

The other thing that comes to mind that I would check is the possibility that you are also applying the same matrix when rendering the scene from the shadow caster’s point of view. When rendering the scene from the light source, you need to have the matrix relative to the light source.

Hi Rdb,

Posting here has been some time indeed. Commonly I’m a steady, silent and happy Panda user working on an airline management game. Currently I’m working on a deferred pbr pipeline for this game but I will first complete it as a separate project and share with other Panda users. Before it’s ready for that I will probably run into some more questions.

Thanks for your quick answer!

gl-coordinate-system default

I corrected this just to be sure but indeed made no difference.

The other thing that comes to mind that I would check is the possibility that you are also applying the same matrix when rendering the scene from the shadow caster’s point of view. When rendering the scene from the light source, you need to have the matrix relative to the light source.

Ah yeah that is the problem ofcourse I completely overlooked this…

So then it seems I have no problem with getting the matrices but I’m experiencing a problem with the velocity buffer. The purpose of the velocity buffer of this anti aliasing technique is to reproject the previous frame over the current frame.

I use a 16 bit float velocity buffer (tex.getFormat() == 21, tex.getComponentType() == 2). In the vertex shader of nodes I have:

current_spos = p3d_ModelViewProjectionMatrix * p3d_Vertex;
previous_spos = previous_mvp_matrix * p3d_Vertex;

In the fragment shader of nodes I have:

vec2 velocity = current_spos.xy / current_spos.w - previous_spos.xy / previous_spos.w;
velocity *= vec2(0.5);  // Convert screen space to texcoords

In order to test/ observe the reprojection in a postprocessing buffer I do:

vec2 velocity = texture(velocity_tex, texcoord).rg;
vec4 current = texture(current_tex, texcoord);
vec4 previous = texture(previous_tex, texcoord + velocity);
vec4 color = mix(current, previous, 0.5);

And force a very low framerate:

globalClock.setMode(ClockObject.MLimited)
globalClock.setFrameRate(2)

Now I would expect near perfect reprojection but I still see quite some ghosting. It is absolutely in the right direction, the result is way better than without reprojection but it’s way more than a few pixels also on places where vertices are so I doubt it’s an interpolation issue.

Do you agree that my aim of an (almost) perfect reprojection is correct? Do you see any problems with the code I posted?

Thank you again!

It’s hard for me to tell what’s going wrong without being able to play with the code for myself. Nothing obvious is jumping out at me, and I must admit I’m not too experienced with this particular technique.

There will of course always be a slight difference with the reprojected image, especially with regards to fragments that were occluded in the previous frame.

You could try a 32-bpc format just to rule out floating-point imprecision as a possibility.

Occluded fragments or precision don’t seem to be the issue. Thanks for looking over it anyway!

Hi,

One more question regarding this separate matrices for rendering shadows. I’m using the Panda shadows with light.setShadowCaster. I’m guessing during rendering of the shadow buffer the vertex/fragment shader of a node will simply be invoked. How can I change the behaviour of the vertex/fragment shader during this rendering step or could I even apply a custom shaders to a node for this step?

One can apply custom shaders at the node-level, at least in OpenGL I believe.

        self.node = some_panda_node
        node_shader = Shader.load(Shader.SL_GLSL, "shaders/custom_v.vert", "shaders/custom_f.frag")
        self.node.set_shader(node_shader)

This is a minimal example case – one can also set shader inputs to the custom shader. The lights which you set on the custom shaded node will still take the regular inputs, like setting the shadow caster on with a certain shadow resolution, I believe.

What you’re looking for is setInitialState on the light node. That allows you to set camera-specific state.

If you need more fine control, look into tag states. These are described in the manual.

See Multi-Pass Rendering — Panda3D Manual

Yes that was what I was looking for thanks!