Reputation: 71
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.be
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
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