0
votes

I'm trying to render a terrain using directx 11 and applying a heightmap to it. I load the heightmap then I copy it to a integer vector, then for each vertex position I assign the Y position of that vertex to the heightmap value, but the terrain is completely destroyed and distorted. When I remove the calculation on the Y axis, I get a flat grid and no problem.

bool cGrid::readRawFile(std::string fileName, int m, int n)
{
   // A height for each vertex
    std::vector<BYTE> in(m*n);
    std::ifstream inFile(fileName.c_str(), std::ios_base::binary);
    if (!inFile)
        return false;
    inFile.read(
        (char*)&in[0], // buffer
        in.size());// number of bytes to read into buffer
    inFile.close();
    // copy BYTE vector to int vector
    m_heightmap.resize(n*m);
    for (int i = 0; i < in.size(); i++)
        m_heightmap[i] = in[i];
    return true;
}

for (size_t i = 0; i<m_Mesh.m_Vertices.size(); ++i)
    {
        XMFLOAT3 p = m_Mesh.m_Vertices[i].Position;
        p.y = (float)m_heightmap[i]*0.5f;
        m_Mesh.m_Vertices[i].Position = p;
    }

here is a video of the problem

https://www.youtube.com/watch?v=lnlIz3DjebM&feature=youtu.beenter image description here

enter image description here

HRESULT cGrid::CreateGrid(float width, float depth, UINT n, UINT m)
{
    HRESULT hr;
    int vertexCount = m*n;
    UINT faceCount = (m - 1)*(n - 1) * 2; // each quad consists of two triangles

    float halfWidth = 0.5f*width;
    float halfDepth = 0.5f*depth;

    // project the grid into xz plane 
    float dx = width / (n - 1);
    float dz = depth / (m - 1);

    float du = 1.0f / (n - 1); // texture co-ordinates
    float dv = 1.0f / (m - 1);


    m_Mesh.m_Vertices.resize(vertexCount);

    // build the vertices of the grid, including the normals and the tangent,
    //you can build then the bitanget by cross product for normal maps -_- 

    for (UINT i = 0; i < m; ++i)
    {
        float z = halfDepth - i*dz; // reset for the next cell 
        for (UINT j = 0; j < n; ++j)
        {
            float x = -halfWidth + j*dx;
            float y = (float)m_heightmap[j + i*m];
            m_Mesh.m_Vertices[i*n + j].Position = XMFLOAT3(x, y, z);
//          m_Mesh.m_Vertices[i*n + j].Normal = XMFLOAT3(0.0f, 1.0f, 0.0f);
//          m_Mesh.m_Vertices[i*n + j].TangentU = XMFLOAT3(1.0f, 0.0f, 0.0f);

            // Stretch texture over grid.
            m_Mesh.m_Vertices[i*n + j].TextureCords.x = j*du;
            m_Mesh.m_Vertices[i*n + j].TextureCords.y = i*dv;
        }
    }

    m_Mesh.m_Indices.resize(faceCount * 3); // 3 indices per face

    // Iterate over each quad and compute indices.
    UINT k = 0;
    for (UINT i = 0; i < m - 1; ++i)
    {
        for (UINT j = 0; j < n - 1; ++j)
        {
            m_Mesh.m_Indices[k] = i*n + j;
            m_Mesh.m_Indices[k + 1] = i*n + j + 1;
            m_Mesh.m_Indices[k + 2] = (i + 1)*n + j;

            m_Mesh.m_Indices[k + 3] = (i + 1)*n + j;
            m_Mesh.m_Indices[k + 4] = i*n + j + 1;
            m_Mesh.m_Indices[k + 5] = (i + 1)*n + j + 1;

            k += 6; // next quad
        }
    }

    m_IndicesSize = m_Mesh.m_Indices.size();


    // Pack all the vertices into vertex buffer
    D3D11_BUFFER_DESC vbd;
    vbd.Usage = D3D11_USAGE_IMMUTABLE;
    vbd.ByteWidth = sizeof(MeshVertex)* vertexCount;
    vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    vbd.CPUAccessFlags = 0;
    vbd.MiscFlags = 0;
    D3D11_SUBRESOURCE_DATA vinitData;
    vinitData.pSysMem = &(m_Mesh.m_Vertices[0]);
    m_pGraphics->getDevice()->CreateBuffer(&vbd, &vinitData, &mVB);

    // Pack the indices of all the meshes into one index buffer.
    D3D11_BUFFER_DESC ibd;
    ibd.Usage = D3D11_USAGE_DEFAULT;
    ibd.ByteWidth = sizeof(UINT)* m_IndicesSize;
    ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
    ibd.CPUAccessFlags = 0;
    ibd.MiscFlags = 0;
    D3D11_SUBRESOURCE_DATA iinitData;
    iinitData.pSysMem = &m_Mesh.m_Indices[0];
    m_pGraphics->getDevice()->CreateBuffer(&ibd, &iinitData, &mIB);

    // Create the constant buffer
    ibd.Usage = D3D11_USAGE_DEFAULT;
    ibd.ByteWidth = sizeof(ConstantBuffer);
    ibd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    ibd.CPUAccessFlags = 0;
    hr = m_pGraphics->getDevice()->CreateBuffer(&ibd, nullptr, &m_pConstantBuffer);
    if (FAILED(hr))
        return hr;

    return hr;
}
1
As a suggestion one thing you can look at for a good reference is terrain rending tutorials that can be found at rastertek.com under the DirectX 10 and DirectX 11 terrain tutorials under the "Historical Tutorials".Francis Cugler
(continued...) I would also like to add that under the series 2, there is a full version for the terrain tutorial for DirectX 11.Francis Cugler

1 Answers

1
votes

I would use unsigned char instead of BYTE when defining std::vector<BYTE> in(m*n) since it isn't a part of the C standard library so it is system dependent.

Also use a cast on this line

in.size());// number of bytes to read into buffer

to the actual parameter type of ifstream::read which is std::streamsize.

Like this:

(std::streamsize)in.size());// number of bytes to read into buffer

Since you're working with an 8-bit height map you should perhaps not just copy the value from the RAW file into your height map like this:

for (int i = 0; i < in.size(); i++)
    m_heightmap[i] = in[i];

Since each height map value is represented by an 8-bit integer you could try dividing the height map value as well as multiply it with some scale modifier. This would make it more convenient if you want to test your way to some good values. Purely for visual purposes...

for (int i = 0; i < in.size(); i++)
    m_heightmap[i] = (float)( in[i] / 255.0f ) * scaleModifier;