by the Codermind team. |
Question
«I'm writing a 3D application using Direct3D9 and I've one of those new GeForce 8800 that supports multisampling with floating point targets. So I know how to render with anti-aliasing and a regular ARGB8 target. I know how to render with HDR with a floating point target. But I can't figure how to combine the two. What are the steps ?»
Answer
It's not that much more complicated..
Direct3D 9
Here's your pseudo d3d code (all targets listed here have same dimensions !):
// Init
CreateDevice(backbuffer and frontbuffer both called targetA,
multisampletype_none, absolutely no automatic depth stencil !).
CreateDepthStencilBuffer(targetZ, Z24X8/Z24S8,
multisampletype_2x_4x_8x, quality level 0-7); // <- no Z16 please
CreateRendertarget(targetB, A16B16G16R16F,
multisampletype_2x_4x_8x, quality level 0-7 (they must match above !))
// <- this is not a texture !
CreateTexture(textureC, Rendertarget, pool_default,
A16B16G16R16F, multisampletype_none); // <- important, see below
// Render frame 0
BeginScene();
// First draw the multisampled scene
SetRenderTarget(targetB);
SetDepthStencilSurface(targetZ);
Clear(both);
RenderScene(); // <- hdr scene as you do usually
// Then downsample the multisampled to the normal buffer with a blit
StretchRect(From targetB to texture C);
// <- no rectangle, matching dimensions please
// Then do the tone mapping pass
SetRenderTarget(targetA);
SetDepthStencilSurface(NULL); // <- important
Clear(color); // optional since you're stomping it just below
DrawFullScreenquad(with texture C); // tone mapping pass with a dedicated shader.
// This should be more complicated if you have bloom or other effects obviously.
RenderInterface(); <- don't tonemap or multisample your interface.
EndScene();
Present();
// Goto Render Frame [...]
// After we're done we release everything.OpenGL
The method is almost the same for OpenGL, though it is somehow complexified by the heavy use of OpenGL extensions (so double check those extensions are available on your graphics card).
// Init
GLenum format = GL_RGBA16F_ARB;
int samples = 4; // for example
GLuint multisampledFloatFBuffer;
glGenFramebuffersEXT(1, &multisampledFloatFBuffer);
glBindFrameBufferEXT(GL_FRAMEBUFFER_EXT, multisampledFloatFBuffer);
GLuint multisampledRenderBuffer;
glGenRenderbuffersEXT(1, &multisampledRenderBuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, multisampledRenderBuffer);
glRenderbufferStorageMultisampleEXT(
GL_RENDERBUFFER_EXT, samples, format, width, height);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, multisampledRenderBuffer);
GLuint multisampledDepthBuffer
glBindFrameBufferEXT(GL_FRAMEBUFFER_EXT, multisampledFloatFBuffer);
glGenRenderbuffersEXT(1, &multisampledDepthBuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, multisampledDepthBuffer);
glRenderbufferStorageMultisampleEXT(
GL_RENDERBUFFER_EXT, samples, GL_DEPTH_COMPONENT24, width, height);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, multisampledDepthBuffer);
GLuint normalFloatFBuffer;
glGenFramebuffersEXT(1, &normalFloatFBuffer);
glBindFrameBufferEXT(GL_FRAMEBUFFER_EXT, normalFloatFBuffer);
GLuint textureFloat;
glGenTextures(1, &textureFloat);
glBindTexture(GL_TEXTURE_RECTANGLE_NV, textureFloat);
glTexImage2D(
GL_TEXTURE_RECTANGLE_NV, 0, format, width, height, 0,
GL_RGBA, GL_INT, NULL);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_NV, textureFloat, 0);
// Render frame 0
// First draw the multisampled scene
glBindFrameBufferEXT(GL_FRAMEBUFFER_EXT, multisampledFloatFBuffer);
Clear(both);
RenderScene(); // <- hdr scene as you do usually
// Then downsample the multisampled to the normal buffer with a blit
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, multisampledFloatFBuffer); // source
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, normalFloatFBuffer); // dest
glBlitFramebufferEXT(
0, 0, width, height, 0, 0, width, height,
GL_COLOR_BUFFER_BIT, GL_LINEAR);// <- matching dimensions please
// Then do the tone mapping pass
glBindFrameBufferEXT(
GL_FRAMEBUFFER_EXT, 0); // unbind all (render to back buffer)
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_RECTANGLE_NV, textureFloat);
DrawFullScreenquad(); // tone mapping pass with a dedicated fragment program.
// This should be more complicated if you have bloom or other effects obviously.
RenderInterface(); <- don't tonemap or multisample your interface.
Present(); // swap buffers
// Goto Render Frame [...]
// After we're done we release everything.As you can see the idea is pretty similar. Note that the code has been simplified, so ALWAYS check with your extension specification to make sure you understand every step.
Direct3D10
The situation is slightly different for Direct3D 10. Direct3D 10 allows you to specify a multisample type for textures. That means that you have the choice between calling ResolveSubResource() to explicitely copy from a multisampled resource to a non multisampled resource similar to what was done for Direct3D 9 and OGL before, or to do a custom resolve pass by reading directly the individual samples in a pixel shader via the load() instruction on a multisampled texture.
There may be more to say about the quality of anti-aliasing that you will be able to get and what tone mapping operator to use. But that should answer your question for now.




