#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{}(_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 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 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 textureInterface; terrainTextures[0].As(&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 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 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 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() )); }