my idea is render an entire terrain based on heightmap using geometry shader, i am parsing only one point per quad of terrain with the heights of the corners, however for some reason i am not being able to expand every point into quads, if not wrong i should be able to do this using geometry shader directly.
Load Terrain on GPU memory -> Draw entire terrain -> Expand every point into 4 vertex -> Process texture on Pixel Shader
Vertex Input:
enum SHTerrainHeightEnum
{
CORNER_TL, // Top-Left
CORNER_TR, // Top-Right
CORNER_BR, // Bottom-Right
CORNER_BL, // Bottom-Left
CORNER_MAX,
};
struct SHTerrainVertex // Point
{
uint16 Index;
float Height[CORNER_MAX];
};
Vertex Shader:
struct VertexInputType
{
float Index : TEXCOORD0;
float4 Heights : POSITION;
};
VertexInputType main( VertexInputType input )
{
return input;
}
Geometry Shader:
cbuffer MatrixBuffer : register(b0)
{
matrix worldMatrix;
matrix viewMatrix;
matrix projectionMatrix;
};
struct VertexInputType
{
float Index : TEXCOORD0;
float4 Heights : POSITION;
};
struct GeometryOutputType
{
float4 Position : POSITION;
float2 UV : TEXCOORD0;
};
[maxvertexcount(4)]
void main(
point VertexInputType input[1],
inout TriangleStream< GeometryOutputType > output
)
{
float x = (float)((uint)input[0].Index % 256) * 100.0f, y = (float)((uint)input[0].Index / 256) * 100.0f;
GeometryOutputType vertex;
// Top Left
vertex.Position = float4(x, y, input[0].Heights[0], 1.0f);
vertex.UV = float2(0.0f, 0.0f);
vertex.Position = mul(vertex.Position, worldMatrix);
vertex.Position = mul(vertex.Position, viewMatrix);
vertex.Position = mul(vertex.Position, projectionMatrix);
output.Append(vertex);
// Top Right
vertex.Position = float4(x + 100.0f, y, input[0].Heights[1], 1.0f);
vertex.UV = float2(1.0f, 0.0f);
vertex.Position = mul(vertex.Position, worldMatrix);
vertex.Position = mul(vertex.Position, viewMatrix);
vertex.Position = mul(vertex.Position, projectionMatrix);
output.Append(vertex);
// Bottom Right
vertex.Position = float4(x + 100.0f, y + 100.0f, input[0].Heights[2], 1.0f);
vertex.UV = float2(1.0f, 1.0f);
vertex.Position = mul(vertex.Position, worldMatrix);
vertex.Position = mul(vertex.Position, viewMatrix);
vertex.Position = mul(vertex.Position, projectionMatrix);
output.Append(vertex);
// Bottom Left
vertex.Position = float4(x, y + 100.0f, input[0].Heights[3], 1.0f);
vertex.UV = float2(0.0f, 1.0f);
vertex.Position = mul(vertex.Position, worldMatrix);
vertex.Position = mul(vertex.Position, viewMatrix);
vertex.Position = mul(vertex.Position, projectionMatrix);
output.Append(vertex);
}
Pixel Shader: struct GeometryOutputType { float4 Position : POSITION; float2 UV : TEXCOORD0; };
float4 main(GeometryOutputType input) : SV_TARGET
{
return float4(0.0f, 0.5f, 0.0f, 1.0f);
}
Render Code:
uint32 TERRAIN_SIZE = 256;
VideoManager::_DeviceContext->VSSetShader(Shader::VertexShader[Shader::VS_TERRAIN], nullptr, 0);
VideoManager::_DeviceContext->GSSetShader(Shader::GeometryShader[Shader::GS_TERRAIN], nullptr, 0);
VideoManager::_DeviceContext->PSSetShader(Shader::PixelShader[Shader::PS_TERRAIN], nullptr, 0);
uint32 stride = sizeof(SHTerrainVertex), offset = 0;
VideoManager::_DeviceContext->IASetVertexBuffers(0, 1, &_VertexBuffer, &stride, &offset);
VideoManager::_DeviceContext->IASetInputLayout(Shader::InputLayout[Shader::VS_TERRAIN]);
VideoManager::_DeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
VideoManager::_DeviceContext->GSSetConstantBuffers(0, 1, &_SettingBuffer);
VideoManager::_DeviceContext->Draw(TERRAIN_SIZE * TERRAIN_SIZE, 0);
VideoManager::_DeviceContext->GSSetShader(nullptr, nullptr, 0);
I couldn't figure out what is wrong with this code, it should draw on screen perfectly however it doesn't draw anything, everything is blank.
I did this for decrease the memory usage and do GPU culling of the terrain discarding the terrain blocks what are outside of camera.
EDIT: I am using DirectX 11 with feature levels of 10.0, if someone has a better recommendation about what I could do for optimize the terrain I will really appreciate
Max terrain size is 256x256, but might be extended to 1024x1024.
Any answer is appreciated, really thanks for your time.