diff --git a/enginecustom/applicationclass.cpp b/enginecustom/applicationclass.cpp index 06c2289..d8c8f81 100644 --- a/enginecustom/applicationclass.cpp +++ b/enginecustom/applicationclass.cpp @@ -22,6 +22,7 @@ ApplicationClass::ApplicationClass() m_TextString3 = 0; m_Fps = 0; m_FpsString = 0; + m_NormalMapShader = 0; } @@ -73,6 +74,16 @@ bool ApplicationClass::Initialize(int screenWidth, int screenHeight, HWND hwnd) m_Camera->SetPosition(0.0f, 0.0f, -12.0f); m_Camera->SetRotation(0.0f, 0.0f, 0.0f); + // Create and initialize the normal map shader object. + m_NormalMapShader = new NormalMapShaderClass; + + result = m_NormalMapShader->Initialize(m_Direct3D->GetDevice(), hwnd); + if (!result) + { + MessageBox(hwnd, L"Could not initialize the normal map shader object.", L"Error", MB_OK); + return false; + } + // Create and initialize the font shader object. m_FontShader = new FontShaderClass; @@ -208,7 +219,7 @@ bool ApplicationClass::Initialize(int screenWidth, int screenHeight, HWND hwnd) // Set the file name of the textures. strcpy_s(textureFilename1, "stone01.tga"); - strcpy_s(textureFilename2, "dirt01.tga"); + strcpy_s(textureFilename2, "normal01.tga"); strcpy_s(textureFilename3, "alpha01.tga"); // Create and initialize the model object. @@ -232,6 +243,12 @@ bool ApplicationClass::Initialize(int screenWidth, int screenHeight, HWND hwnd) return false; } + // Create and initialize the light object. + m_Light = new LightClass; + + m_Light->SetDiffuseColor(1.0f, 1.0f, 1.0f, 1.0f); + m_Light->SetDirection(0.0f, 0.0f, 1.0f); + // Set the number of lights we will use. m_numLights = 4; @@ -389,22 +406,6 @@ void ApplicationClass::Shutdown() m_LightShader = 0; } - // Release the light shader object. - if (m_LightShader) - { - m_LightShader->Shutdown(); - delete m_LightShader; - m_LightShader = 0; - } - - // Release the light map shader object. - if (m_LightMapShader) - { - m_LightMapShader->Shutdown(); - delete m_LightMapShader; - m_LightMapShader = 0; - } - // Release the model object. if (m_Model) { @@ -413,6 +414,14 @@ void ApplicationClass::Shutdown() m_Model = 0; } + // Release the normal map shader object. + if (m_NormalMapShader) + { + m_NormalMapShader->Shutdown(); + delete m_NormalMapShader; + m_NormalMapShader = 0; + } + // Release the multitexture shader object. if (m_MultiTextureShader) { @@ -469,7 +478,7 @@ bool ApplicationClass::Frame(InputClass* Input) bool result, mouseDown; float frameTime; - static float rotation = 0.0f; + static float rotation = 360.0f; static float x = 6.f; static float y = 3.f; static float z = 0.f; @@ -687,11 +696,18 @@ bool ApplicationClass::Render(float rotation, float x, float y, float z) // return false; //} - // Alphamapping - result = m_AlphaMapShader->Render(m_Direct3D->GetDeviceContext(), m_Model->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix, + /*result = m_AlphaMapShader->Render(m_Direct3D->GetDeviceContext(), m_Model->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix, m_Model->GetTexture(0), m_Model->GetTexture(1), m_Model->GetTexture(2)); if (!result) + { + return false; + }*/ + + //Normal Mapping + result = m_NormalMapShader->Render(m_Direct3D->GetDeviceContext(), m_Model->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix, + m_Model->GetTexture(0), m_Model->GetTexture(1), m_Light->GetDirection(), m_Light->GetDiffuseColor()); + if (!result) { return false; } diff --git a/enginecustom/applicationclass.h b/enginecustom/applicationclass.h index 906c1b5..90f5d47 100644 --- a/enginecustom/applicationclass.h +++ b/enginecustom/applicationclass.h @@ -22,6 +22,8 @@ #include "textclass.h" #include "fpsclass.h" #include "inputclass.h" +#include "normalmapshaderclass.h" + ///////////// // GLOBALS // @@ -73,6 +75,7 @@ private: FpsClass* m_Fps; TextClass* m_FpsString; int m_previousFps; + NormalMapShaderClass* m_NormalMapShader; }; #endif diff --git a/enginecustom/enginecustom.vcxproj b/enginecustom/enginecustom.vcxproj index bb17b1f..ab41f30 100644 --- a/enginecustom/enginecustom.vcxproj +++ b/enginecustom/enginecustom.vcxproj @@ -36,6 +36,7 @@ + @@ -59,6 +60,7 @@ + @@ -77,6 +79,8 @@ + + @@ -105,6 +109,7 @@ + diff --git a/enginecustom/enginecustom.vcxproj.filters b/enginecustom/enginecustom.vcxproj.filters index 5fc3cd9..5d19cc1 100644 --- a/enginecustom/enginecustom.vcxproj.filters +++ b/enginecustom/enginecustom.vcxproj.filters @@ -93,6 +93,9 @@ Fichiers sources + + Fichiers sources + @@ -158,6 +161,9 @@ Fichiers d%27en-tĂȘte + + Fichiers d%27en-tĂȘte + @@ -184,6 +190,9 @@ assets + + assets + @@ -229,6 +238,12 @@ texture + + shader + + + shader + diff --git a/enginecustom/modelclass.cpp b/enginecustom/modelclass.cpp index 122183e..ff2f5ce 100644 --- a/enginecustom/modelclass.cpp +++ b/enginecustom/modelclass.cpp @@ -31,6 +31,9 @@ bool ModelClass::Initialize(ID3D11Device* device, ID3D11DeviceContext* deviceCon return false; } + // Calculate the tangent and binormal vectors for the model. + CalculateModelVectors(); + // Initialize the vertex and index buffers. result = InitializeBuffers(device); if (!result) @@ -104,6 +107,8 @@ bool ModelClass::InitializeBuffers(ID3D11Device* device) vertices[i].position = XMFLOAT3(m_model[i].x, m_model[i].y, m_model[i].z); vertices[i].texture = XMFLOAT2(m_model[i].tu, m_model[i].tv); vertices[i].normal = XMFLOAT3(m_model[i].nx, m_model[i].ny, m_model[i].nz); + vertices[i].tangent = XMFLOAT3(m_model[i].tx, m_model[i].ty, m_model[i].tz); + vertices[i].binormal = XMFLOAT3(m_model[i].bx, m_model[i].by, m_model[i].bz); indices[i] = i; } @@ -201,6 +206,7 @@ void ModelClass::RenderBuffers(ID3D11DeviceContext* deviceContext) return; } + bool ModelClass::LoadTextures(ID3D11Device* device, ID3D11DeviceContext* deviceContext, char* filename1, char* filename2, char* filename3) { bool result; @@ -302,6 +308,128 @@ bool ModelClass::LoadModel(char* filename) return true; } +void ModelClass::CalculateModelVectors() +{ + int faceCount, i, index; + TempVertexType vertex1, vertex2, vertex3; + VectorType tangent, binormal; + + + // Calculate the number of faces in the model. + faceCount = m_vertexCount / 3; + + // Initialize the index to the model data. + index = 0; + + // Go through all the faces and calculate the the tangent and binormal vectors. + for (i = 0; i < faceCount; i++) + { + // Get the three vertices for this face from the model. + vertex1.x = m_model[index].x; + vertex1.y = m_model[index].y; + vertex1.z = m_model[index].z; + vertex1.tu = m_model[index].tu; + vertex1.tv = m_model[index].tv; + index++; + + vertex2.x = m_model[index].x; + vertex2.y = m_model[index].y; + vertex2.z = m_model[index].z; + vertex2.tu = m_model[index].tu; + vertex2.tv = m_model[index].tv; + index++; + + vertex3.x = m_model[index].x; + vertex3.y = m_model[index].y; + vertex3.z = m_model[index].z; + vertex3.tu = m_model[index].tu; + vertex3.tv = m_model[index].tv; + index++; + + // Calculate the tangent and binormal of that face. + CalculateTangentBinormal(vertex1, vertex2, vertex3, tangent, binormal); + + // Store the tangent and binormal for this face back in the model structure. + m_model[index - 1].tx = tangent.x; + m_model[index - 1].ty = tangent.y; + m_model[index - 1].tz = tangent.z; + m_model[index - 1].bx = binormal.x; + m_model[index - 1].by = binormal.y; + m_model[index - 1].bz = binormal.z; + + m_model[index - 2].tx = tangent.x; + m_model[index - 2].ty = tangent.y; + m_model[index - 2].tz = tangent.z; + m_model[index - 2].bx = binormal.x; + m_model[index - 2].by = binormal.y; + m_model[index - 2].bz = binormal.z; + + m_model[index - 3].tx = tangent.x; + m_model[index - 3].ty = tangent.y; + m_model[index - 3].tz = tangent.z; + m_model[index - 3].bx = binormal.x; + m_model[index - 3].by = binormal.y; + m_model[index - 3].bz = binormal.z; + } + + return; +} + +void ModelClass::CalculateTangentBinormal(TempVertexType vertex1, TempVertexType vertex2, TempVertexType vertex3, VectorType& tangent, VectorType& binormal) +{ + float vector1[3], vector2[3]; + float tuVector[2], tvVector[2]; + float den; + float length; + + + // Calculate the two vectors for this face. + vector1[0] = vertex2.x - vertex1.x; + vector1[1] = vertex2.y - vertex1.y; + vector1[2] = vertex2.z - vertex1.z; + + vector2[0] = vertex3.x - vertex1.x; + vector2[1] = vertex3.y - vertex1.y; + vector2[2] = vertex3.z - vertex1.z; + + // Calculate the tu and tv texture space vectors. + tuVector[0] = vertex2.tu - vertex1.tu; + tvVector[0] = vertex2.tv - vertex1.tv; + + tuVector[1] = vertex3.tu - vertex1.tu; + tvVector[1] = vertex3.tv - vertex1.tv; + + // Calculate the denominator of the tangent/binormal equation. + den = 1.0f / (tuVector[0] * tvVector[1] - tuVector[1] * tvVector[0]); + + // Calculate the cross products and multiply by the coefficient to get the tangent and binormal. + tangent.x = (tvVector[1] * vector1[0] - tvVector[0] * vector2[0]) * den; + tangent.y = (tvVector[1] * vector1[1] - tvVector[0] * vector2[1]) * den; + tangent.z = (tvVector[1] * vector1[2] - tvVector[0] * vector2[2]) * den; + + binormal.x = (tuVector[0] * vector2[0] - tuVector[1] * vector1[0]) * den; + binormal.y = (tuVector[0] * vector2[1] - tuVector[1] * vector1[1]) * den; + binormal.z = (tuVector[0] * vector2[2] - tuVector[1] * vector1[2]) * den; + + // Calculate the length of this normal. + length = sqrt((tangent.x * tangent.x) + (tangent.y * tangent.y) + (tangent.z * tangent.z)); + + // Normalize the normal and then store it + tangent.x = tangent.x / length; + tangent.y = tangent.y / length; + tangent.z = tangent.z / length; + + // Calculate the length of this normal. + length = sqrt((binormal.x * binormal.x) + (binormal.y * binormal.y) + (binormal.z * binormal.z)); + + // Normalize the normal and then store it + binormal.x = binormal.x / length; + binormal.y = binormal.y / length; + binormal.z = binormal.z / length; + + return; +} + void ModelClass::ReleaseModel() { if (m_model) diff --git a/enginecustom/modelclass.h b/enginecustom/modelclass.h index fb2450a..7116f9d 100644 --- a/enginecustom/modelclass.h +++ b/enginecustom/modelclass.h @@ -32,6 +32,8 @@ private: XMFLOAT3 position; XMFLOAT2 texture; XMFLOAT3 normal; + XMFLOAT3 tangent; + XMFLOAT3 binormal; }; struct ModelType @@ -39,6 +41,8 @@ private: float x, y, z; float tu, tv; float nx, ny, nz; + float tx, ty, tz; + float bx, by, bz; }; struct Vertex { @@ -53,6 +57,18 @@ private: float nx, ny, nz; }; + struct TempVertexType + { + float x, y, z; + float tu, tv; + float nx, ny, nz; + }; + + struct VectorType + { + float x, y, z; + }; + struct Face { int v1, v2, v3; int t1, t2, t3; @@ -81,6 +97,9 @@ private: bool LoadModel(char*); void ReleaseModel(); + void CalculateModelVectors(); + void CalculateTangentBinormal(TempVertexType, TempVertexType, TempVertexType, VectorType&, VectorType&); + private: ID3D11Buffer* m_vertexBuffer, * m_indexBuffer; int m_vertexCount, m_indexCount; diff --git a/enginecustom/normal01.tga b/enginecustom/normal01.tga new file mode 100644 index 0000000..dbcd466 Binary files /dev/null and b/enginecustom/normal01.tga differ diff --git a/enginecustom/normalmap.ps b/enginecustom/normalmap.ps new file mode 100644 index 0000000..1b6ecc3 --- /dev/null +++ b/enginecustom/normalmap.ps @@ -0,0 +1,71 @@ +///////////// +// GLOBALS // +///////////// + +Texture2D shaderTexture1 : register(t0); +Texture2D shaderTexture2 : register(t1); +SamplerState SampleType : register(s0); + +cbuffer LightBuffer +{ + float4 diffuseColor; + float3 lightDirection; + float padding; +}; + + +////////////// +// TYPEDEFS // +////////////// + +struct PixelInputType +{ + float4 position : SV_POSITION; + float2 tex : TEXCOORD0; + float3 normal : NORMAL; + float3 tangent : TANGENT; + float3 binormal : BINORMAL; +}; + +//////////////////////////////////////////////////////////////////////////////// +// Pixel Shader +//////////////////////////////////////////////////////////////////////////////// +float4 NormalMapPixelShader(PixelInputType input) : SV_TARGET +{ + float4 textureColor; + float4 bumpMap; + float3 bumpNormal; + float3 lightDir; + float lightIntensity; + float4 color; + + + // Sample the pixel color from the color texture at this location. + textureColor = shaderTexture1.Sample(SampleType, input.tex); + + // Sample the pixel from the normal map. + bumpMap = shaderTexture2.Sample(SampleType, input.tex); + + // Expand the range of the normal value from (0, +1) to (-1, +1). + bumpMap = (bumpMap * 2.0f) - 1.0f; + + // Calculate the normal from the data in the normal map. + bumpNormal = (bumpMap.x * input.tangent) + (bumpMap.y * input.binormal) + (bumpMap.z * input.normal); + + // Normalize the resulting bump normal. + bumpNormal = normalize(bumpNormal); + + // Invert the light direction for calculations. + lightDir = -lightDirection; + + // Calculate the amount of light on this pixel based on the normal map value. + lightIntensity = saturate(dot(bumpNormal, lightDir)); + + // Determine the final amount of diffuse color based on the diffuse color combined with the light intensity. + color = saturate(diffuseColor * lightIntensity); + + // Combine the final light color with the texture color. + color = color * textureColor; + + return color; +} \ No newline at end of file diff --git a/enginecustom/normalmap.vs b/enginecustom/normalmap.vs new file mode 100644 index 0000000..4a16cd2 --- /dev/null +++ b/enginecustom/normalmap.vs @@ -0,0 +1,65 @@ +///////////// +// GLOBALS // +///////////// +cbuffer MatrixBuffer +{ + matrix worldMatrix; + matrix viewMatrix; + matrix projectionMatrix; +}; + +////////////// +// TYPEDEFS // +////////////// +struct VertexInputType +{ + float4 position : POSITION; + float2 tex : TEXCOORD0; + float3 normal : NORMAL; + float3 tangent : TANGENT; + float3 binormal : BINORMAL; +}; + +struct PixelInputType +{ + float4 position : SV_POSITION; + float2 tex : TEXCOORD0; + float3 normal : NORMAL; + float3 tangent : TANGENT; + float3 binormal : BINORMAL; +}; + + +//////////////////////////////////////////////////////////////////////////////// +// Vertex Shader +//////////////////////////////////////////////////////////////////////////////// +PixelInputType NormalMapVertexShader(VertexInputType input) +{ + PixelInputType output; + + + // Change the position vector to be 4 units for proper matrix calculations. + input.position.w = 1.0f; + + // Calculate the position of the vertex against the world, view, and projection matrices. + output.position = mul(input.position, worldMatrix); + output.position = mul(output.position, viewMatrix); + output.position = mul(output.position, projectionMatrix); + + // Store the texture coordinates for the pixel shader. + output.tex = input.tex; + + // Calculate the normal vector against the world matrix only and then normalize the final value. + output.normal = mul(input.normal, (float3x3)worldMatrix); + output.normal = normalize(output.normal); + + // Calculate the tangent vector against the world matrix only and then normalize the final value. + output.tangent = mul(input.tangent, (float3x3)worldMatrix); + output.tangent = normalize(output.tangent); + + // Calculate the binormal vector against the world matrix only and then normalize the final value. + output.binormal = mul(input.binormal, (float3x3)worldMatrix); + output.binormal = normalize(output.binormal); + + return output; +} \ No newline at end of file diff --git a/enginecustom/normalmapshaderclass.cpp b/enginecustom/normalmapshaderclass.cpp new file mode 100644 index 0000000..dbd365c --- /dev/null +++ b/enginecustom/normalmapshaderclass.cpp @@ -0,0 +1,441 @@ +#include "normalmapshaderclass.h" + + +NormalMapShaderClass::NormalMapShaderClass() +{ + m_vertexShader = 0; + m_pixelShader = 0; + m_layout = 0; + m_matrixBuffer = 0; + m_sampleState = 0; + m_lightBuffer = 0; +} + + +NormalMapShaderClass::NormalMapShaderClass(const NormalMapShaderClass& other) +{ +} + + +NormalMapShaderClass::~NormalMapShaderClass() +{ +} + + +bool NormalMapShaderClass::Initialize(ID3D11Device* device, HWND hwnd) +{ + bool result; + wchar_t vsFilename[128]; + wchar_t psFilename[128]; + int error; + + // Set the filename of the vertex shader. + error = wcscpy_s(vsFilename, 128, L"normalmap.vs"); + if (error != 0) + { + return false; + } + + // Set the filename of the pixel shader. + error = wcscpy_s(psFilename, 128, L"normalmap.ps"); + if (error != 0) + { + return false; + } + + // Initialize the vertex and pixel shaders. + result = InitializeShader(device, hwnd, vsFilename, psFilename); + if (!result) + { + return false; + } + + return true; +} + + +void NormalMapShaderClass::Shutdown() +{ + // Shutdown the vertex and pixel shaders as well as the related objects. + ShutdownShader(); + + return; +} + +bool NormalMapShaderClass::Render(ID3D11DeviceContext* deviceContext, int indexCount, XMMATRIX worldMatrix, XMMATRIX viewMatrix, XMMATRIX projectionMatrix, + ID3D11ShaderResourceView* texture1, ID3D11ShaderResourceView* texture2, XMFLOAT3 lightDirection, XMFLOAT4 diffuseColor) +{ + bool result; + + + // Set the shader parameters that it will use for rendering. + result = SetShaderParameters(deviceContext, worldMatrix, viewMatrix, projectionMatrix, texture1, texture2, lightDirection, diffuseColor); + if (!result) + { + return false; + } + + // Now render the prepared buffers with the shader. + RenderShader(deviceContext, indexCount); + + return true; +} + + +bool NormalMapShaderClass::InitializeShader(ID3D11Device* device, HWND hwnd, WCHAR* vsFilename, WCHAR* psFilename) +{ + HRESULT result; + ID3D10Blob* errorMessage; + ID3D10Blob* vertexShaderBuffer; + ID3D10Blob* pixelShaderBuffer; + D3D11_INPUT_ELEMENT_DESC polygonLayout[5]; + unsigned int numElements; + D3D11_BUFFER_DESC matrixBufferDesc; + D3D11_SAMPLER_DESC samplerDesc; + D3D11_BUFFER_DESC lightBufferDesc; + + + // Initialize the pointers this function will use to null. + errorMessage = 0; + vertexShaderBuffer = 0; + pixelShaderBuffer = 0; + + // Compile the vertex shader code. + result = D3DCompileFromFile(vsFilename, NULL, NULL, "NormalMapVertexShader", "vs_5_0", D3D10_SHADER_ENABLE_STRICTNESS, 0, + &vertexShaderBuffer, &errorMessage); + if (FAILED(result)) + { + // If the shader failed to compile it should have writen something to the error message. + if (errorMessage) + { + OutputShaderErrorMessage(errorMessage, hwnd, vsFilename); + } + // If there was nothing in the error message then it simply could not find the shader file itself. + else + { + MessageBox(hwnd, vsFilename, L"Missing Shader File", MB_OK); + } + + return false; + } + + // Compile the pixel shader code. + result = D3DCompileFromFile(psFilename, NULL, NULL, "NormalMapPixelShader", "ps_5_0", D3D10_SHADER_ENABLE_STRICTNESS, 0, + &pixelShaderBuffer, &errorMessage); + if (FAILED(result)) + { + // If the shader failed to compile it should have writen something to the error message. + if (errorMessage) + { + OutputShaderErrorMessage(errorMessage, hwnd, psFilename); + } + // If there was nothing in the error message then it simply could not find the file itself. + else + { + MessageBox(hwnd, psFilename, L"Missing Shader File", MB_OK); + } + + return false; + } + + // Create the vertex shader from the buffer. + result = device->CreateVertexShader(vertexShaderBuffer->GetBufferPointer(), vertexShaderBuffer->GetBufferSize(), NULL, &m_vertexShader); + if (FAILED(result)) + { + return false; + } + + // Create the pixel shader from the buffer. + result = device->CreatePixelShader(pixelShaderBuffer->GetBufferPointer(), pixelShaderBuffer->GetBufferSize(), NULL, &m_pixelShader); + if (FAILED(result)) + { + return false; + } + + // Create the vertex input layout description. + polygonLayout[0].SemanticName = "POSITION"; + polygonLayout[0].SemanticIndex = 0; + polygonLayout[0].Format = DXGI_FORMAT_R32G32B32_FLOAT; + polygonLayout[0].InputSlot = 0; + polygonLayout[0].AlignedByteOffset = 0; + polygonLayout[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + polygonLayout[0].InstanceDataStepRate = 0; + + polygonLayout[1].SemanticName = "TEXCOORD"; + polygonLayout[1].SemanticIndex = 0; + polygonLayout[1].Format = DXGI_FORMAT_R32G32_FLOAT; + polygonLayout[1].InputSlot = 0; + polygonLayout[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT; + polygonLayout[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + polygonLayout[1].InstanceDataStepRate = 0; + + polygonLayout[2].SemanticName = "NORMAL"; + polygonLayout[2].SemanticIndex = 0; + polygonLayout[2].Format = DXGI_FORMAT_R32G32B32_FLOAT; + polygonLayout[2].InputSlot = 0; + polygonLayout[2].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT; + polygonLayout[2].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + polygonLayout[2].InstanceDataStepRate = 0; + + polygonLayout[3].SemanticName = "TANGENT"; + polygonLayout[3].SemanticIndex = 0; + polygonLayout[3].Format = DXGI_FORMAT_R32G32B32_FLOAT; + polygonLayout[3].InputSlot = 0; + polygonLayout[3].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT; + polygonLayout[3].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + polygonLayout[3].InstanceDataStepRate = 0; + + polygonLayout[4].SemanticName = "BINORMAL"; + polygonLayout[4].SemanticIndex = 0; + polygonLayout[4].Format = DXGI_FORMAT_R32G32B32_FLOAT; + polygonLayout[4].InputSlot = 0; + polygonLayout[4].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT; + polygonLayout[4].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + polygonLayout[4].InstanceDataStepRate = 0; + + // Get a count of the elements in the layout. + numElements = sizeof(polygonLayout) / sizeof(polygonLayout[0]); + + // Create the vertex input layout. + result = device->CreateInputLayout(polygonLayout, numElements, vertexShaderBuffer->GetBufferPointer(), + vertexShaderBuffer->GetBufferSize(), &m_layout); + if (FAILED(result)) + { + return false; + } + + // Release the vertex shader buffer and pixel shader buffer since they are no longer needed. + vertexShaderBuffer->Release(); + vertexShaderBuffer = 0; + + pixelShaderBuffer->Release(); + pixelShaderBuffer = 0; + + // Setup the description of the dynamic matrix constant buffer that is in the vertex shader. + matrixBufferDesc.Usage = D3D11_USAGE_DYNAMIC; + matrixBufferDesc.ByteWidth = sizeof(MatrixBufferType); + matrixBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + matrixBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + matrixBufferDesc.MiscFlags = 0; + matrixBufferDesc.StructureByteStride = 0; + + // Create the constant buffer pointer so we can access the vertex shader constant buffer from within this class. + result = device->CreateBuffer(&matrixBufferDesc, NULL, &m_matrixBuffer); + if (FAILED(result)) + { + return false; + } + + // Create a texture sampler state description. + samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + samplerDesc.MipLODBias = 0.0f; + samplerDesc.MaxAnisotropy = 1; + samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + samplerDesc.BorderColor[0] = 0; + samplerDesc.BorderColor[1] = 0; + samplerDesc.BorderColor[2] = 0; + samplerDesc.BorderColor[3] = 0; + samplerDesc.MinLOD = 0; + samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; + + // Create the texture sampler state. + result = device->CreateSamplerState(&samplerDesc, &m_sampleState); + if (FAILED(result)) + { + return false; + } + + // Setup the description of the light dynamic constant buffer that is in the pixel shader. + lightBufferDesc.Usage = D3D11_USAGE_DYNAMIC; + lightBufferDesc.ByteWidth = sizeof(LightBufferType); + lightBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + lightBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + lightBufferDesc.MiscFlags = 0; + lightBufferDesc.StructureByteStride = 0; + + // Create the constant buffer pointer so we can access the vertex shader constant buffer from within this class. + result = device->CreateBuffer(&lightBufferDesc, NULL, &m_lightBuffer); + if (FAILED(result)) + { + return false; + } + + return true; +} + + +void NormalMapShaderClass::ShutdownShader() +{ + // Release the light constant buffer. + if (m_lightBuffer) + { + m_lightBuffer->Release(); + m_lightBuffer = 0; + } + + // Release the sampler state. + if (m_sampleState) + { + m_sampleState->Release(); + m_sampleState = 0; + } + + // Release the matrix constant buffer. + if (m_matrixBuffer) + { + m_matrixBuffer->Release(); + m_matrixBuffer = 0; + } + + // Release the layout. + if (m_layout) + { + m_layout->Release(); + m_layout = 0; + } + + // Release the pixel shader. + if (m_pixelShader) + { + m_pixelShader->Release(); + m_pixelShader = 0; + } + + // Release the vertex shader. + if (m_vertexShader) + { + m_vertexShader->Release(); + m_vertexShader = 0; + } + + return; +} + + +void NormalMapShaderClass::OutputShaderErrorMessage(ID3D10Blob* errorMessage, HWND hwnd, WCHAR* shaderFilename) +{ + char* compileErrors; + unsigned long long bufferSize, i; + ofstream fout; + + + // Get a pointer to the error message text buffer. + compileErrors = (char*)(errorMessage->GetBufferPointer()); + + // Get the length of the message. + bufferSize = errorMessage->GetBufferSize(); + + // Open a file to write the error message to. + fout.open("shader-error.txt"); + + // Write out the error message. + for (i = 0; i < bufferSize; i++) + { + fout << compileErrors[i]; + } + + // Close the file. + fout.close(); + + // Release the error message. + errorMessage->Release(); + errorMessage = 0; + + // Pop a message up on the screen to notify the user to check the text file for compile errors. + MessageBox(hwnd, L"Error compiling shader. Check shader-error.txt for message.", shaderFilename, MB_OK); + + return; +} + + +bool NormalMapShaderClass::SetShaderParameters(ID3D11DeviceContext* deviceContext, XMMATRIX worldMatrix, XMMATRIX viewMatrix, XMMATRIX projectionMatrix, + ID3D11ShaderResourceView* texture1, ID3D11ShaderResourceView* texture2, XMFLOAT3 lightDirection, XMFLOAT4 diffuseColor) +{ + HRESULT result; + D3D11_MAPPED_SUBRESOURCE mappedResource; + MatrixBufferType* dataPtr; + unsigned int bufferNumber; + LightBufferType* dataPtr2; + + + // Transpose the matrices to prepare them for the shader. + worldMatrix = XMMatrixTranspose(worldMatrix); + viewMatrix = XMMatrixTranspose(viewMatrix); + projectionMatrix = XMMatrixTranspose(projectionMatrix); + + // Lock the constant buffer so it can be written to. + result = deviceContext->Map(m_matrixBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return false; + } + + // Get a pointer to the data in the constant buffer. + dataPtr = (MatrixBufferType*)mappedResource.pData; + + // Copy the matrices into the constant buffer. + dataPtr->world = worldMatrix; + dataPtr->view = viewMatrix; + dataPtr->projection = projectionMatrix; + + // Unlock the constant buffer. + deviceContext->Unmap(m_matrixBuffer, 0); + + // Set the position of the constant buffer in the vertex shader. + bufferNumber = 0; + + // Finally set the constant buffer in the vertex shader with the updated values. + deviceContext->VSSetConstantBuffers(bufferNumber, 1, &m_matrixBuffer); + + // Set shader texture resources in the pixel shader. + deviceContext->PSSetShaderResources(0, 1, &texture1); + deviceContext->PSSetShaderResources(1, 1, &texture2); + + // Lock the light constant buffer so it can be written to. + result = deviceContext->Map(m_lightBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return false; + } + + // Get a pointer to the data in the constant buffer. + dataPtr2 = (LightBufferType*)mappedResource.pData; + + // Copy the lighting variables into the constant buffer. + dataPtr2->diffuseColor = diffuseColor; + dataPtr2->lightDirection = lightDirection; + dataPtr2->padding = 0.0f; + + // Unlock the constant buffer. + deviceContext->Unmap(m_lightBuffer, 0); + + // Set the position of the light constant buffer in the pixel shader. + bufferNumber = 0; + + // Finally set the light constant buffer in the pixel shader with the updated values. + deviceContext->PSSetConstantBuffers(bufferNumber, 1, &m_lightBuffer); + + return true; +} + + +void NormalMapShaderClass::RenderShader(ID3D11DeviceContext* deviceContext, int indexCount) +{ + // Set the vertex input layout. + deviceContext->IASetInputLayout(m_layout); + + // Set the vertex and pixel shaders that will be used to render this triangle. + deviceContext->VSSetShader(m_vertexShader, NULL, 0); + deviceContext->PSSetShader(m_pixelShader, NULL, 0); + + // Set the sampler state in the pixel shader. + deviceContext->PSSetSamplers(0, 1, &m_sampleState); + + // Render the triangle. + deviceContext->DrawIndexed(indexCount, 0, 0); + + return; +} \ No newline at end of file diff --git a/enginecustom/normalmapshaderclass.h b/enginecustom/normalmapshaderclass.h new file mode 100644 index 0000000..76dec19 --- /dev/null +++ b/enginecustom/normalmapshaderclass.h @@ -0,0 +1,62 @@ +#ifndef _NORMALMAPSHADERCLASS_H_ +#define _NORMALMAPSHADERCLASS_H_ + + +////////////// +// INCLUDES // +////////////// +#include +#include +#include +#include +using namespace DirectX; +using namespace std; + + +//////////////////////////////////////////////////////////////////////////////// +// Class name: NormalMapShaderClass +//////////////////////////////////////////////////////////////////////////////// +class NormalMapShaderClass +{ +private: + struct MatrixBufferType + { + XMMATRIX world; + XMMATRIX view; + XMMATRIX projection; + }; + + struct LightBufferType + { + XMFLOAT4 diffuseColor; + XMFLOAT3 lightDirection; + float padding; + }; + +public: + NormalMapShaderClass(); + NormalMapShaderClass(const NormalMapShaderClass&); + ~NormalMapShaderClass(); + + bool Initialize(ID3D11Device*, HWND); + void Shutdown(); + bool Render(ID3D11DeviceContext*, int, XMMATRIX, XMMATRIX, XMMATRIX, ID3D11ShaderResourceView*, ID3D11ShaderResourceView*, XMFLOAT3, XMFLOAT4); + +private: + bool InitializeShader(ID3D11Device*, HWND, WCHAR*, WCHAR*); + void ShutdownShader(); + void OutputShaderErrorMessage(ID3D10Blob*, HWND, WCHAR*); + + bool SetShaderParameters(ID3D11DeviceContext*, XMMATRIX, XMMATRIX, XMMATRIX, ID3D11ShaderResourceView*, ID3D11ShaderResourceView*, XMFLOAT3, XMFLOAT4); + void RenderShader(ID3D11DeviceContext*, int); + +private: + ID3D11VertexShader* m_vertexShader; + ID3D11PixelShader* m_pixelShader; + ID3D11InputLayout* m_layout; + ID3D11Buffer* m_matrixBuffer; + ID3D11SamplerState* m_sampleState; + ID3D11Buffer* m_lightBuffer; +}; + +#endif \ No newline at end of file