Multiple Shadow Renderers for Multiple ViewPorts?

I’m working on an application that is displaying three different views of a scene utilizing AwtPanels. My basic methodology to construct the different viewports are to clone the camera, move it, create a ViewPort for the cloned camera, and attach the AwtPanel to the new viewport.

I want to enable shadows in all three ViewPorts, but I’m running in to issues. I’m currently using a BasicShadowRenderer.

If I construct a single BSR and attach it to any one if the individual viewports, everything works as expected.

If I attempt to attach a single instance of the BSR to multiple viewports, only the first viewport with the BSR attached looks fine; the other viewports simply display their background color with none of the scene elements.

If I attempt to create individual BSR’s for each viewport, I get an Incomplete Read Buffer exception.

A little code snippet to give you an idea of what I’m doing, this is the snippet where I make three disparate BSR’s:


// …

// set up stuff

// …




BasicShadowRenderer shadowRenderer = new BasicShadowRenderer(assetManager, 256);



final Camera clonedCam = cam.clone();

Vector3f originalCamLocation = cam.getLocation();

clonedCam.setLocation(new Vector3f(originalCamLocation.x + 6f, originalCamLocation.y, originalCamLocation.z - 9f));

clonedCam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);

final Camera clonedCamOverhead = cam.clone();

clonedCamOverhead.setLocation(new Vector3f(originalCamLocation.x, originalCamLocation.y + 10f, originalCamLocation.z - 10f));

clonedCamOverhead.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);

clonedCamOverhead.setRotation(clonedCamOverhead.getRotation().mult(new Quaternion().fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_Z)));

final ViewPort viewPortForClonedCam = renderManager.createMainView(“View of cloned cam 1”, clonedCam);



viewPortForClonedCam.setClearFlags(true, true, true);

BasicShadowRenderer shadowRenderer2 = new BasicShadowRenderer(assetManager, 256);



final ViewPort viewPortForClonedCamOverhead = renderManager.createMainView(“View of cloned cam 2”, clonedCamOverhead);



viewPortForClonedCamOverhead.setClearFlags(true, true, true);

BasicShadowRenderer shadowRenderer3 = new BasicShadowRenderer(assetManager, 256);



panel1.attachTo(false, viewPort);

panel2.attachTo(false, viewPortForClonedCam);

panel3.attachTo(false, viewPortForClonedCamOverhead, guiViewPort);


This should work like normal. Do you use a normal jme application or do you do the update loop yourself somehow?

Would it be any different if he tried using the new shadow filters etc?

Not really, they are both applied per viewport.

I’m not touching the update loop at all, and I’m using a regular SimpleApplication. The only thing I could think of that isn’t “normal” would be that the renderer is set to AwtPanelsContext.class in the AppSettings so that I can use the AwtPanels.

Are you on osx?

I had an issue with incomplete read buffer for the shadow maps on osx. This is worked around in the DirectionalLightShadowRenderer, maybe you should give it a try.

One instance for multiple viewport will giv eyou unexpected results for sure. The processors are not stateless and hold data relative to the viewport they are attached to (the viewport itself for starters).

The right way to do it is to have one processor for each viewport

@nehon I am on OS X but one of my coworkers worked with the code on his Win7 machine and reported back with similar results.

We don’t intend on using BSR in production, it was just for a proof-of-concept demo, so I’ll give it a try with other Shadow processors and see if I encounter the same issues then report back.

Can you post the exception?

=== OpenGL FBO State ===
Context doublebuffered? false
Nov 8, 2012 6:43:25 PM com.jme3.renderer.lwjgl.LwjglRenderer setFrameBuffer
SEVERE: === jMonkeyEngine FBO State ===
FrameBuffer[format=256x256x1, drawBuf=0]
Depth => TextureTarget[format=Depth]

Is proper? true
Is bound to draw? true
Is bound to read? true
Draw buffer: NONE
== Renderbuffer Depth ==
RB ID: -1
Is proper? false
Type: Texture
Nov 8, 2012 6:43:25 PM handleError
SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,6,main]
java.lang.IllegalStateException: Incomplete read buffer.
at com.jme3.renderer.lwjgl.LwjglRenderer.checkFrameBufferError(
at com.jme3.renderer.lwjgl.LwjglRenderer.setFrameBuffer(
at com.jme3.shadow.BasicShadowRenderer.postQueue(
at com.jme3.renderer.RenderManager.renderViewPort(
at com.jme3.renderer.RenderManager.render(
at com.jme3.system.awt.AwtPanelsContext.updateInThread(
at com.jme3.system.awt.AwtPanelsContext.access$1(
at com.jme3.system.awt.AwtPanelsContext$AwtPanelsListener.update(
at com.jme3.system.lwjgl.LwjglOffscreenBuffer.runLoop(

FWIW, switching to PssmShadowRenderer alleviates the exception; there are no issues with launching the application.

Of course, 3 PssmShadowRenderers aren’t great for performance, even with just a single shadow map. But workable for what we need to do, at least right now with out a ton of physics. That comes later, and we’ll have to deal with that sort of performance when we get there.

@nehon, I don’t see a class anywhere called DirectionalLightShadowRenderer, is this a WIP thing? I can only see BSR, Pssm, and PointLight in the source.

Well it has been committed 2 days ago.

Pssm is the same as DirectionalLight that’s just a renaming. So just know that once you update to nightly, Pssm will be deprecated and you’ll have to use DirectionLightShadowRenderer…

Also there is no performance difference between basic and pssm with one split, is it?

EDIT : also I committed a fix to avoid the exception of the incomplete draw buffer in BasicShadowRenderer

@nehon A single BSR attached to one of the viewports the same size as a single Pssm with one split attached to one of the viewports performs much differently. A difference of around 20fps. There’s also a big, big difference in the quality of the shadows.

@dljsjr said:
There's also a big, big difference in the quality of the shadows.

I hope you mean PSSM is better in quality at least

@nehon haha, yes, that’s exactly what I mean.