1
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\begingroup\$ Geometry shader is still missing from some GPU-s, it's not very reliable in case of game developement. It's also memory and performace inefficient to do this every frame. Just stick to CPU generazed terrain. \$\endgroup\$
    – Bálint
    Apr 13 '16 at 5:52
  • \$\begingroup\$ ok, thank you so much for the information, i didn't know about that :) \$\endgroup\$
    – Isaías
    Apr 21 '16 at 4:22
-1
\$\begingroup\$

Forgot to answer for mark it as answered.

At the end I finished doing what Balint recommended me, really thanks Balint for your answer.

\$\endgroup\$
3
  • \$\begingroup\$ Could you include a description of what you chose as your solution in the answer? \$\endgroup\$
    – user5665
    Jul 3 '16 at 14:02
  • \$\begingroup\$ Yes, of course, I was going to include it, but forgot. What I actually do is upload all terrain blocks(due to game needs every terrain block is 4 vertex, and 6 index) to GPU memory, then for render a limited area I just render using the index data. So it would be N render calls(based on Y-coord, so if have to render Y from 20 to 30 it would be 10). Also for limit X-coord i just decrease the index count and increase index offsef. I am not sure if it is exactly the most efficient way, but actually is the best I could think due to map limitations on my game if know a better way let me know :) \$\endgroup\$
    – Isaías
    Jul 3 '16 at 14:20
  • \$\begingroup\$ Forgot, it is an height-map, actually all map textures are allocated in only one Texture2D array and compressed with BC3_UNORM, also divided the terrain buffers between static and dynamic, and the dynamic buffer is also divided due to update frequency, so it wouldn't always update the entire buffer, just what is needed, provided a third parameter(instead of 2 floats UV, what i did is provide an UV of 3 floats, last one for the texture to be used), also implemented LOD to textures, that is all what I did in replace of the geometry shader, if i find a better solution for sure will change it. \$\endgroup\$
    – Isaías
    Jul 3 '16 at 14:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.