Added the camera class
Added the DDS Texture Loading for future use Added the gamepad class for future use Added first child method to the scenegraph Added RGB to intensity and lerp methods to the shared methods class Added the terrain node class with normals Fixed issue with submeshnode not passing the world transform to the actual meshes
This commit is contained in:
410
Graphics2/TerrainNode.cpp
Normal file
410
Graphics2/TerrainNode.cpp
Normal file
@ -0,0 +1,410 @@
|
||||
#include "TerrainNode.h"
|
||||
|
||||
#define WORLD_HEIGHT 512
|
||||
|
||||
TerrainNode::TerrainNode(wstring name, wstring heightMap, int widthX, int widthZ, int cellSizeX, int cellSizeZ) : SceneNode(name)
|
||||
{
|
||||
_heightMap = heightMap;
|
||||
|
||||
_widthX = widthX;
|
||||
_widthZ = widthZ;
|
||||
|
||||
_gridCols = _widthX + 1;
|
||||
_gridRows = _widthZ + 1;
|
||||
|
||||
_cellSizeX = cellSizeX;
|
||||
_cellSizeZ = cellSizeZ;
|
||||
|
||||
_polygonsCount = (_gridCols * _gridRows) * 2;
|
||||
_vertexCount = _polygonsCount * 2;
|
||||
_indiciesCount = _polygonsCount * 3;
|
||||
}
|
||||
|
||||
bool TerrainNode::Initialise()
|
||||
{
|
||||
_device = DirectXFramework::GetDXFramework()->GetDevice();
|
||||
_deviceContext = DirectXFramework::GetDXFramework()->GetDeviceContext();
|
||||
|
||||
if (_heightMap.length() > 0)
|
||||
{
|
||||
if (LoadHeightMap(_heightMap))
|
||||
{
|
||||
_usedHeightMap = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_usedHeightMap = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_usedHeightMap = false;
|
||||
}
|
||||
|
||||
GenerateTerrainData();
|
||||
GenerateBuffers();
|
||||
BuildShaders();
|
||||
BuildVertexLayout();
|
||||
BuildConstantBuffer();
|
||||
|
||||
BuildBlendState();
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Vector3D polygonNormal = Vector3D(0.0f, 0.0f, 0.0f);
|
||||
|
||||
VERTEX 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(0.0f, 1.0f);
|
||||
_terrainVerts.push_back(vertex);
|
||||
_terrainNormals.push_back(polygonNormal);
|
||||
|
||||
vertex = VERTEX();
|
||||
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(1.0f, 1.0f);
|
||||
_terrainVerts.push_back(vertex);
|
||||
_terrainNormals.push_back(polygonNormal);
|
||||
|
||||
vertex = VERTEX();
|
||||
vertex.Position = XMFLOAT3(x * _cellSizeX + centerWidth, GetHeightMapValueAt(currentIndex + offsetIndexZ), -z * _cellSizeZ + centerDepth);
|
||||
vertex.Normal = XMFLOAT3(0.0f, 0.0f, 0.0f);
|
||||
vertex.TexCoord = XMFLOAT2(0.0f, 0.0f);
|
||||
_terrainVerts.push_back(vertex);
|
||||
_terrainNormals.push_back(polygonNormal);
|
||||
|
||||
vertex = VERTEX();
|
||||
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(1.0f, 0.0f);
|
||||
_terrainVerts.push_back(vertex);
|
||||
_terrainNormals.push_back(polygonNormal);
|
||||
|
||||
_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++)
|
||||
{
|
||||
Vector3D vectorA = Vector3D(_terrainVerts[currentNormalIndex + 1].Position, _terrainVerts[currentNormalIndex].Position);
|
||||
Vector3D vectorB = Vector3D(_terrainVerts[currentNormalIndex + 2].Position, _terrainVerts[currentNormalIndex].Position);
|
||||
Vector3D polygonNormal = Vector3D::CrossProduct(vectorA, vectorB);
|
||||
|
||||
_terrainNormals[currentNormalIndex] += polygonNormal;
|
||||
_terrainNormals[currentNormalIndex + 1] += polygonNormal;
|
||||
_terrainNormals[currentNormalIndex + 2] += polygonNormal;
|
||||
_terrainNormals[currentNormalIndex + 3] += 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 < _terrainNormals.size(); i++)
|
||||
{
|
||||
_terrainNormals[i].Normalize();
|
||||
_terrainVerts[i].Normal = _terrainNormals[i].Get();
|
||||
}
|
||||
|
||||
_terrainNormals.clear();
|
||||
}
|
||||
|
||||
void TerrainNode::AddNormalToVertex(int row, int col, int vertexIndex, Vector3D normal)
|
||||
{
|
||||
int rowIndexOffset = row * _gridCols;
|
||||
int colIndexOffset = col;
|
||||
|
||||
int finalIndex = vertexIndex + ((rowIndexOffset + colIndexOffset) * 4);
|
||||
|
||||
if (row >= 0 && row < _gridRows && col >= 0 && col < _gridCols)
|
||||
{
|
||||
_terrainNormals[finalIndex] += normal;
|
||||
}
|
||||
if (row == _gridRows)
|
||||
{
|
||||
int test = 1;
|
||||
}
|
||||
}
|
||||
|
||||
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(VERTEX) * _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(&_worldTransformation) * viewTransformation * projectionTransformation;
|
||||
|
||||
// Draw the first cube
|
||||
CBUFFER cBuffer;
|
||||
cBuffer.completeTransformation = completeTransformation;
|
||||
cBuffer.worldTransformation = XMLoadFloat4x4(&_worldTransformation);
|
||||
cBuffer.ambientColor = 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, 1.0f);
|
||||
//cBuffer.LightColor = XMFLOAT4(SharedMethods::RGBValueToIntensity(0x89), 0.0f, 5.0f, 5.0f);
|
||||
//cBuffer.LightColor = _directionalLightColor;
|
||||
cBuffer.cameraPosition = DirectXFramework::GetDXFramework()->GetCamera()->GetRawCameraPosition();
|
||||
|
||||
_deviceContext->VSSetShader(_vertexShader.Get(), 0, 0);
|
||||
_deviceContext->PSSetShader(_pixelShader.Get(), 0, 0);
|
||||
_deviceContext->IASetInputLayout(_layout.Get());
|
||||
|
||||
// Update the constant buffer
|
||||
_deviceContext->VSSetConstantBuffers(0, 1, _constantBuffer.GetAddressOf());
|
||||
_deviceContext->UpdateSubresource(_constantBuffer.Get(), 0, 0, &cBuffer, 0, 0);
|
||||
|
||||
// Set the texture to be used by the pixel shader
|
||||
_deviceContext->PSSetShaderResources(0, 1, _texture.GetAddressOf());
|
||||
|
||||
UINT stride = sizeof(VERTEX);
|
||||
UINT offset = 0;
|
||||
_deviceContext->IASetVertexBuffers(0, 1, _vertexBuffer.GetAddressOf(), &stride, &offset);
|
||||
_deviceContext->IASetIndexBuffer(_indexBuffer.Get(), DXGI_FORMAT_R32_UINT, 0);
|
||||
cBuffer.diffuseCoefficient = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
cBuffer.specularCoefficient = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
cBuffer.shininess = 1.0f;
|
||||
cBuffer.opacity = 1.0f;
|
||||
// Update the constant buffer
|
||||
_deviceContext->VSSetConstantBuffers(0, 1, _constantBuffer.GetAddressOf());
|
||||
_deviceContext->UpdateSubresource(_constantBuffer.Get(), 0, 0, &cBuffer, 0, 0);
|
||||
_deviceContext->PSSetShaderResources(0, 1, _texture.GetAddressOf());
|
||||
_deviceContext->PSSetConstantBuffers(0, 1, _constantBuffer.GetAddressOf());
|
||||
_deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
//_deviceContext->RSSetState(_wireframeRasteriserState.Get());
|
||||
_deviceContext->DrawIndexed(_indiciesCount, 0, 0);
|
||||
|
||||
// Turn back face culling back on in case another renderer
|
||||
// relies on it
|
||||
_deviceContext->RSSetState(_defaultRasteriserState.Get());
|
||||
}
|
||||
|
||||
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"TerrainShadersNoBlend.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"TerrainShadersNoBlend.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(CBUFFER);
|
||||
bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
ThrowIfFailed(_device->CreateBuffer(&bufferDesc, NULL, _constantBuffer.GetAddressOf()));
|
||||
}
|
||||
|
||||
void TerrainNode::BuildBlendState()
|
||||
{
|
||||
D3D11_BLEND_DESC transparentDesc = { 0 };
|
||||
transparentDesc.AlphaToCoverageEnable = false;
|
||||
transparentDesc.IndependentBlendEnable = false;
|
||||
transparentDesc.RenderTarget[0].BlendEnable = true;
|
||||
transparentDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
|
||||
transparentDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
||||
transparentDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
||||
transparentDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ZERO;
|
||||
transparentDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
||||
transparentDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||
transparentDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||
ThrowIfFailed(_device->CreateBlendState(&transparentDesc, _transparentBlendState.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;
|
||||
}
|
Reference in New Issue
Block a user