[TOC]
Render targets represent destination surfaces onto which objects are rendered. They can be textures or windows.
In Banshee render targets are represented with:
Each type comes in two variants, both of which provide almost equivalent functionality, but the former is for use on the simulation thread, and the latter is for use on the core thread. If you are confused by the dual nature of the objects, read the core thread manual.
We're going to focus on the simulation thread implementation in this manual, and then note the differences in the core thread version at the end.
Render windows are render targets that are backed up by OS-specific windows. Each application must have at least one render window in order to display its contents to the user. All created windows are double or triple buffered, meaning they internally have multiple render surfaces that are swapped between during rendering (see the section about rendering later). This makes them useful for displaying final rendering results in the screen, while render textures are used for intermediary processing.
Creating a @ref BansheeEngine::RenderWindow "RenderWindow" involves filling out the @ref BansheeEngine::RENDER_WINDOW_DESC "RENDER_WINDOW_DESC" and calling @ref BansheeEngine::RenderWindow::create "RenderWindow::create". This method also accepts a parent render window, in case your window is meant to be a child of another window. @ref BansheeEngine::RENDER_WINDOW_DESC "RENDER_WINDOW_DESC" contains many properties, and you should read its reference for information about what all of them do. In this manual we'll just cover the most important settings:
@ref BansheeEngine::RENDER_WINDOW_DESC::videoMode "RENDER_WINDOW_DESC::videoMode"
You can create a @ref BansheeEngine::VideoMode "VideoMode" manually by providing a custom resolution and a refresh rate, or you can query @ref BansheeEngine::RenderAPI::getVideoModeInfo "RenderAPI::getVideoModeInfo" to retrieve all available video modes for all available monitors. The latter is the suggested method as it guarantees the video mode will be compatible with the hardware.
@ref BansheeEngine::RENDER_WINDOW_DESC::fullscreen "RENDER_WINDOW_DESC::fullscreen"
@ref BansheeEngine::RENDER_WINDOW_DESC::vsync "RENDER_WINDOW_DESC::vsync"
@ref BansheeEngine::RENDER_WINDOW_DESC::multisampleCount "RENDER_WINDOW_DESC::multisampleCount"
@ref BansheeEngine::RENDER_WINDOW_DESC::depthBuffer "RENDER_WINDOW_DESC::depthBuffer"
@ref BansheeEngine::RENDER_WINDOW_DESC::gamma "RENDER_WINDOW_DESC::gamma"
An example that creates a 1280x720 window:
RENDER_WINDOW_DESC desc;
desc.videoMode = VideoMode(1280, 720);
desc.fullscreen = false;
SPtr<RenderWindow> window = RenderWindow::create(desc);
Once the window is created you can perform the following actions:
And more. Read the @ref BansheeEngine::RenderWindow "RenderWindow" reference for the rest.
You can also use the window to convert between screen and window coordinates by calling:
Render textures are simpler than windows, but you are given more control over their format. Internally a render texture is just a @ref BansheeEngine::Texture "Texture" created with the @ref BansheeEngine::TU_RENDERTARGET "TU_RENDERTARGET" flag. Read the texture manual to learn how to create such textures.
Render texture must contain at least one texture (color surface), but may optionally also contain a depth-stencil surface. Depth-stencil surface is also a @ref BansheeEngine::Texture "Texture", but one created with the @ref BansheeEngine::TU_DEPTHSTENCIL "TU_DEPTHSTENCIL" flag. Depth stencil surfaces only accept specific pixel formats starting with "D" prefix in @ref BansheeEngine::PixelFormat "PixelFormat". Dimensions of the depth stencil surface must match the color surface.
To create a render texture call @ref BansheeEngine::RenderTexture::create(const RENDER_TEXTURE_DESC&) "RenderTexture::create" with a populated @ref BansheeEngine::RENDER_TEXTURE_DESC "RENDER_TEXTURE_DESC" structure. This structure expects a reference to the color surface texture, and an optional depth-stencil surface texture. For each of those you must also specify the face and mip level onto which to render, in case your texture has multiple.
For example:
// Create a 1280x720 texture with 32-bit RGBA format
HTexture color = Texture::create(TEX_TYPE_2D, 1280, 720, 1, 0, PF_R8G8B8A8);
// Create a 1280x720 texture with a 32-bit depth-stencil format
HTexture depthStencil = Texture::create(TEX_TYPE_2D, 1280, 720, 1, 0, PF_D24S8);
RENDER_TEXTURE_DESC desc;
desc.colorSurface.texture = color;
desc.colorSurface.face = 0;
desc.colorSurface.mipLevel = 0;
desc.depthStencilSurface.texture = depthStencil;
desc.depthStencilSurface.face = 0;
desc.depthStencilSurface.mipLevel = 0;
SPtr<RenderTexture> renderTexture = RenderTexture::create(desc);
Optionally you can also use the overloaded @ref BansheeEngine::RenderTexture::create(TextureType, UINT32, UINT32, PixelFormat, bool, UINT32, bool, PixelFormat) "RenderTexture::create" to create the texture surfaces and the render texture in one go:
// Has the same result as above:
SPtr<RenderTexture> renderTexture = RenderTexture::create(TEX_TYPE_2D, 1280, 720, PF_R8G8B8A8, false, 0, true, PF_D24S8);
Render textures can also contain multiple color surfaces (up to 8). Such targets simply allow you to write more data at once, improving performance as you do not need to execute multiple draw calls. To create a texture with multiple color surfaces you must create a @ref BansheeEngine::MultiRenderTexture "MultiRenderTexture" by calling @ref BansheeEngine::MultiRenderTexture::create "MultiRenderTexture::create".
Their creation is identical to normal render textures, only they accept more than one color surface. Use BS_MAX_MULTIPLE_RENDER_TARGETS to learn what is the maximum supported number of color surfaces per target (usually 8). All color surfaces (and the depth/stencil surface) must have the same dimensions.
Same as windows, render textures can be created with support for multiple samples per pixel. This allows affects such as multi-sampled antialiasing and similar. To create a multi-sampled render texture simply create a @ref BansheeEngine::Texture "Texture" with its multisampleCount parameter larger than one, which you then use to initialize a render texture. Make sure that all surfaces (including depth-stencil) in a render texture have the same number of samples.
In order to display a multi-sampled render texture on the screen you need to resolve the texture into a non-multi-sampled one. For windows this is done automatically for you, but for textures you must do it manually. You can do it from the GPU program (render API dependant), or by calling @ref BansheeEngine::TextureCore::copy "TextureCore::copy".
@ref BansheeEngine::TextureCore::copy "TextureCore::copy" works only on the core thread, and it will copy contents of one texture to another texture. If you ensure that the source texture is multi-sampled but the destination is not, it will automatically resolve the multi-sampled texture.
All render targets have a priority that can be set by calling @ref BansheeEngine::RenderTarget::setPriority "RenderTarget::setPriority". This priority can be used as a hint to the renderer in which order should the targets be rendered to. Targets with higher priority will be rendered to before targets with lower priority. If you are rendering manually using the @ref BansheeEngine::RenderAPI "RenderAPI" then this value is not used.
Now that we know how to create a render target we can use it in one of various ways: render to it, read from it, clear it, or use its contents to render something else.
Use @ref BansheeEngine::RenderAPI::setRenderTarget "RenderAPI::setRenderTarget" to bind a render target for rendering. After binding you may issue draw calls, after which you should follow it with a call to @ref BansheeEngine::RenderAPI::swapBuffers "RenderAPI::swapBuffers" if the target has multiple buffers (like a window). Read the render API manual for more information.
Call @ref BansheeEngine::RenderAPI::clearRenderTarget "RenderAPI::clearRenderTarget" to clear all or portions of a render target to a specific color/value. Read the render API manual for more information.
If you wish to read render target pixels from the CPU, you can use the normal @ref BansheeEngine::Texture "Texture" read functionality as described in the texture manual. To retrieve a @ref BansheeEngine::Texture "Texture" from a @ref BansheeEngine::RenderTexture "RenderTexture" or @ref BansheeEngine::MultiRenderTexture "MultiRenderTexture" call the following methods:
Before reading you must make sure the render target is not currently bound for rendering otherwise this will fail. You cannot read from a @ref BansheeEngine::RenderWindow "RenderWindow".
Sometimes you render to a render texture only to use it as input in another rendering operation. In such case the render texture is first used for writing, and then for reading. This case is similar to above, first you make sure that the render texture is not currently bound for writing, and then you call one of the above listed methods to retrieve the required @ref BansheeEngine::Texture "Texture".
Then you can bind the texture for rendering as normal (described in the render API manual).
For depth/stencil surfaces there is a special case where you might need to leave them bound as a render target to be used for depth/stencil testing (not writing), but also for reading within a GPU program. In such a case you can call @ref BansheeEngine::RenderAPI::setRenderTarget "RenderAPI::setRenderTarget" with readOnlyDepthStencil parameter set to true.