Over here I managed to extract an image of the scene being rendered, then restore the depth buffer to continue drawing.
It’s a neat little hacky alternative for getting a refraction map without drawing the entire scene out to a depth texture. But what if I want the depth texture? I’ve decided to give it a try, but I’m probably going to need help because I have zero idea what I’m doing.
The starting point: I’ve added some code to PlatformApplyRenderTargets
in GraphicsDevice.OpenGL.cs. The method now takes a parameter, “oldGLDepthBuffer
”, and uses it in place of the new RenderTarget’s GLDepthBuffer if it’s not -1.
private IRenderTarget PlatformApplyRenderTargets(int oldGLDepthBuffer = -1) //NEW!
{
var glFramebuffer = 0;
if (!this.glFramebuffers.TryGetValue(this._currentRenderTargetBindings, out glFramebuffer))
{
this.framebufferHelper.GenFramebuffer(out glFramebuffer);
this.framebufferHelper.BindFramebuffer(glFramebuffer);
var renderTargetBinding = this._currentRenderTargetBindings[0];
var renderTarget = renderTargetBinding.RenderTarget as IRenderTarget;
if(oldGLDepthBuffer == -1) //NEW!
this.framebufferHelper.FramebufferRenderbuffer((int)FramebufferAttachment.DepthAttachment, renderTarget.GLDepthBuffer, 0);
else
this.framebufferHelper.FramebufferRenderbuffer((int)FramebufferAttachment.DepthAttachment, oldGLDepthBuffer, 0);
this.framebufferHelper.FramebufferRenderbuffer((int)FramebufferAttachment.StencilAttachment, renderTarget.GLStencilBuffer, 0);
for (var i = 0; i < this._currentRenderTargetCount; ++i)
{
renderTargetBinding = this._currentRenderTargetBindings[i];
renderTarget = renderTargetBinding.RenderTarget as IRenderTarget;
var attachement = (int)(FramebufferAttachment.ColorAttachment0 + i);
if (renderTarget.GLColorBuffer != renderTarget.GLTexture)
this.framebufferHelper.FramebufferRenderbuffer(attachement, renderTarget.GLColorBuffer, 0);
else
this.framebufferHelper.FramebufferTexture2D(attachement, (int)renderTarget.GetFramebufferTarget(renderTargetBinding), renderTarget.GLTexture, 0, renderTarget.MultiSampleCount);
}
What stands out to me is the loop after we set the Depth and Stencil buffers. That loop is where we set any additional RenderTargets that were fed in as part of the SetRenderTargets()
method (used for Multiple Render Targets). Most notably, it uses the same method (FramebufferRenderbuffer) that we used to set the depth texture.
All good so far! Now in theory, if I feed in a “DepthOutputRenderTarget” as the first item in this loop, and inject it with oldGLDepthBuffer instead of renderTarget.GLColorBuffer, that RenderTarget should also be handed the depth texture!
Which I did. And got a completely black screen for my sins.
Okaaaayyy… not a great start. All the UI bits and bobs that were rendered after this are fine: they’re simply drawn on top of the black. So it just looks like I’ve just screwed up the scene render somehow.
So, what’s the issue here? First and most obvious: converting DepthStencilFormat to SurfaceFormat. I don’t know to what extent this is an issue, but I assume at the very least they will need to be the same size in bytes.
So, I’ve downgraded the primary render target’s depth stencil format to Depth16 and set depthOutput render target’s SurfaceFormat to HalfSingle. Both 16 bit, they should be compatible.
Still getting a black screen.
Alright, I have two hypotheses about what I’m seeing. Either the black screen is a misguided attempt to render the depthOutput target onto the screen, or I’ve completely screwed up in some manner and am trying to force OpenGL to do complete nonsense. Can’t rule either of those out at this stage.
This is the relevant section of code, where I’m FramebufferRenderbuffer-ing the Depth, Stencil and DepthOutput.
this.framebufferHelper.FramebufferRenderbuffer((int)FramebufferAttachment.DepthAttachment, oldGLDepthBuffer, 0);
this.framebufferHelper.FramebufferRenderbuffer((int)FramebufferAttachment.StencilAttachment, renderTarget.GLStencilBuffer, 0);
var depthOutputRenderTarget = this._currentRenderTargetBindings[1].RenderTarget as IRenderTarget;
this.framebufferHelper.FramebufferRenderbuffer((int)FramebufferAttachment.DepthAttachment, oldGLDepthBuffer, 0);
Which FramebufferAttachment I use doesn’t seem to make a difference.
And this is where it comes out on the higher levels:
sceneRenderTarget = new RenderTarget2D(GraphicsDevice, width, height, false,
format, pp.DepthStencilFormat, pp.MultiSampleCount,
RenderTargetUsage.PreserveContents);
depthOutputRenderTarget = new RenderTarget2D(GraphicsDevice, width, height, false,
SurfaceFormat.HalfSingle, DepthFormat.None, pp.MultiSampleCount,
RenderTargetUsage.PreserveContents);
GraphicsDevice.SetRenderTargets(sceneRenderTarget, depthOutputRenderTarget);
As of right now, I am not drawing depthOutputRenderTarget to the screen, and sceneRenderTarget is coming out black.
Sooooo… any idea’s what to try from here?