
Added terrainBuffer struct Added shared methods to genereate random UV's and intensities Added water to the terrain Added random UV's to the shader Removed the vector3d class since DX can deal with that stuff...
651 lines
22 KiB
C++
651 lines
22 KiB
C++
#include "TerrainNode.h"
|
|
|
|
#define WORLD_HEIGHT 1024
|
|
|
|
TerrainNode::TerrainNode(wstring name, wstring heightMap, wstring seed, float waterHeight, wstring waterNormalMap, int widthX, int widthZ, int cellSizeX, int cellSizeZ) : SceneNode(name)
|
|
{
|
|
_heightMap = heightMap;
|
|
_seedString = seed;
|
|
_seedHash = std::hash<wstring>{}(_seedString);
|
|
|
|
srand(_seedHash);
|
|
|
|
_widthX = widthX;
|
|
_widthZ = widthZ;
|
|
|
|
_gridCols = _widthX + 1;
|
|
_gridRows = _widthZ + 1;
|
|
|
|
_cellSizeX = cellSizeX;
|
|
_cellSizeZ = cellSizeZ;
|
|
|
|
_waterHeight = waterHeight;
|
|
_waterNormalMapName = waterNormalMap;
|
|
|
|
_polygonsCount = (_gridCols * _gridRows) * 2;
|
|
_vertexCount = _polygonsCount * 2;
|
|
_indiciesCount = _polygonsCount * 3;
|
|
}
|
|
|
|
void TerrainNode::SetAmbientLight(XMFLOAT4 ambientLight)
|
|
{
|
|
_ambientLight = ambientLight;
|
|
}
|
|
|
|
void TerrainNode::SetWaterColor(XMFLOAT4 waterColor)
|
|
{
|
|
_waterColor = waterColor;
|
|
}
|
|
|
|
void TerrainNode::SetDirectionalLight(FXMVECTOR lightVector, XMFLOAT4 lightColor)
|
|
{
|
|
_directionalLightColor = lightColor;
|
|
XMStoreFloat4(&_directionalLightVector, lightVector);
|
|
}
|
|
|
|
void TerrainNode::SetCameraPosition(XMFLOAT4 cameraPosition)
|
|
{
|
|
_cameraPosition = cameraPosition;
|
|
}
|
|
|
|
bool TerrainNode::Initialise()
|
|
{
|
|
_device = DirectXFramework::GetDXFramework()->GetDevice();
|
|
_deviceContext = DirectXFramework::GetDXFramework()->GetDeviceContext();
|
|
|
|
if (_device.Get() == nullptr || _deviceContext.Get() == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (_heightMap.length() > 0)
|
|
{
|
|
if (LoadHeightMap(_heightMap))
|
|
{
|
|
_usedHeightMap = true;
|
|
}
|
|
else
|
|
{
|
|
_usedHeightMap = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_usedHeightMap = false;
|
|
}
|
|
|
|
GenerateTerrainData();
|
|
LoadTerrainTextures();
|
|
GenerateBlendMap();
|
|
BuildExtraMaps();
|
|
|
|
GenerateBuffers();
|
|
|
|
BuildShaders();
|
|
BuildVertexLayout();
|
|
BuildConstantBuffer();
|
|
BuildRendererStates();
|
|
return true;
|
|
}
|
|
|
|
void TerrainNode::GenerateTerrainData()
|
|
{
|
|
float totalWidth = (float)(_gridCols * _cellSizeX);
|
|
float totalDepth = (float)(_gridRows * _cellSizeZ);
|
|
|
|
float centerWidth = totalWidth * -0.5f;
|
|
float centerDepth = totalDepth * 0.5f;
|
|
|
|
_terrainStartX = centerWidth;
|
|
_terrainStartZ = centerDepth;
|
|
_terrainEndX = centerWidth + totalWidth - 1;
|
|
_terrainEndZ = centerDepth - totalDepth + 1;
|
|
|
|
float bu = 1.0f / (float)(_gridCols - 1u);
|
|
float bv = 1.0f / (float)(_gridRows - 1u);
|
|
|
|
int currentVertexCount = 0;
|
|
for (int z = 0; z < _gridRows; z++)
|
|
{
|
|
for (int x = 0; x < _gridCols; x++)
|
|
{
|
|
int currentIndex = (z * _gridCols) + x;
|
|
int offsetIndexX = 1;
|
|
if (x == _widthX)
|
|
{
|
|
offsetIndexX = 0;
|
|
}
|
|
int offsetIndexZ = _gridCols;
|
|
if (z == _widthZ)
|
|
{
|
|
offsetIndexZ = 0;
|
|
}
|
|
|
|
float rUA = 0.0f;
|
|
float rVA = rUA; // 0.0f;
|
|
float rUB = 1.0f;
|
|
float rVB = rUB;
|
|
|
|
|
|
/*int tumbleAmount = rand() % 10;
|
|
|
|
float prevUV = 0.0f;
|
|
bool firstTumble = true;
|
|
for (int ti = 0; ti < tumbleAmount; ti++)
|
|
{
|
|
prevUV = rVB;
|
|
rVB = rUB;
|
|
rUB = rVA;
|
|
rVA = rUA;
|
|
rUA = prevUV;
|
|
}*/
|
|
|
|
// TL
|
|
TerrainVertex vertex{};
|
|
vertex.Position = XMFLOAT3(x * _cellSizeX + centerWidth, GetHeightMapValueAt(currentIndex), (-z + 1) * _cellSizeZ + centerDepth);
|
|
vertex.Normal = XMFLOAT3(0.0f, 0.0f, 0.0f);
|
|
vertex.TexCoord = XMFLOAT2(rUA, rVA);
|
|
vertex.BlendMapTexCoord = XMFLOAT2((bu * x), (bv * z));
|
|
_terrainVerts.push_back(vertex);
|
|
|
|
// TR
|
|
vertex = TerrainVertex();
|
|
vertex.Position = XMFLOAT3((x + 1) * _cellSizeX + centerWidth, GetHeightMapValueAt(currentIndex + offsetIndexX), (-z + 1) * _cellSizeZ + centerDepth);
|
|
vertex.Normal = XMFLOAT3(0.0f, 0.0f, 0.0f);
|
|
vertex.TexCoord = XMFLOAT2(rUB, rVA);
|
|
vertex.BlendMapTexCoord = XMFLOAT2((bu * (x + 1)), (bv * z));
|
|
_terrainVerts.push_back(vertex);
|
|
|
|
// BL
|
|
vertex = TerrainVertex();
|
|
vertex.Position = XMFLOAT3(x * _cellSizeX + centerWidth, GetHeightMapValueAt(currentIndex + offsetIndexZ), -z * _cellSizeZ + centerDepth);
|
|
vertex.Normal = XMFLOAT3(0.0f, 0.0f, 0.0f);
|
|
vertex.TexCoord = XMFLOAT2(rUA, rVB);
|
|
vertex.BlendMapTexCoord = XMFLOAT2((bu * x), (bv * (z + 1)));
|
|
_terrainVerts.push_back(vertex);
|
|
|
|
// BR
|
|
vertex = TerrainVertex();
|
|
vertex.Position = XMFLOAT3((x + 1) * _cellSizeX + centerWidth, GetHeightMapValueAt(currentIndex + offsetIndexZ + offsetIndexX), -z * _cellSizeZ + centerDepth);
|
|
vertex.Normal = XMFLOAT3(0.0f, 0.0f, 0.0f);
|
|
vertex.TexCoord = XMFLOAT2(rUB, rVB);
|
|
vertex.BlendMapTexCoord = XMFLOAT2((bu * (x + 1)), (bv * (z + 1)));
|
|
_terrainVerts.push_back(vertex);
|
|
|
|
_indices.push_back(currentVertexCount);
|
|
_indices.push_back(currentVertexCount + 1);
|
|
_indices.push_back(currentVertexCount + 2);
|
|
|
|
_indices.push_back(currentVertexCount + 2);
|
|
_indices.push_back(currentVertexCount + 1);
|
|
_indices.push_back(currentVertexCount + 3);
|
|
currentVertexCount += 4;
|
|
}
|
|
}
|
|
|
|
int currentNormalIndex = 0;
|
|
for (int z = 0; z < _gridRows; z++)
|
|
{
|
|
for (int x = 0; x < _gridCols; x++)
|
|
{
|
|
XMVECTOR v1 = XMVectorSet(_terrainVerts[currentNormalIndex + 1].Position.x - _terrainVerts[currentNormalIndex].Position.x,
|
|
_terrainVerts[currentNormalIndex + 1].Position.y - _terrainVerts[currentNormalIndex].Position.y,
|
|
_terrainVerts[currentNormalIndex + 1].Position.z - _terrainVerts[currentNormalIndex].Position.z,
|
|
0.0f);
|
|
XMVECTOR v2 = XMVectorSet(_terrainVerts[currentNormalIndex + 2].Position.x - _terrainVerts[currentNormalIndex].Position.x,
|
|
_terrainVerts[currentNormalIndex + 2].Position.y - _terrainVerts[currentNormalIndex].Position.y,
|
|
_terrainVerts[currentNormalIndex + 2].Position.z - _terrainVerts[currentNormalIndex].Position.z,
|
|
0.0f);
|
|
|
|
XMVECTOR polygonNormal = XMVector3Cross(v1, v2);
|
|
|
|
XMStoreFloat3(&_terrainVerts[currentNormalIndex].Normal, XMVectorAdd(XMLoadFloat3(&_terrainVerts[currentNormalIndex].Normal), polygonNormal));
|
|
XMStoreFloat3(&_terrainVerts[currentNormalIndex + 1].Normal, XMVectorAdd(XMLoadFloat3(&_terrainVerts[currentNormalIndex + 1].Normal), polygonNormal));
|
|
XMStoreFloat3(&_terrainVerts[currentNormalIndex + 2].Normal, XMVectorAdd(XMLoadFloat3(&_terrainVerts[currentNormalIndex + 2].Normal), polygonNormal));
|
|
XMStoreFloat3(&_terrainVerts[currentNormalIndex + 3].Normal, XMVectorAdd(XMLoadFloat3(&_terrainVerts[currentNormalIndex + 3].Normal), polygonNormal));
|
|
|
|
AddNormalToVertex(z - 1, x - 1, 3, polygonNormal);
|
|
AddNormalToVertex(z - 1, x, 2, polygonNormal);
|
|
AddNormalToVertex(z - 1, x, 3, polygonNormal);
|
|
AddNormalToVertex(z - 1, x + 1, 2, polygonNormal);
|
|
|
|
AddNormalToVertex(z, x - 1, 1, polygonNormal);
|
|
AddNormalToVertex(z, x - 1, 3, polygonNormal);
|
|
AddNormalToVertex(z, x + 1, 0, polygonNormal);
|
|
AddNormalToVertex(z, x + 1, 2, polygonNormal);
|
|
AddNormalToVertex(z + 1, x - 1, 1, polygonNormal);
|
|
AddNormalToVertex(z + 1, x, 0, polygonNormal);
|
|
AddNormalToVertex(z + 1, x, 1, polygonNormal);
|
|
AddNormalToVertex(z + 1, x + 1, 0, polygonNormal);
|
|
|
|
currentNormalIndex += 4;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < _terrainVerts.size(); i++)
|
|
{
|
|
XMVECTOR currentNormal = XMLoadFloat3(&_terrainVerts[i].Normal);
|
|
//XMVECTOR normalised = XMVector3Normalize(currentNormal);
|
|
XMStoreFloat3(&_terrainVerts[i].Normal, XMVector3Normalize(currentNormal));
|
|
}
|
|
}
|
|
|
|
void TerrainNode::AddNormalToVertex(int row, int col, int vertexIndex, XMVECTOR normal)
|
|
{
|
|
int rowIndexOffset = row * _gridCols;
|
|
int colIndexOffset = col;
|
|
|
|
int finalIndex = vertexIndex + ((rowIndexOffset + colIndexOffset) * 4);
|
|
|
|
if (row >= 0 && row < (int)_gridRows && col >= 0 && col < (int)_gridCols)
|
|
{
|
|
XMStoreFloat3(&_terrainVerts[finalIndex].Normal, XMVectorAdd(XMLoadFloat3(&_terrainVerts[finalIndex].Normal), normal));
|
|
}
|
|
}
|
|
|
|
void TerrainNode::GenerateBuffers()
|
|
{
|
|
// Setup the structure that specifies how big the vertex
|
|
// buffer should be
|
|
D3D11_BUFFER_DESC vertexBufferDescriptor;
|
|
vertexBufferDescriptor.Usage = D3D11_USAGE_IMMUTABLE;
|
|
vertexBufferDescriptor.ByteWidth = sizeof(TerrainVertex) * _vertexCount;
|
|
vertexBufferDescriptor.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
|
vertexBufferDescriptor.CPUAccessFlags = 0;
|
|
vertexBufferDescriptor.MiscFlags = 0;
|
|
vertexBufferDescriptor.StructureByteStride = 0;
|
|
|
|
// Now set up a structure that tells DirectX where to get the
|
|
// data for the vertices from
|
|
D3D11_SUBRESOURCE_DATA vertexInitialisationData;
|
|
vertexInitialisationData.pSysMem = &_terrainVerts[0];
|
|
|
|
// and create the vertex buffer
|
|
ThrowIfFailed(_device->CreateBuffer(&vertexBufferDescriptor, &vertexInitialisationData, _vertexBuffer.GetAddressOf()));
|
|
|
|
// Setup the structure that specifies how big the index
|
|
// buffer should be
|
|
D3D11_BUFFER_DESC indexBufferDescriptor;
|
|
indexBufferDescriptor.Usage = D3D11_USAGE_IMMUTABLE;
|
|
indexBufferDescriptor.ByteWidth = sizeof(UINT) * _indiciesCount;
|
|
indexBufferDescriptor.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
|
indexBufferDescriptor.CPUAccessFlags = 0;
|
|
indexBufferDescriptor.MiscFlags = 0;
|
|
indexBufferDescriptor.StructureByteStride = 0;
|
|
|
|
// Now set up a structure that tells DirectX where to get the
|
|
// data for the indices from
|
|
D3D11_SUBRESOURCE_DATA indexInitialisationData;
|
|
indexInitialisationData.pSysMem = &_indices[0];
|
|
|
|
// and create the index buffer
|
|
ThrowIfFailed(_device->CreateBuffer(&indexBufferDescriptor, &indexInitialisationData, _indexBuffer.GetAddressOf()));
|
|
}
|
|
|
|
void TerrainNode::Render()
|
|
{
|
|
XMMATRIX projectionTransformation = DirectXFramework::GetDXFramework()->GetProjectionTransformation();
|
|
XMMATRIX viewTransformation = DirectXFramework::GetDXFramework()->GetCamera()->GetViewMatrix();
|
|
|
|
XMMATRIX completeTransformation = XMLoadFloat4x4(&_combinedWorldTransformation) * viewTransformation * projectionTransformation;
|
|
|
|
// Draw the first cube
|
|
TCBUFFER cBuffer;
|
|
cBuffer.completeTransformation = completeTransformation;
|
|
cBuffer.worldTransformation = XMLoadFloat4x4(&_worldTransformation);
|
|
cBuffer.ambientColor = _ambientLight; // XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f);
|
|
//cBuffer.AmbientColor = XMFLOAT4(SharedMethods::RGBValueToIntensity(0xfd), 0.0f, 1.0f, 1.0f); //XMFLOAT4(1, 1, 1, 1); //_ambientLight;
|
|
cBuffer.lightVector = XMVector4Normalize(XMLoadFloat4(&_directionalLightVector));
|
|
//cBuffer.lightColor = XMFLOAT4(0.5f, 0.5f, 0.5f, 0.5f);
|
|
//cBuffer.LightColor = XMFLOAT4(SharedMethods::RGBValueToIntensity(0x89), 0.0f, 5.0f, 5.0f);
|
|
cBuffer.lightColor = _directionalLightColor;
|
|
XMStoreFloat4(&cBuffer.cameraPosition, DirectXFramework::GetDXFramework()->GetCamera()->GetCameraPosition());
|
|
|
|
cBuffer.waterHeight = _waterHeight;
|
|
cBuffer.waterShininess = 15.0f;
|
|
cBuffer.waterColor = _waterColor;
|
|
|
|
_deviceContext->PSSetShaderResources(0, 1, _blendMapResourceView.GetAddressOf());
|
|
_deviceContext->PSSetShaderResources(1, 1, _texturesResourceView.GetAddressOf());
|
|
_deviceContext->PSSetShaderResources(2, 1, _waterNormalMap.GetAddressOf());
|
|
_deviceContext->PSSetShaderResources(3, 1, _rngNoiseMap.GetAddressOf());
|
|
|
|
_deviceContext->VSSetShader(_vertexShader.Get(), 0, 0);
|
|
_deviceContext->PSSetShader(_pixelShader.Get(), 0, 0);
|
|
_deviceContext->IASetInputLayout(_layout.Get());
|
|
|
|
UINT stride = sizeof(TerrainVertex);
|
|
UINT offset = 0;
|
|
_deviceContext->IASetVertexBuffers(0, 1, _vertexBuffer.GetAddressOf(), &stride, &offset);
|
|
_deviceContext->IASetIndexBuffer(_indexBuffer.Get(), DXGI_FORMAT_R32_UINT, 0);
|
|
cBuffer.diffuseCoefficient = XMFLOAT4(0.8f, 0.8f, 0.8f, 1.0f);
|
|
cBuffer.specularCoefficient = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
|
|
cBuffer.shininess = 10.0f;
|
|
cBuffer.opacity = 1.0f;
|
|
|
|
// Update the constant buffer
|
|
_deviceContext->VSSetConstantBuffers(0, 1, _constantBuffer.GetAddressOf());
|
|
_deviceContext->PSSetConstantBuffers(0, 1, _constantBuffer.GetAddressOf());
|
|
_deviceContext->UpdateSubresource(_constantBuffer.Get(), 0, 0, &cBuffer, 0, 0);
|
|
_deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
|
|
|
//_deviceContext->RSSetState(_wireframeRasteriserState.Get());
|
|
_deviceContext->DrawIndexed(_indiciesCount, 0, 0);
|
|
}
|
|
|
|
void TerrainNode::Shutdown(void)
|
|
{
|
|
}
|
|
|
|
void TerrainNode::BuildShaders()
|
|
{
|
|
DWORD shaderCompileFlags = 0;
|
|
#if defined( _DEBUG )
|
|
shaderCompileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
|
|
#endif
|
|
|
|
ComPtr<ID3DBlob> compilationMessages = nullptr;
|
|
|
|
//Compile vertex shader
|
|
HRESULT hr = D3DCompileFromFile(L"TerrainShaders.hlsl",
|
|
nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE,
|
|
"VShader", "vs_5_0",
|
|
shaderCompileFlags, 0,
|
|
_vertexShaderByteCode.GetAddressOf(),
|
|
compilationMessages.GetAddressOf());
|
|
|
|
if (compilationMessages.Get() != nullptr)
|
|
{
|
|
// If there were any compilation messages, display them
|
|
MessageBoxA(0, (char*)compilationMessages->GetBufferPointer(), 0, 0);
|
|
}
|
|
// Even if there are no compiler messages, check to make sure there were no other errors.
|
|
ThrowIfFailed(hr);
|
|
ThrowIfFailed(_device->CreateVertexShader(_vertexShaderByteCode->GetBufferPointer(), _vertexShaderByteCode->GetBufferSize(), NULL, _vertexShader.GetAddressOf()));
|
|
|
|
// Compile pixel shader
|
|
hr = D3DCompileFromFile(L"TerrainShaders.hlsl",
|
|
nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE,
|
|
"PShader", "ps_5_0",
|
|
shaderCompileFlags, 0,
|
|
_pixelShaderByteCode.GetAddressOf(),
|
|
compilationMessages.GetAddressOf());
|
|
|
|
if (compilationMessages.Get() != nullptr)
|
|
{
|
|
// If there were any compilation messages, display them
|
|
MessageBoxA(0, (char*)compilationMessages->GetBufferPointer(), 0, 0);
|
|
}
|
|
ThrowIfFailed(hr);
|
|
ThrowIfFailed(_device->CreatePixelShader(_pixelShaderByteCode->GetBufferPointer(), _pixelShaderByteCode->GetBufferSize(), NULL, _pixelShader.GetAddressOf()));
|
|
}
|
|
|
|
|
|
void TerrainNode::BuildVertexLayout()
|
|
{
|
|
// Create the vertex input layout. This tells DirectX the format
|
|
// of each of the vertices we are sending to it.
|
|
|
|
D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
|
|
{
|
|
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
|
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT , D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
|
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT , D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
|
{ "TEXCOORD", 1, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT , D3D11_INPUT_PER_VERTEX_DATA, 0 }
|
|
};
|
|
ThrowIfFailed(_device->CreateInputLayout(vertexDesc, ARRAYSIZE(vertexDesc), _vertexShaderByteCode->GetBufferPointer(), _vertexShaderByteCode->GetBufferSize(), _layout.GetAddressOf()));
|
|
}
|
|
|
|
void TerrainNode::BuildConstantBuffer()
|
|
{
|
|
D3D11_BUFFER_DESC bufferDesc;
|
|
ZeroMemory(&bufferDesc, sizeof(bufferDesc));
|
|
bufferDesc.Usage = D3D11_USAGE_DEFAULT;
|
|
bufferDesc.ByteWidth = sizeof(TCBUFFER);
|
|
bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
|
ThrowIfFailed(_device->CreateBuffer(&bufferDesc, NULL, _constantBuffer.GetAddressOf()));
|
|
}
|
|
|
|
void TerrainNode::BuildRendererStates()
|
|
{
|
|
// Set default and wireframe rasteriser states
|
|
D3D11_RASTERIZER_DESC rasteriserDesc;
|
|
rasteriserDesc.FillMode = D3D11_FILL_SOLID;
|
|
rasteriserDesc.CullMode = D3D11_CULL_BACK;
|
|
rasteriserDesc.FrontCounterClockwise = false;
|
|
rasteriserDesc.DepthBias = 0;
|
|
rasteriserDesc.SlopeScaledDepthBias = 0.0f;
|
|
rasteriserDesc.DepthBiasClamp = 0.0f;
|
|
rasteriserDesc.DepthClipEnable = true;
|
|
rasteriserDesc.ScissorEnable = false;
|
|
rasteriserDesc.MultisampleEnable = false;
|
|
rasteriserDesc.AntialiasedLineEnable = false;
|
|
ThrowIfFailed(_device->CreateRasterizerState(&rasteriserDesc, _defaultRasteriserState.GetAddressOf()));
|
|
rasteriserDesc.FillMode = D3D11_FILL_WIREFRAME;
|
|
ThrowIfFailed(_device->CreateRasterizerState(&rasteriserDesc, _wireframeRasteriserState.GetAddressOf()));
|
|
}
|
|
|
|
bool TerrainNode::LoadHeightMap(wstring heightMapFilename)
|
|
{
|
|
unsigned int mapSize = _gridCols * _gridRows;
|
|
USHORT* rawFileValues = new USHORT[mapSize];
|
|
|
|
std::ifstream inputHeightMap;
|
|
inputHeightMap.open(heightMapFilename.c_str(), std::ios_base::binary);
|
|
if (!inputHeightMap)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
inputHeightMap.read((char*)rawFileValues, mapSize * 2);
|
|
inputHeightMap.close();
|
|
|
|
// Normalise BYTE values to the range 0.0f - 1.0f;
|
|
for (unsigned int i = 0; i < mapSize; i++)
|
|
{
|
|
_heightValues.push_back((float)rawFileValues[i] / 65536);
|
|
}
|
|
delete[] rawFileValues;
|
|
return true;
|
|
}
|
|
|
|
float TerrainNode::GetHeightMapValueAt(int index)
|
|
{
|
|
float result = 0;
|
|
if (_usedHeightMap)
|
|
{
|
|
result = _heightValues[index] * WORLD_HEIGHT; // +(rand() % 10);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void TerrainNode::LoadTerrainTextures()
|
|
{
|
|
// Change the paths below as appropriate for your use
|
|
wstring terrainTextureNames[5] = { L"Textures\\grass.dds", L"Textures\\darkdirt.dds", L"Textures\\stone.dds", L"Textures\\lightdirt.dds", L"Textures\\snow.dds" };
|
|
|
|
// Load the textures from the files
|
|
ComPtr<ID3D11Resource> terrainTextures[5];
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
ThrowIfFailed(CreateDDSTextureFromFileEx(_device.Get(),
|
|
_deviceContext.Get(),
|
|
terrainTextureNames[i].c_str(),
|
|
0,
|
|
D3D11_USAGE_IMMUTABLE,
|
|
D3D11_BIND_SHADER_RESOURCE,
|
|
0,
|
|
0,
|
|
false,
|
|
terrainTextures[i].GetAddressOf(),
|
|
nullptr
|
|
));
|
|
}
|
|
// Now create the Texture2D arrary. We assume all textures in the
|
|
// array have the same format and dimensions
|
|
|
|
D3D11_TEXTURE2D_DESC textureDescription;
|
|
ComPtr<ID3D11Texture2D> textureInterface;
|
|
terrainTextures[0].As<ID3D11Texture2D>(&textureInterface);
|
|
textureInterface->GetDesc(&textureDescription);
|
|
|
|
D3D11_TEXTURE2D_DESC textureArrayDescription;
|
|
textureArrayDescription.Width = textureDescription.Width;
|
|
textureArrayDescription.Height = textureDescription.Height;
|
|
textureArrayDescription.MipLevels = textureDescription.MipLevels;
|
|
textureArrayDescription.ArraySize = 5;
|
|
textureArrayDescription.Format = textureDescription.Format;
|
|
textureArrayDescription.SampleDesc.Count = 1;
|
|
textureArrayDescription.SampleDesc.Quality = 0;
|
|
textureArrayDescription.Usage = D3D11_USAGE_DEFAULT;
|
|
textureArrayDescription.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
|
textureArrayDescription.CPUAccessFlags = 0;
|
|
textureArrayDescription.MiscFlags = 0;
|
|
|
|
ComPtr<ID3D11Texture2D> textureArray = 0;
|
|
ThrowIfFailed(_device->CreateTexture2D(&textureArrayDescription, 0, textureArray.GetAddressOf()));
|
|
|
|
// Copy individual texture elements into texture array.
|
|
|
|
for (UINT i = 0; i < 5; i++)
|
|
{
|
|
// For each mipmap level...
|
|
for (UINT mipLevel = 0; mipLevel < textureDescription.MipLevels; mipLevel++)
|
|
{
|
|
_deviceContext->CopySubresourceRegion(textureArray.Get(),
|
|
D3D11CalcSubresource(mipLevel, i, textureDescription.MipLevels),
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
terrainTextures[i].Get(),
|
|
mipLevel,
|
|
nullptr
|
|
);
|
|
}
|
|
}
|
|
|
|
// Create a resource view to the texture array.
|
|
D3D11_SHADER_RESOURCE_VIEW_DESC viewDescription;
|
|
viewDescription.Format = textureArrayDescription.Format;
|
|
viewDescription.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
|
|
viewDescription.Texture2DArray.MostDetailedMip = 0;
|
|
viewDescription.Texture2DArray.MipLevels = textureArrayDescription.MipLevels;
|
|
viewDescription.Texture2DArray.FirstArraySlice = 0;
|
|
viewDescription.Texture2DArray.ArraySize = 5;
|
|
|
|
ThrowIfFailed(_device->CreateShaderResourceView(textureArray.Get(), &viewDescription, _texturesResourceView.GetAddressOf()));
|
|
}
|
|
|
|
void TerrainNode::GenerateBlendMap()
|
|
{
|
|
RGBA snowTops = RGBA{ 0u, 0u, 0u, 255u };
|
|
RGBA grassLand = RGBA{ 0u, 0u, 50u, 0u };
|
|
RGBA lightDirt = RGBA{ 50u, 0u, 255u, 0u };
|
|
RGBA darkDirt = RGBA{ 255u, 0u, 0u, 0u };
|
|
|
|
vector<RGBA> colorSteps = {darkDirt, lightDirt, grassLand, grassLand, grassLand, snowTops};
|
|
|
|
ColorGradient terrainBlendGradient = ColorGradient(30.0f, 650.0f, colorSteps);
|
|
|
|
// Note that _numberOfRows and _numberOfColumns need to be setup
|
|
// to the number of rows and columns in your grid in order for this
|
|
// to work.
|
|
DWORD* blendMap = new DWORD[_gridCols * _gridRows];
|
|
DWORD* blendMapPtr = blendMap;
|
|
BYTE r;
|
|
BYTE g;
|
|
BYTE b;
|
|
BYTE a;
|
|
|
|
DWORD index = 0;
|
|
for (DWORD i = 0; i < _gridRows; i++)
|
|
{
|
|
for (DWORD j = 0; j < _gridCols; j++)
|
|
{
|
|
|
|
// Calculate the appropriate blend colour for the
|
|
// current location in the blend map. This has been
|
|
// left as an exercise for you. You need to calculate
|
|
// appropriate values for the r, g, b and a values (each
|
|
// between 0 and 255). The code below combines these
|
|
// into a DWORD (32-bit value) and stores it in the blend map.
|
|
|
|
int currentIndex = ((i * _gridCols) + j) * 4;
|
|
|
|
float totalHeights = 0.0f;
|
|
float biggestSlope = 0.0f;
|
|
|
|
for (int si = 0; si < 4; si++)
|
|
{
|
|
totalHeights += _terrainVerts[currentIndex + si].Position.y;
|
|
if (_terrainVerts[currentIndex + si].Normal.y > biggestSlope)
|
|
{
|
|
biggestSlope = _terrainVerts[currentIndex + si].Normal.y;
|
|
}
|
|
}
|
|
|
|
float avgHeight = totalHeights / 4.0f;
|
|
|
|
RGBA currentBlend = terrainBlendGradient.GetRGBAValue(avgHeight);
|
|
r = currentBlend.red;
|
|
g = currentBlend.green;
|
|
b = currentBlend.blue;
|
|
a = currentBlend.alpha;
|
|
|
|
DWORD mapValue = (a << 24) + (b << 16) + (g << 8) + r;
|
|
*blendMapPtr++ = mapValue;
|
|
}
|
|
}
|
|
D3D11_TEXTURE2D_DESC blendMapDescription;
|
|
blendMapDescription.Width = _gridCols;
|
|
blendMapDescription.Height = _gridRows;
|
|
blendMapDescription.MipLevels = 1;
|
|
blendMapDescription.ArraySize = 1;
|
|
blendMapDescription.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
blendMapDescription.SampleDesc.Count = 1;
|
|
blendMapDescription.SampleDesc.Quality = 0;
|
|
blendMapDescription.Usage = D3D11_USAGE_DEFAULT;
|
|
blendMapDescription.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
|
blendMapDescription.CPUAccessFlags = 0;
|
|
blendMapDescription.MiscFlags = 0;
|
|
|
|
D3D11_SUBRESOURCE_DATA blendMapInitialisationData;
|
|
blendMapInitialisationData.pSysMem = blendMap;
|
|
blendMapInitialisationData.SysMemPitch = 4 * _gridCols;
|
|
|
|
ComPtr<ID3D11Texture2D> blendMapTexture;
|
|
ThrowIfFailed(_device->CreateTexture2D(&blendMapDescription, &blendMapInitialisationData, blendMapTexture.GetAddressOf()));
|
|
|
|
// Create a resource view to the texture array.
|
|
D3D11_SHADER_RESOURCE_VIEW_DESC viewDescription;
|
|
viewDescription.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
viewDescription.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
|
viewDescription.Texture2D.MostDetailedMip = 0;
|
|
viewDescription.Texture2D.MipLevels = 1;
|
|
|
|
ThrowIfFailed(_device->CreateShaderResourceView(blendMapTexture.Get(), &viewDescription, _blendMapResourceView.GetAddressOf()));
|
|
delete[] blendMap;
|
|
}
|
|
|
|
void TerrainNode::BuildExtraMaps()
|
|
{
|
|
// Note that in order to use CreateWICTextureFromFile, we
|
|
// need to ensure we make a call to CoInitializeEx in our
|
|
// Initialise method (and make the corresponding call to
|
|
// CoUninitialize in the Shutdown method). Otherwise,
|
|
// the following call will throw an exception
|
|
ThrowIfFailed(CreateWICTextureFromFile(_device.Get(),
|
|
_deviceContext.Get(),
|
|
_waterNormalMapName.c_str(),
|
|
nullptr,
|
|
_waterNormalMap.GetAddressOf()
|
|
));
|
|
|
|
ThrowIfFailed(CreateWICTextureFromFile(_device.Get(),
|
|
_deviceContext.Get(),
|
|
L"Textures\\noiseMap.png",
|
|
nullptr,
|
|
_rngNoiseMap.GetAddressOf()
|
|
));
|
|
} |