It begins!
This week I started my work for Terrain by working on its generation.
Firstly it’s worth noting that my Marching Cube method has been dropped because I don’t really think it will work super well for the worms terrain and so instead I’ve decided to go with the render target method that was recommended in the lectures.
The Theory
The idea for this method is to use something called a render target which is basically a separate space to draw into from the standard screen. It’s like drawing into a texture, you just have to note when you want to draw into the RT or the screen space.
The render target stores data that you write into it and is normally on the GPU which allows you to draw the content of the render target into the screen space, however in order to draw things into it or to get information about it you need to map it onto the CPU (and then when you’re done map it back onto the GPU).
The reason why this method is useful is because when you draw things into the terrain you have to use a blendstate which specifies how you want data to be applied to the render target. This allows us to do things such as perform operations that check if a pixel has an alpha value of 0 and if not make it 0, which will be how I plan to implement deformation.
So now that I’ve talked a little about the theory, let’s look at how it works in c++:
The Implementation
I started out with this method by first creating a Terrain2D class and using it to contain important information about the Terrain which we won’t be storing inside the render target. This class currently won’t contain that much but I think it will be more useful when it comes to storing collision information. Other than that we also contain the Terrain backgrounds width and height.
To start, we first need to take our background image and draw it onto the render target, but we only ever want to do this when we are loading a new terrain, so we make sure that we mark whether we have done this yet or not.
Here is the code I use for this:
if (!m_terrainData->hasRenderTargetLoadedCurrentTexture())
{
//Code potentially for drawing into the Terrain RenderTarget
//Draw stuff to the render texture
m_terrain->Begin(m_d3dContext.Get());
m_terrain->ClearRenderTarget(m_d3dContext.Get(), 0.f, 0.f, 0.f, 0.f);
m_DD2D->m_Sprites->Begin(SpriteSortMode_Deferred, m_states->NonPremultiplied());
m_DD2D->m_Sprites->Draw(m_terrainData->getTerrainTextureRV(), XMFLOAT2(0.0f, 0.0f)); //Draws terrain to terrain RT
if (m_terrainData->showDebug()) { std::cout << "[Terrain] Terrain data image has drawn into RT..." << std::endl; }
m_DD2D->m_Sprites->End();
m_terrain->End(m_d3dContext.Get());
m_terrainData->hasRenderTargetLoadedCurrentTexture(true);
}
It starts by checking m_terrainData (A variable which represents our Terrain2D instance) and returns whether or not the render target has had the background draw into it yet, if not then m_terrain (A variable which represents our render target instance) is mapped onto the CPU so we can draw stuff into it (this is done by calling the Begin function). From here we then clear the render target as we dont want anything in it before we draw our background onto it, then we prepare the terrain sprite and draw it into the render target. After this is done we map the render target back onto the GPU so it can be drawn later and tell the terrainData that we have drawn the background so this function won’t be re-called next frame.
I also had the idea for a debug system that can be toggled on and off that allows people to focus only on messages from specific systems. You can see it used in the code example, however I am not yet happy with it as it requires bools in peoples headers that people need to manually navigate to which makes the system somewhat annoying to use at times, if I have time I may try to upgrade it.
Here is what the current output displays:
To actually draw the render target to the screen we use simply get the shader resource view and draw it to 0,0 in the screen space.
m_DD2D->m_Sprites->Begin(SpriteSortMode_Deferred, m_states->NonPremultiplied());
m_DD2D->m_Sprites->Draw(m_terrain->GetShaderResourceView(), XMFLOAT2(0.0f, 0.0f));
m_DD2D->m_Sprites->End();
Next week I plan to get Deformation working if I can figure it out.