ahmed andre
ahmed andre

Reputation: 71

Rendering a terrain in directx 11

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;
}

Upvotes: 0

Views: 2037

Answers (1)

SvinSimpe
SvinSimpe

Reputation: 870

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;

Upvotes: 1

Related Questions