Shadow plane/matrix woes (webGL presentation inc.)

Oh wow, I can’t believe my password to this place was still in the Firefox browser on this workstation :o

I’ve been flirting with the darkside (Direct3D) the last few years, but now thanks to WebGL (and the perennial hair yanker) here I am. Disclaimer: I’ve been working on restoring some old turn of the century software mainly which happened to be DirectX based.

Moving along. I’ve been doing a lot of stuff with graphics without ever running into any trouble for a long time… so I am humbled to be here looking for some schooling today. I haven’t invested a ton of time into this problem, but I went totally Moby Dick on it last night, so now I am trying to find some distance.

The problem is simple enough: (link will need a WebGL browser)

Before bed I decided to see if a shadow would add anything to this model viewer project (about two weeks old 3D code wise) … I am pleased with the effect, which was simple enough to setup, and seems very natural versus the usual abstract ground plane visualization.

I expected to project things against the light in the shader, but I did two seconds of research and got the picture that you can use a matrix to do all the work for you.

I grabbed some code from here ( and got started.

The projection was going in a snap and seems fine…

But that was not the end of my story :whistle:


Shadows have a problem of being infinite… or nearly so. So that won’t work, because the shadow either gets lost beyond the far plane, or goes outside the viewport (which may need to be seamlessly blended over a background)

So the idea, is to be able to create a radial fog around the model (so the shadow will be blended into the background before it gets too far away)

It seems like a very simple problem. Alas I tried 3~5 distinct techniques and could not get a cleanly blended shadow. I am befuddled as to why not.

I don’t grasp the matrix construction frankly, but I don’t see how in model space the product of the matrix would exhibit the kind of dislocality I’ve observed. Like I say it looks good, but I may have set it up wrong and or am not appreciation its role.

The fog needs to be relative to the center of the model on display. So I calculate the distance from the shadow points for the basis of blending the shadow. I’ve tried that in local, model, view space, and screen space, and the distances are always discontinuous and generally dirty. For this model, around the base, the result is a nice radial bloom, as expected, but the projection of the spout is always disastrous…

I wish I could visualize the shadow matrix without running it through the projection matrix, but then it would not be visible would it. I can attest that along the Y plane the distances are uniform meaning the shadow plane in its own space is not askew, but otherwise I am stumped.

I can setup different scenarios on request. The source code can be seen in the link (have the browser pull it up) … if you want to tinker with the page you can save it (WebPage complete) and drop the files here ( into the folder with the root document. Mind you Google Chrome won’t let you access the files through the file:// protocol (so you would need to use Firefox)

Many features in the controls do not work yet, you just want to use the 1/2/3 radios and scrollbars (click to make them appear) in the WebGL app.

If you like the any of the unlicensed code feel free to take it / do whatever you want with it.

Apologies for the wordy post. Viva OpenGL :eek:

You mean it’s been a whole day (or so) and no one has come to my rescue :o

I was undaunted. But didn’t spend more time going nuts, just picking away at it.

I tried using just the fragment coords (gl_FragCoord) but this was not really satisfying, doesn’t handle the zfar clipping case, and seems flat over all. So I ruled that out and forged onward.

I was pretty sure at time of posting that the shadow matrix had to be creating an optical illusion… like an old timey Escher sketch. I guess it’s pretty obvious looking at the matrix since the W row or whatever was in play.

Anyway, for posterity sake. Luckily for me it turned out the projection divide logic was all that was required. Not after the projection, but inside the model space for a change.

Because the shadow projection is squashed into a matte of overlapping triangles, its important to do the division in the fragment shader, so you get per pixel distances.

This is a neat effect I think. The planar shadow is not very popular nowadays it seems like, but its not bad for low-fi presentations.

I will update the WebGL app as soon as I can tweak the falloff and try to add some code into this thread before I am done.

PS: Was this an appropriate question for this forum/board? It was pure 3D theory / technically not dependent upon OpenGL one bit. But This is still a good place for platform agnostic 3D programmers I think (though my memory may be fuzzy)

Have a look at the diagram here. It describes how it works very clearly:

Note that there is no “model space”. There’s object space, world space, eye space, clip space, and NDC space.

Hey a reply!

By model space I meant any of those spaces up to before projection. Eg. GL_MODELVIEW.

I admit I did not think to websearch “shadow mapping” because its a fairly involved subject, where I was aiming for the very simple kind of ground plane projection common in video games when I was a kid.

I was hoping someone would take mercy upon me because I was pretty sure my situation was not intractable. I’m surprised no one popped in and suggested the projection divide of the shadow matrix output before I figured it out.

I can’t say if the shadow matrix is the same as the light matrix in the diagram. It’s very possible. I’d never dealt with two projection style matrices before.

My results have been quite nice, but the model in the webGL app doesn’t exhibit very much falloff in its shadow because it doesn’t go far outside the boundary. I will see about adding a better demo where ?shadow=1 when I follow up on this.

Offtopic: I think my blend from shadow to non-shadow has about 4 shades. There was a lot of banding in the shades so I had to squash it as much as possible. I gotta admit, I am not sure why better than 8bit colour is not standard by now, because the banding is incredibly obvious.

PS: I don’t think think this adventure is finished quite yet. The placement of the light is optimal I think, but its not ideal for all models, but its as ideal as it can be for “all” models. The only way to make it better is to pull the light back if it is inside a part of the model (or rather has a portion of the model behind it) … the only robust way to do that I can think of is to render at least a few pixels from the POV of the light (actually from some place behind it) and read back the depth values so to gauge how far away the model is (and adjust the light accordingly) … which seems not dissimilar from the Paul’s Project there. So thanks for the tip.

Anyway, I’d like to make this a solid resource for anyone cramming stuff into search engines on the topic since I wasn’t able to find enough recent info as I would have liked.

Finally updated the model at to show off more of the shadow being blended at the extremities.

The original model is still at .

Shadow=1 is just for this thread actually since shadows are default now.

The code in the renderer is a lot better now if not perfected, in case anyone wants to use it to do your own thing with WebGL. I wouldn’t mind a link to where you got left in the source.

Firefox upgraded to 10.0 today for me. It now has anisotropic filtering going (8 or 4x) and antialising by default. Maybe linear mipmapping too. I think people will be more interested in WebGL now that it’s not so gimped.

PS: The only magic bit about the code happens when the camera is pitched perfectly up so that you are looking up along the Y axis. I had to modify the first parameter of glDepthOffset (I think that’s the API) in a way I don’t fully understand to alleviate some artifacts that I reckon are either caused by the model being aligned with the depth buffer causing greater deltas in the offset or by some singularity in the plane equation code that flips the offset.

From what I can gather the first parameter scales things relative to the z-distance so my hunch was to use it to relax things near the z-near plane.

The monster on display is pretty crazy, but I chose it because it casts wild shadows and doesn’t suffer from a lot of the texture mapping artifacts that many of the few hundred models on the website do. The models are all really great and hold up still very well I think, but it seems like the texture filtering was a not well understood thing around the time they were made (sometime in the late 90s I’d guess)