Just posting my rant about what I’ve been up for the past few days to keep this information on the record. This is fairly low-level stuff that probably won’t be all that interesting to most of you.
I’ve worked with TobiasSpringer to add support for render-to-2d-texture-array. You can now attach a texture array to a buffer using add_render_texture. Similar to how rendering to a cube map works, you can create one display region per layer and use set_cube_map_index to indicate which layer you want to render to.
(Yes, set_cube_map_index sounds a bit silly when applied to texture arrays. We should probably rename it into set_layer_index, or something of the sort.)
However, this isn’t very economical for rendering to a lot of layers. Panda will have to create one FBO per layer, and issue all of the draw calls for each layer.
To remedy that, I’ve also added a new render-to-texture mode called RTM_bind_layered. Instead of creating one FBO per layer, this will instead create a single FBO with all of the layers attached to the buffer. The idea is that you then use a geometry shader and indicate which layer you wish to write to by assigning gl_Layer (or in Cg, binding to the LAYER semantic) and the OpenGL implementation will know which layer of the texture to write the fragment to.
If you wish to render the same geometry to all layers, you can combine this with geometry instancing using set_instance_count(n_layers), and assigning the value of gl_InstanceID to gl_Layer in the shader. If instancing isn’t supported on the card, you can simply use a “for” loop in the geometry shader to issue the geometry N times, albeit a bit less efficiently.
This technique is particularly useful for cube map rendering, where you want to draw the same geometry to all faces without incurring the cost of sending the geometry to the GPU six times (once per FBO). I intend to use this when I add point light shadows support to Panda.
Needless to say, to use this method, you need both render-to-texture support and geometry shaders to use RTM_bind_layered. You can use it without a geometry shader, but you’ll only be able to draw to the first layer.
Unfortunately, this means that if you want to support a fallback approach, you’ll need to have two completely different implementations: one shader-based, in which you’re forced to handle the camera transformations in the shader, and one where you create a whole bunch of display regions and set up the appropriate Lenses. I don’t think that there is an easy way around this that will serve everyone’s needs. (Since it requires shader code to deal with the layer that it’s to be rendered on, it will require the use of the shader generator, but there are many cases where people will want to use their own shaders instead.)
As you can’t apply texture arrays to a model using the fixed-function pipeline, you previously had to use a shader to sample texture arrays. You can now also render texture arrays on a model without using a shader, by enabling the shader generator. The layer that is sampled is determined by the W texture coordinate. The buffer viewer takes advantage of this to display the layers attached to a buffer on separate cards.
While I was at it, I’ve overhauled the FBO code a bit here and there to make the RTP_depth_stencil handling more simple, not to make buffers that the user didn’t ask for, and better respect the user’s FrameBufferProperties settings (ie. set_depth_bits(32) will actually ask Panda to use a 32-bit depth attachment.)
(You can now also request a floating-point depth buffer by setting the Texture component type to T_float, but I’m really iffy on the ambiguity of whether the framebuffer storage is defined by the format of the Texture object or by the FrameBufferProperties settings. The fact that Texture does not distinguish between the internal format and the external format isn’t helping to make this less ambiguous. Maybe we can simply add some flags to FrameBufferProperties to signify a floating-point buffer? drwr, any thoughts?)
The next step is to take advantage of this functionality to add efficient point light shadow mapping.