GLSL, texture projection

Hi,

As the subject says, I experience problem with texture projection in GLSL.

My eventual goal is to write spotlight and directional light shadows in GLSL (I already have those in Cg), but I wanted to start by projecting a simple texture over an even simpler scene. And I got stuck.

Below is a sample showing the problem. The shader kind of works, but there’s one major problem with it. When you move the camera, the nicely projected texture (apparently randomly) turns into static noise…

I would think it’s a matrix issue if it wasn’t that the entire thing seems rather random.

If I deliberately screw up the matrices I get coherently bad results – the texture is projected from the camera, instead of the intended projector, or the texture looks like a set of parallel lines, or it’s just projected top down on the floor, disregarding the lens completely.

But with the issue at hand, this is not the case. The texture looks good at one camera position, while moving the camera a millimeter in any direction brings in the static.

I’m a bit lost and out of ideas, basically… :slight_smile:

Sample:
dl.dropbox.com/u/196274/glsl/glslProjected.zip

My spec:
Ubuntu 12.04, 64 bit, fully updated
GF GTX 460
NVidia drivers version 310 (from ubuntu repos, marked as experimental yet battle tested with a significant portion of what is available on Steam for Linux).

Thanks in advance for any input on this.

I would advise not to use projectTexture with gl_TextureMatrix when using GLSL. It is not a very efficient method. Instead, you should construct your own projection matrix in the vertex shader, like in the numerous example shadow shaders.

That said, it would appear that there is something wrong in the way gl_TextureMatrix is passed to the shader, which merits further investigation.

For what it’s worth, texture2Dproj is the same as texture2D except that the fourth coordinate first undergoes a perspective division. So, first dividing by shadowCoord.w and then passing it to texture2Dproj is unnecessary.

I know there are better ways to do it. However, all shadow examples I could find over the net focused on providing the right textures to the shader, rather than generating them inside the shader. I’m actually in doubt whether computing them inside the shader is even possible… Perhaps I’m wrong, or just spoiled by the vast range of matrices provided in Panda’s Cg, but I really can’t think of a way to arrive at a projection matrix inside the shader without providing it as shader input.

Still, even if projecting textures this way is suboptimal, I think it’s still worth being persuaded to work correctly :slight_smile:. And, in the meantime, I’ll try finding a way to get correct texture projection by other means :slight_smile:.

I’m not talking about making a texture in the shader, but constructing the shadow coordinates based on the light matrix which is a usually constant matrix passed in as a uniform.

Look at how shadow.sha in the Shadow sample does it, for instance - it transforms the vertex position into the clipspace of the light, and then calculates the shadow coordinates based on that.

I know you’re not talking about making the texture in the shader :slight_smile:.

What I mean is that I have to get a couple of matrices into the shader anyway. The one that comes in when I do setShaderInput(“myMatrix”, myLight) won’t cut it, I suppose.

I understand, thought, that computing the final matrix out of them in the shader will be faster than doing that in Panda.

I’ll take a closer look into the Cg code for shadows, but I also found out that, while (IIRC) you can easily pass a matrix (as Mat4) directly into a Cg shader, you can’t do the same when using GLSL. It results in an error stating that “shader input is not a nodepath”.

I can get any matrix into the shader if I wrap it with a Node like this:

dummy = render.attachNewNode("dummy")
dummy.setMat(mat)

but I’m not sure if a matrix passed like this doesn’t get distorted somehow.

Also, I can see that the Cg sample for shadows uses a matrix that’s passed into it: trans_model_to_clip_of_light. I don’t see a matrix like this being actually made in any of these shaders.

And one more thing I forgot to mention, I’m using a recent buildbot Panda.

I’ve managed to get it to work the way you suggested, rdb – assuming I understood your suggestions correctly, that is :slight_smile:.

I dropped projectTexture completely, then supplied the lens’ projection matrix into the shader and used it to compute the texture matrix. However, I still needed at least one additional matrix to be supplied – light-to-model, because the projection matrix is in light’s space.

I thought that getting the correct light-to-model matrix would be as simple as:

self.floor.setShaderInput("LightMatrix", light)

but it wasn’t. As I found out, this gives me the light’s transform in its parent space, which only does the trick when the light and the target mesh have a common parent.

I solved it by supplying this matrix:

self.light.getMat(self.floor)

through a dummy node. I updated the dummy’s transform with the matrix coming from the above code in a task run in every frame.

While this works, it’s hardly a real solution. I would expect the matrices coming from setting a shader input to a nodepath to be supplied in model or world space. In the later case, two matrices would obviously be needed as the vertex positions are supplied in model space.

Obviously, I might still be missing something, so any input is welcome :slight_smile:.

The code I ended up with is here:
dl.dropbox.com/u/196274/glsl/gls … orking.zip

EDIT:

I got the basic GLSL directional shadows to work.

Now all I need is some input on whether the issue I’ve encountered with the matrices (the apparent coordinate space incompatibility, so to speak) is a bug or a feature :slight_smile:. And if it’s a feature, then what is the intended way to make use of it.

I’ll post the code here tomorrow, as soon as I manage to clean it up a little.

In the latest devel, you can use a trans_model_to_clip_of_light matrix in GLSL as well, I believe.

Passing matrices is supposed to work directly. I’ll investigate.

Hm, I thought you were against translating this mechanics to GLSL and even wanted to move away from it in Cg, am I wrong?

Anyway, I still wonder about setShaderInput(“name”, nodepath). Is it deliberate that it gives the parent space transform matrix? It seems a bit useless that way, at least if you wanted to avoid using all the additional matrices from Cg. In most scenarios, you can’t really translate these coordinates to the model or world space without resorting to the, say, “Cg mechanics”.

Thanks for taking a look into passing these matrices directly in GLSL. Should I file a bug report on that?

EDIT:

As promised, here’s the shadows code:

dl.dropbox.com/u/196274/glsl/shadows.zip

Note that it contains no actual lighting, just “recording” and projecting shadows.

I was, since I don’t think that hardcoding these as variable names is a good idea. Someone from Disney went ahead and added them in because he needed them; I can’t really argue against the fact that we currently have no other straightforward way to do it.

I’ve been thinking a lot recently about how the shader system could be redesigned to allow this to be done more easily.

Passing a NodePath means it’s always getting the transformation matrix of that NodePath, which is always relative to the parent. There’s currently no easy way to specify that it should be relative to another node, so there’s no going around that. In the future, perhaps we could allow people to pass a second ‘other’ node to which the matrices should be made relative.

About the matrices; it’s not my highest priority at the moment, so sure, go ahead and file a bug report. It’s not very difficult to do, though, it just involves porting some of the changes that the CMU students made to the GLSL side.

Am I understanding this correctly that the semantics shown here will work with GLSL shaders in a devel version? I took a look through shader.cxx for 1.8.1, and it seemed pretty clear that it’s not set up to work there.

Please excuse my ignorance here, but where can I find the devel version of panda? There seems to be nothing in the devel section of “Downloads.”

Alternatively, is there a good example somewhere that shows a preferred way of updating a GLSL modelview and projection matrix per frame, if its not using those hard coded matrix names?

Thanks!

It’s in panda/src/glstuff/glShaderContext_src.cxx for the GLSL-specific code.

The devel builds are currently only available under buildbot.panda3d.org/downloads/

However, in the case of the modelview and projection matrix, you are instead encouraged to use p3d_ModelViewProjectionMatrix and the like, which have been supported for a lot longer.