Shadows go brrr
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,35 +1,41 @@
|
||||
// Global parameters
|
||||
SamplerState gShadowSampler : ShadowSampler;
|
||||
SamplerState gShadowSampler2 : ShadowSampler {
|
||||
Filter = MIN_MAG_MIP_POINT;
|
||||
AddressU = CLAMP;
|
||||
AddressV = CLAMP;
|
||||
ComparisonFunc = LESS_EQUAL;
|
||||
};
|
||||
texture2D gShadowMap : ShadowMap;
|
||||
float4x4 gLightViewProj : LightViewProjection;
|
||||
|
||||
DepthStencilState ShadowDepthStencilState
|
||||
{
|
||||
DepthEnable = true;
|
||||
DepthWriteMask = ALL; // Write depth to the shadow map
|
||||
DepthFunc = LESS_EQUAL; // Compare depth in the shadow map
|
||||
StencilEnable = false; // We don't need stencil operations here
|
||||
};
|
||||
|
||||
SamplerState gSampleState : SampleState;
|
||||
RasterizerState gRasterizerState : RastState;
|
||||
|
||||
// Transformations
|
||||
float4x4 gWorldViewProj : WorldViewProjection;
|
||||
float4x4 gWorldMatrix : WorldMatrix;
|
||||
float4x4 gLightViewProj : LightViewProjection;
|
||||
|
||||
// Textures
|
||||
texture2D gDiffuseMap : DiffuseMap;
|
||||
texture2D gNormalMap : Normal;
|
||||
texture2D gSpecularMap : Specular;
|
||||
texture2D gGlossMap : Gloss;
|
||||
texture2D gShadowMap : ShadowMap;
|
||||
|
||||
// Light properties
|
||||
float3 gLightDirection : LightDirection;
|
||||
float3 gLightColor : LightColor;
|
||||
float3 gCameraPosition : CameraPosition;
|
||||
bool gUseNormal : UseNormal;
|
||||
|
||||
// Constants
|
||||
static const float3 gAmbient = float3(.03f, .03f, .03f);
|
||||
static const float gLightIntensity = 7.f;
|
||||
static const float PI = 3.14159f;
|
||||
static const float gSpecularReflectance = 1.f;
|
||||
static const float gShininess = 25.f;
|
||||
|
||||
// Shadow bias to reduce artifacts
|
||||
static const float gShadowBias = 0.005f;
|
||||
|
||||
// Input/Output structures
|
||||
// Input output structures
|
||||
struct VS_INPUT {
|
||||
float3 Position : POSITION;
|
||||
float2 TexCoord : TEXCOORD;
|
||||
@@ -43,66 +49,90 @@ struct VS_OUTPUT {
|
||||
float2 TexCoord : TEXCOORD;
|
||||
float3 Normal : NORMAL;
|
||||
float3 Tangent : TANGENT;
|
||||
float4 LightPosition : TEXCOORD1;
|
||||
float4 ShadowCoord : SHADOWCOORD; // Add this to store shadow map coordinates
|
||||
};
|
||||
|
||||
// Vertex shader
|
||||
VS_OUTPUT VS(VS_INPUT input) {
|
||||
VS_OUTPUT output = (VS_OUTPUT)0;
|
||||
|
||||
output.Position = mul(float4(input.Position, 1.f), gWorldViewProj);
|
||||
output.WorldPosition = mul(float4(input.Position, 1.f), gWorldMatrix);
|
||||
output.TexCoord = input.TexCoord;
|
||||
output.Normal = mul(input.Normal, (float3x3)gWorldMatrix);
|
||||
output.Tangent = mul(input.Tangent, (float3x3)gWorldMatrix);
|
||||
output.LightPosition = mul(float4(input.Position, 1.f), gLightViewProj);
|
||||
output.Position = mul(float4(input.Position, 1.f), gWorldViewProj);
|
||||
|
||||
|
||||
output.TexCoord = input.TexCoord;
|
||||
output.Normal = mul(input.Normal, (float3x3) gWorldMatrix);
|
||||
output.Tangent = mul(input.Tangent, (float3x3) gWorldMatrix);
|
||||
|
||||
// Calculate shadow map coordinates
|
||||
// lightSpaceMatrix * vec4(vs_out.FragPos, 1.0);
|
||||
output.ShadowCoord = mul(float4(input.Position, 1.f) , gLightViewProj);
|
||||
return output;
|
||||
}
|
||||
|
||||
float ShadowCalculation(float4 lightPos) {
|
||||
// Transform light position to shadow map space
|
||||
float2 shadowCoord = lightPos.xy / lightPos.w;
|
||||
shadowCoord = shadowCoord * 0.5f + 0.5f;
|
||||
// Shadow sampling function
|
||||
float ShadowCalculation(float4 shadowCoord) {
|
||||
// Normalize the depth by dividing by the w component
|
||||
float3 projCoord = shadowCoord.xyz / shadowCoord.w;
|
||||
|
||||
// Convert from [-1, 1] to [0, 1]
|
||||
float2 UVCoords;
|
||||
UVCoords.x = 0.5f * projCoord.x + 0.5f;
|
||||
UVCoords.y = -0.5f * projCoord.y + 0.5f;
|
||||
// float z = 0.5 * projCoord.z + 0.5;
|
||||
float z = projCoord.z;
|
||||
// Sample the shadow map
|
||||
float shadowDepth = gShadowMap.Sample(gSampleState, shadowCoord).r;
|
||||
float shadowDepth = gShadowMap.Sample(gShadowSampler2, UVCoords.xy).r;
|
||||
|
||||
float bias = 0.0025f;
|
||||
|
||||
// float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005);
|
||||
|
||||
// return gShadowMap.Sample(gShadowSampler2, UVCoords.xy).r;
|
||||
// Check if the current fragment is in shadow
|
||||
if (shadowDepth + bias < z)
|
||||
return 0.5f;
|
||||
else
|
||||
return 1.0f;
|
||||
|
||||
// Compare depth and apply bias
|
||||
if (shadowDepth + gShadowBias < lightPos.z / lightPos.w) {
|
||||
return 0.0f; // In shadow
|
||||
}
|
||||
return 1.0f; // Not in shadow
|
||||
}
|
||||
|
||||
// Pixel shader
|
||||
float4 PS(VS_OUTPUT input) : SV_TARGET {
|
||||
// Normalize inputs
|
||||
float3 normal = normalize(input.Normal);
|
||||
float3 lightDir = normalize(gLightDirection);
|
||||
// Check if gDiffuseMap sample has a valid value, otherwise render red
|
||||
// if (gDiffuseMap.Sample(gSampleState, input.TexCoord).a == 0.f)
|
||||
// return float4(1.f, 0.f, 0.f, 1.f);
|
||||
|
||||
// Diffuse lighting
|
||||
float NdotL = max(dot(normal, -lightDir), 0.0f);
|
||||
float3 diffuse = gLightColor * NdotL;
|
||||
// return float4(Shade(input), 1.0f); // Use the shading function with shadow
|
||||
|
||||
// Shadows
|
||||
float shadowFactor = ShadowCalculation(input.LightPosition);
|
||||
// return gShadowMap.Sample(gShadowSampler, input.ShadowCoord.xy / input.ShadowCoord.w); // Sample shadow map
|
||||
|
||||
// Ambient + Diffuse * Shadow
|
||||
float3 finalColor = gAmbient + (diffuse * shadowFactor);
|
||||
// float3 finalColor = float3(shadowFactor,shadowFactor,shadowFactor);
|
||||
float shadowFactor = ShadowCalculation(input.ShadowCoord);
|
||||
|
||||
float3 diffuseColor = gDiffuseMap.Sample(gSampleState, input.TexCoord).rgb;
|
||||
|
||||
float3 finalColor = float3(1.f, 1.f, 1.f) * shadowFactor;
|
||||
finalColor += gAmbient;
|
||||
|
||||
|
||||
// return float4(shadowDepth,shadowDepth,shadowDepth, 1.0f);
|
||||
return float4(finalColor, 1.0f);
|
||||
// return gShadowMap.Sample(gShadowSampler, input.TexCoord); // Sample shadow map
|
||||
}
|
||||
|
||||
DepthStencilState gDepthStencilState {
|
||||
// DepthStencilState
|
||||
DepthStencilState gDepthStencilState
|
||||
{
|
||||
DepthEnable = true;
|
||||
DepthWriteMask = ALL;
|
||||
DepthFunc = LESS;
|
||||
StencilEnable = true;
|
||||
};
|
||||
|
||||
// Technique
|
||||
technique11 DefaultTechnique {
|
||||
pass P0 {
|
||||
SetDepthStencilState(gDepthStencilState, 0);
|
||||
SetDepthStencilState(ShadowDepthStencilState, 0);
|
||||
SetRasterizerState(gRasterizerState);
|
||||
SetVertexShader(CompileShader(vs_5_0, VS()));
|
||||
SetGeometryShader(NULL);
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
float4x4 gLightWorldViewProj : WorldViewProjection;
|
||||
|
||||
float4x4 gWorldViewProj: WorldViewProjection; //For compatibility sake
|
||||
|
||||
Texture2D gShadowMap : ShadowMap;
|
||||
SamplerState gShadowMapSampler : ShadowMapSampler;
|
||||
|
||||
struct VS_Input {
|
||||
float3 Position : POSITION;
|
||||
float2 TexCoord : TEXCOORD;
|
||||
@@ -27,14 +23,24 @@ VS_Output VS_Shadow(VS_Input input)
|
||||
float4 PS_Shadow(VS_Output input) : SV_TARGET
|
||||
{
|
||||
// Output depth information (Z/W in clip space)
|
||||
return float4(input.Position.z / input.Position.w, 0.0f, 0.0f, 1.0f);
|
||||
// // gl_FragDepth = gl_FragCoord.z;
|
||||
return float4(input.Position.z / input.Position.w, 0.0f, 0.0f, input.Position.z / input.Position.w);
|
||||
}
|
||||
|
||||
// Rasterizer state for front face culling
|
||||
RasterizerState FrontFaceCull
|
||||
{
|
||||
FrontCounterClockwise = FALSE;
|
||||
CullMode = FRONT;
|
||||
};
|
||||
|
||||
// Technique for rendering shadow map
|
||||
technique11 DefaultTechnique
|
||||
{
|
||||
pass P0
|
||||
{
|
||||
//Set FrontFaceCulling
|
||||
SetRasterizerState(FrontFaceCull);
|
||||
SetVertexShader(CompileShader(vs_5_0, VS_Shadow()));
|
||||
SetPixelShader(CompileShader(ps_5_0, PS_Shadow()));
|
||||
}
|
||||
|
||||
@@ -7,13 +7,15 @@ SamplerState::SamplerState(ID3D11Device *device)
|
||||
SamplerState::~SamplerState() {
|
||||
if (m_samplerState) m_samplerState->Release();
|
||||
}
|
||||
|
||||
bool SamplerState::Initialize() {
|
||||
D3D11_SAMPLER_DESC samplerDesc = {};
|
||||
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
// samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
// samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
// samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
samplerDesc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL;
|
||||
samplerDesc.MinLOD = 0;
|
||||
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
|
||||
|
||||
@@ -9,9 +9,9 @@ public:
|
||||
SamplerState(ID3D11Device* device);
|
||||
~SamplerState();
|
||||
|
||||
|
||||
bool Initialize();
|
||||
ID3D11SamplerState* GetSamplerState() const { return m_samplerState; }
|
||||
|
||||
private:
|
||||
ID3D11Device* m_device;
|
||||
ID3D11SamplerState* m_samplerState;
|
||||
|
||||
@@ -40,6 +40,7 @@ void ShadowMapBuffer::SetRenderTarget(ID3D11DeviceContext *deviceContext) {
|
||||
deviceContext->OMSetRenderTargets(0, nullptr, m_depthBuffer.GetDepthStencilView());
|
||||
}
|
||||
|
||||
|
||||
void ShadowMapBuffer::ResetRenderTarget(ID3D11DeviceContext *deviceContext) {
|
||||
ID3D11RenderTargetView *nullRTV = nullptr;
|
||||
deviceContext->OMSetRenderTargets(1, &nullRTV, nullptr);
|
||||
|
||||
@@ -27,9 +27,7 @@ public:
|
||||
|
||||
ID3D11SamplerState *GetSamplerState() const { return m_samplerState.GetSamplerState(); }
|
||||
|
||||
|
||||
ID3D11DepthStencilView *GetDepthStencilView();
|
||||
|
||||
private:
|
||||
ID3D11Device *m_device;
|
||||
UINT m_width;
|
||||
|
||||
@@ -60,11 +60,9 @@ void dae::Camera::Update(const dae::Timer *pTimer) {
|
||||
if (pKeyboardState[SDL_SCANCODE_LSHIFT]) {
|
||||
MovementSpeed *= 2;
|
||||
}
|
||||
|
||||
if (pKeyboardState[SDL_SCANCODE_W]) {
|
||||
origin += forward * deltaTime * MovementSpeed;
|
||||
}
|
||||
|
||||
if (pKeyboardState[SDL_SCANCODE_A]) {
|
||||
origin -= right * deltaTime * MovementSpeed;
|
||||
}
|
||||
|
||||
@@ -9,13 +9,10 @@ BaseEffect::BaseEffect(ID3D11Device *devicePtr, const std::wstring &filePath) {
|
||||
const std::ifstream file(filePath);
|
||||
if (!file)
|
||||
std::wcout << L"File doesn't exist" << std::endl;
|
||||
|
||||
m_EffectPtr = LoadEffect(devicePtr, filePath);
|
||||
m_TechniquePtr = m_EffectPtr->GetTechniqueByName("DefaultTechnique");
|
||||
|
||||
if (!m_TechniquePtr->IsValid())
|
||||
std::wcout << L"Technique is not valid" << std::endl;
|
||||
|
||||
m_MatWorldViewProjVariablePtr = m_EffectPtr->GetVariableByName("gWorldViewProj")->AsMatrix();
|
||||
if (!m_MatWorldViewProjVariablePtr->IsValid())
|
||||
std::wcout << L"gWorldViewProj Matrix is not valid" << std::endl;
|
||||
@@ -54,11 +51,11 @@ ID3DX11Effect *BaseEffect::LoadEffect(ID3D11Device *devicePtr, const std::wstrin
|
||||
ss << errorsPtr[i];
|
||||
OutputDebugStringW(ss.str().c_str());
|
||||
|
||||
|
||||
errorBlobPtr->Release();
|
||||
errorBlobPtr = nullptr;
|
||||
return nullptr;
|
||||
} else {
|
||||
|
||||
std::wstringstream ss;
|
||||
ss << "EffectLoader: Failed to CreateEffectFromFile!\nPath: " << filePath;
|
||||
std::wcout << ss.str() << std::endl;
|
||||
@@ -81,7 +78,6 @@ void BaseEffect::SetCameraPos(const dae::Vector3 &vector3) const {
|
||||
}
|
||||
|
||||
void BaseEffect::SetMaterial(Material *material) {
|
||||
|
||||
}
|
||||
|
||||
void BaseEffect::SetWorldMatrix(const dae::Matrix& matrix) const {
|
||||
|
||||
@@ -28,6 +28,8 @@ public:
|
||||
|
||||
ID3DX11EffectTechnique* GetTechniquePtr() const { return m_TechniquePtr; }
|
||||
|
||||
|
||||
|
||||
void SetWorldViewProjMatrix(const dae::Matrix& matrix);
|
||||
|
||||
virtual void NextSamplingState();
|
||||
|
||||
@@ -40,6 +40,7 @@ Effect::Effect(ID3D11Device *devicePtr, const std::wstring &filePath)
|
||||
if(!m_CameraPosVariablePtr->IsValid())
|
||||
std::wcout << L"gCameraPos Vector is not valid" << std::endl;
|
||||
|
||||
|
||||
m_LightColorVariablePtr = m_EffectPtr->GetVariableByName("gLightColor")->AsVector();
|
||||
if(!m_LightColorVariablePtr->IsValid())
|
||||
std::wcout << L"gLightColor Vector is not valid" << std::endl;
|
||||
@@ -60,6 +61,10 @@ Effect::Effect(ID3D11Device *devicePtr, const std::wstring &filePath)
|
||||
if(!m_ShadowMapSamplerVariablePtr->IsValid())
|
||||
std::wcout << L"gShadowSampler Sampler is not valid" << std::endl;
|
||||
|
||||
m_LightWorldViewProjVariablePtr = m_EffectPtr->GetVariableByName("gLightViewProj")->AsMatrix();
|
||||
if(!m_LightWorldViewProjVariablePtr->IsValid())
|
||||
std::wcout << L"gLightWorldViewProj Matrix is not valid" << std::endl;
|
||||
|
||||
m_UseNormalMapVariablePtr->SetBool(m_UseNormalMap);
|
||||
|
||||
|
||||
@@ -73,6 +78,7 @@ Effect::Effect(ID3D11Device *devicePtr, const std::wstring &filePath)
|
||||
this->InitSamplers(devicePtr);
|
||||
this->InitRasterizer(devicePtr);
|
||||
|
||||
|
||||
m_SamplerVariablePtr->SetSampler(0,m_SamplerStates[static_cast<int>(m_TechniqueType)]);
|
||||
m_RasterizerVariablePtr->SetRasterizerState(0,m_RasterizerStates[static_cast<int>(m_CullMode)]);
|
||||
}
|
||||
@@ -214,9 +220,13 @@ void Effect::InitRasterizer(ID3D11Device *devicePtr) {
|
||||
void Effect::SetShadowMapSampler(ID3D11SamplerState *pState) {
|
||||
|
||||
m_ShadowMapSamplerVariablePtr->SetSampler(0,pState);
|
||||
|
||||
}
|
||||
|
||||
void Effect::SetShadowMap(ID3D11ShaderResourceView *pView) {
|
||||
m_ShadowMapVariablePtr->SetResource(pView);
|
||||
}
|
||||
|
||||
void Effect::SetLightViewProjMatrix(Matrix matrix) {
|
||||
m_LightWorldViewProjVariablePtr->SetMatrix(reinterpret_cast<const float*>(&matrix));
|
||||
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ public:
|
||||
|
||||
void SetShadowMapSampler(ID3D11SamplerState *pState);
|
||||
|
||||
void SetLightViewProjMatrix(Matrix matrix);
|
||||
|
||||
private:
|
||||
|
||||
void InitSamplers(ID3D11Device* devicePtr);
|
||||
@@ -58,6 +60,9 @@ private:
|
||||
|
||||
ID3DX11EffectShaderResourceVariable* m_ShadowMapVariablePtr{};
|
||||
|
||||
//m_LightWorldViewProjVariablePtr
|
||||
ID3DX11EffectMatrixVariable* m_LightWorldViewProjVariablePtr{};
|
||||
|
||||
ID3DX11EffectSamplerVariable* m_ShadowMapSamplerVariablePtr{};
|
||||
|
||||
TechniqueType m_TechniqueType{TechniqueType::Linear};
|
||||
|
||||
@@ -12,15 +12,17 @@ ShadowEffect::ShadowEffect(ID3D11Device *devicePtr, const std::wstring &filePath
|
||||
throw std::runtime_error("Failed to retrieve gLightWorldViewProj variable in ShadowEffect.");
|
||||
}
|
||||
|
||||
m_ShadowMapVariable = m_EffectPtr->GetVariableByName("gShadowMap")->AsShaderResource();
|
||||
if (!m_ShadowMapVariable->IsValid()) {
|
||||
throw std::runtime_error("Failed to retrieve gShadowMap variable in ShadowEffect.");
|
||||
}
|
||||
|
||||
m_ShadowMapSamplerVariable = m_EffectPtr->GetVariableByName("gShadowMapSampler")->AsSampler();
|
||||
if (!m_ShadowMapSamplerVariable->IsValid()) {
|
||||
throw std::runtime_error("Failed to retrieve gShadowMapSampler variable in ShadowEffect.");
|
||||
}
|
||||
// m_ShadowMapVariable = m_EffectPtr->GetVariableByName("gShadowMap")->AsShaderResource();
|
||||
// if (!m_ShadowMapVariable->IsValid()) {
|
||||
// throw std::runtime_error("Failed to retrieve gShadowMap variable in ShadowEffect.");
|
||||
// }
|
||||
//
|
||||
|
||||
// m_ShadowMapSamplerVariable = m_EffectPtr->GetVariableByName("gShadowMapSampler")->AsSampler();
|
||||
// if (!m_ShadowMapSamplerVariable->IsValid()) {
|
||||
// throw std::runtime_error("Failed to retrieve gShadowMapSampler variable in ShadowEffect.");
|
||||
// }
|
||||
}
|
||||
|
||||
void ShadowEffect::SetLightWorldViewProjMatrix(const Matrix &matrix) {
|
||||
|
||||
@@ -21,18 +21,25 @@ void Light::SetUp(const dae::Vector3 &up) {
|
||||
}
|
||||
|
||||
dae::Matrix Light::GetViewMatrix() const {
|
||||
auto test = dae::Matrix::CreateLookAtLH(m_Position, m_Target, m_Up);
|
||||
return dae::Matrix::CreateLookAtLH(m_Position, m_Target, m_Up);
|
||||
}
|
||||
|
||||
dae::Matrix Light::GetProjectionMatrix(float nearPlane, float farPlane, float size) const {
|
||||
return dae::Matrix::CreateOrthographic(size, size, nearPlane, farPlane);
|
||||
}
|
||||
|
||||
dae::Matrix Light::GetViewProjectionMatrix(float nearPlane, float farPlane, float size) const {
|
||||
return GetViewMatrix() * GetProjectionMatrix(nearPlane, farPlane, size);
|
||||
}
|
||||
|
||||
void Light::Update() {
|
||||
// If the light position or target changes dynamically, this is where updates would be managed.
|
||||
}
|
||||
// m_ViewMatrix = dae::Matrix::CreateLookAtLH(m_Position, m_Target, m_Up);
|
||||
// m_ProjectionMatrix = dae::Matrix::CreateOrthographic(size, size, nearPlane, farPlane);
|
||||
}
|
||||
|
||||
dae::Vector3 Light::GetTarget() {
|
||||
return m_Target;
|
||||
}
|
||||
|
||||
dae::Vector3 Light::GetPosition() {
|
||||
return m_Position;
|
||||
}
|
||||
|
||||
@@ -15,11 +15,13 @@ public:
|
||||
void SetUp(const dae::Vector3 &up);
|
||||
|
||||
dae::Matrix GetViewMatrix() const;
|
||||
dae::Matrix GetProjectionMatrix(float nearPlane = 0.1f, float farPlane = 100.0f, float size = 20.0f) const;
|
||||
dae::Matrix GetViewProjectionMatrix(float nearPlane = 0.1f, float farPlane = 100.0f, float size = 20.0f) const;
|
||||
dae::Matrix GetProjectionMatrix(float nearPlane = 0.1f, float farPlane = 100.0f, float size = 50.0f) const;
|
||||
dae::Matrix GetViewProjectionMatrix(float nearPlane = 0.1f, float farPlane = 100.0f, float size = 50.0f) const;
|
||||
|
||||
void Update();
|
||||
|
||||
dae::Vector3 GetTarget();
|
||||
dae::Vector3 GetPosition();
|
||||
private:
|
||||
dae::Vector3 m_Position;
|
||||
dae::Vector3 m_Target;
|
||||
|
||||
@@ -144,44 +144,26 @@ namespace dae {
|
||||
return out;
|
||||
}
|
||||
|
||||
Matrix Matrix::CreateLookAtLH(const Vector3& origin, const Vector3& forward, const Vector3& up) {
|
||||
// Calculate the z-axis (view direction)
|
||||
Vector3 zAxis = forward - origin;
|
||||
if (zAxis.SqrMagnitude() < 1e-6f) {
|
||||
// Avoid NaN by ensuring the forward and origin are not the same
|
||||
zAxis = Vector3(0, 0, 1); // Default to a valid direction
|
||||
}
|
||||
zAxis = zAxis.Normalized();
|
||||
|
||||
// Calculate the x-axis (right direction)
|
||||
Vector3 xAxis = Vector3::Cross(up, zAxis);
|
||||
if (xAxis.SqrMagnitude() < 1e-6f) {
|
||||
// Handle the case where up is parallel to zAxis
|
||||
Vector3 alternateUp = (std::abs(up.x) > 0.9f) ? Vector3(0, 1, 0) : Vector3(1, 0, 0);
|
||||
xAxis = Vector3::Cross(alternateUp, zAxis);
|
||||
}
|
||||
xAxis = xAxis.Normalized();
|
||||
|
||||
// Calculate the y-axis (up direction)
|
||||
Matrix Matrix::CreateLookAtLH(const Vector3& origin, const Vector3& forward, const Vector3& up)
|
||||
{
|
||||
Vector3 zAxis = (forward - origin).Normalized();
|
||||
Vector3 xAxis = Vector3::Cross(up, zAxis).Normalized();
|
||||
Vector3 yAxis = Vector3::Cross(zAxis, xAxis).Normalized();
|
||||
|
||||
// Calculate the translation
|
||||
Vector3 trans = {
|
||||
-Vector3::Dot(xAxis, origin),
|
||||
-Vector3::Dot(yAxis, origin),
|
||||
-Vector3::Dot(zAxis, origin)
|
||||
};
|
||||
|
||||
// Return the look-at matrix in row-major order
|
||||
Vector3 trans =
|
||||
{
|
||||
-Vector3::Dot(xAxis, origin),
|
||||
-Vector3::Dot(yAxis, origin),
|
||||
-Vector3::Dot(zAxis, origin)
|
||||
};
|
||||
return {
|
||||
{xAxis.x, yAxis.x, zAxis.x, 0.0f},
|
||||
{xAxis.y, yAxis.y, zAxis.y, 0.0f},
|
||||
{xAxis.z, yAxis.z, zAxis.z, 0.0f},
|
||||
{trans.x, trans.y, trans.z, 1.0f}
|
||||
{xAxis.x, yAxis.x, zAxis.x},
|
||||
{xAxis.y, yAxis.y, zAxis.y},
|
||||
{xAxis.z, yAxis.z, zAxis.z},
|
||||
{trans.x, trans.y, trans.z}
|
||||
};
|
||||
}
|
||||
|
||||
Matrix Matrix::CreatePerspectiveFovLH(float fovy, float aspect, float zn, float zf)
|
||||
Matrix Matrix::CreatePerspectiveFovLH(float fovy, float aspect, float zn, float zf)
|
||||
{
|
||||
return Matrix(
|
||||
{ 1.f / (aspect * fovy), 0, 0, 0 },
|
||||
@@ -300,6 +282,7 @@ namespace dae {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
const Matrix& Matrix::operator*=(const Matrix& m)
|
||||
{
|
||||
Matrix copy{ *this };
|
||||
@@ -320,12 +303,12 @@ namespace dae {
|
||||
data[3] = {vector3, 1};
|
||||
}
|
||||
|
||||
Matrix Matrix::CreateOrthographic(float size, float size1, float plane, float plane1) {
|
||||
Matrix Matrix::CreateOrthographic(float size, float size1, float nearPlane, float farPlane) {
|
||||
return Matrix(
|
||||
{2.f / size, 0, 0, 0},
|
||||
{0, 2.f / size1, 0, 0},
|
||||
{0, 0, 1.f / (plane1 - plane), 0},
|
||||
{0, 0, -plane / (plane1 - plane), 1}
|
||||
{0, 0, 1.f / (farPlane - nearPlane), 0},
|
||||
{0, 0, -nearPlane / (farPlane - nearPlane), 1}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,8 @@ namespace dae {
|
||||
static Matrix CreateLookAtLH(const Vector3& origin, const Vector3& forward, const Vector3& up);
|
||||
static Matrix CreatePerspectiveFovLH(float fovy, float aspect, float zn, float zf);
|
||||
|
||||
|
||||
|
||||
Vector4& operator[](int index);
|
||||
Vector4 operator[](int index) const;
|
||||
Matrix operator*(const Matrix& m) const;
|
||||
|
||||
@@ -9,37 +9,71 @@
|
||||
|
||||
void ShadowTestScene::Initialize(ID3D11Device *DevicePtr, ID3D11DeviceContext *DeviceContextPtr, Camera *camera) {
|
||||
// Initialize shadow map buffer
|
||||
m_ShadowMapBuffer = new ShadowMapBuffer(DevicePtr, 1024, 1024); // Example resolution: 1024x1024
|
||||
m_ShadowMapBuffer = new ShadowMapBuffer(DevicePtr, 1024 * 4, 1024 * 4); // Example resolution: 1024x1024
|
||||
if(!m_ShadowMapBuffer->Initialize()){
|
||||
assert(true && "Shadow map buffer failed to initialize");
|
||||
}
|
||||
// Initialize light source
|
||||
m_Light.SetPosition({0.0f, 10.0f, 0.0f});
|
||||
m_Light.SetPosition({-20.0f, 30.0f, 0.0f});
|
||||
m_Light.SetTarget({0, -5, 40});
|
||||
m_Light.SetUp({0.0f, 1.0f, 0.0f});
|
||||
|
||||
std::vector<VertexIn> vertices{};
|
||||
std::vector<uint32_t> indices{};
|
||||
|
||||
if(!Utils::ParseOBJNew("resources/scene.obj", vertices, indices, true)){
|
||||
if(!Utils::ParseOBJNew("resources/ShadingDemo.obj", vertices, indices, true)){
|
||||
assert(true && "Model failed to load");
|
||||
}
|
||||
|
||||
auto material = std::make_shared<Material>();
|
||||
// material->diffuseTexturePtr = Texture::LoadFromFile("resources/vehicle_diffuse.png", DevicePtr);
|
||||
|
||||
auto shadowEffect = new ShadowEffect(DevicePtr, L"resources/shadowEffect.fx");
|
||||
auto otherEffect = new Effect(DevicePtr, L"resources/SuperSimpleDiffuse.fx");
|
||||
|
||||
auto shadowMesh = new ShadowMesh(DevicePtr, vertices, indices, std::make_shared<Material>(), shadowEffect, otherEffect);
|
||||
auto shadowMesh = new ShadowMesh(DevicePtr, vertices, indices, material, shadowEffect, otherEffect);
|
||||
|
||||
|
||||
// std::vector<std::unique_ptr<Utils::MaterialMesh>> materialMeshes;
|
||||
// Utils::LoadObjWithMaterials("resources/scene.obj", materialMeshes, true, DevicePtr);
|
||||
// for (const auto &mesh: materialMeshes) {
|
||||
// if (mesh->vertices.size() > 0) {
|
||||
// std::shared_ptr<Material> material = std::make_shared<Material>();
|
||||
// BaseEffect *effect = new Effect(DevicePtr, L"resources/SuperSimpleDiffuse.fx");
|
||||
// ShadowEffect* shadowEffect = new ShadowEffect(DevicePtr, L"resources/shadowEffect.fx");
|
||||
// material->diffuseTexturePtr = Texture::LoadFromFile("./resources/diorama/" + mesh->diffuse_texture, DevicePtr);
|
||||
//
|
||||
// if (mesh->opacity_map != "") {
|
||||
//// continue;
|
||||
//// effect = new FireEffect(DevicePtr, L"resources/Fire.fx");
|
||||
//// material->diffuseTexturePtr = Texture::LoadFromFile("./resources/diorama/" + mesh->diffuse_texture, DevicePtr);
|
||||
// } else {
|
||||
// }
|
||||
//
|
||||
// m_shadowMeshes.push_back(new ShadowMesh(DevicePtr, mesh->vertices, mesh->indices, material, shadowEffect, effect));
|
||||
//
|
||||
// Matrix worldMatrix = m_shadowMeshes.back()->GetWorldMatrix();
|
||||
// worldMatrix *= Matrix::CreateScale(2.f, 2.f, 2.f);
|
||||
// worldMatrix *= Matrix::CreateScale(-1.f, 1.f, 1.f); // Mirror the model (Possible loading fault)
|
||||
// m_shadowMeshes.back()->SetWorldMatrix(worldMatrix);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
//Move forward 100
|
||||
shadowMesh->SetWorldMatrix(Matrix::CreateTranslation(Vector3(0, -5, 40)));
|
||||
|
||||
//
|
||||
m_shadowMeshes.push_back(shadowMesh);
|
||||
// m_shadowMaterials.push_back(material);
|
||||
}
|
||||
|
||||
void ShadowTestScene::Update() {
|
||||
|
||||
// m_Light.SetTarget(lightTarget);
|
||||
Vector3 pos = m_Light.GetPosition();
|
||||
pos.y = sin(SDL_GetTicks() / 1000.f) * 10.f + 10.f;
|
||||
m_Light.SetPosition(pos);
|
||||
|
||||
|
||||
m_Light.Update();
|
||||
}
|
||||
|
||||
@@ -48,40 +82,65 @@ void ShadowTestScene::Render(ID3D11DeviceContext *devicePtr, ID3D11RenderTargetV
|
||||
// Shadow map pass
|
||||
|
||||
// Set the viewport to match the shadow map size
|
||||
// D3D11_VIEWPORT shadowViewport = {};
|
||||
// shadowViewport.Width = static_cast<float>(1024);
|
||||
// shadowViewport.Height = static_cast<float>(1024);
|
||||
// shadowViewport.MinDepth = 0.0f;
|
||||
// shadowViewport.MaxDepth = 1.0f;
|
||||
// devicePtr->RSSetViewports(1, &shadowViewport);
|
||||
D3D11_VIEWPORT shadowViewport = {};
|
||||
shadowViewport.Width = static_cast<float>(1024 * 4);
|
||||
shadowViewport.Height = static_cast<float>(1024 * 4);
|
||||
shadowViewport.MinDepth = 0.0f;
|
||||
shadowViewport.MaxDepth = 1.0f;
|
||||
devicePtr->RSSetViewports(1, &shadowViewport);
|
||||
|
||||
devicePtr->OMSetRenderTargets(0, nullptr, m_ShadowMapBuffer->GetDepthStencilView());
|
||||
devicePtr->ClearDepthStencilView(m_ShadowMapBuffer->GetDepthStencilView(), D3D11_CLEAR_DEPTH, 1.0f, 0);
|
||||
ID3D11ShaderResourceView* shadowMap = m_ShadowMapBuffer->GetShaderResourceView();
|
||||
devicePtr->PSSetShaderResources(0, 1, &shadowMap);
|
||||
devicePtr->OMSetRenderTargets(0, nullptr, m_ShadowMapBuffer->GetDepthStencilView()); // Set the shadow map as the render target
|
||||
devicePtr->ClearDepthStencilView(m_ShadowMapBuffer->GetDepthStencilView(), D3D11_CLEAR_DEPTH, 1.0f, 0); // Clear the shadow map
|
||||
ID3D11ShaderResourceView* shadowMap = m_ShadowMapBuffer->GetShaderResourceView(); // Get the shadow map shader resource view
|
||||
devicePtr->PSSetShaderResources(0, 1, &shadowMap); // Set the shadow map as a shader resource
|
||||
|
||||
devicePtr->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
|
||||
ID3D11SamplerState* shadowSampler = m_ShadowMapBuffer->GetSamplerState();
|
||||
devicePtr->PSSetSamplers(0, 1, &shadowSampler);
|
||||
|
||||
auto lightViewProjection = m_Light.GetViewProjectionMatrix();
|
||||
|
||||
for (auto* mesh : m_shadowMeshes) {
|
||||
Matrix lightWorldViewProj = mesh->GetWorldMatrix() * m_Light.GetViewProjectionMatrix();
|
||||
Matrix lightWorldViewProj = mesh->GetWorldMatrix() * lightViewProjection;
|
||||
dynamic_cast<ShadowMesh*>(mesh)->RenderShadow(devicePtr, lightWorldViewProj);
|
||||
}
|
||||
|
||||
ID3D11DepthStencilView* nullDepthStencilView = nullptr;
|
||||
devicePtr->OMSetRenderTargets(1, &renderTargetViewPtr, nullDepthStencilView);
|
||||
|
||||
// Set the depthmap correctly
|
||||
|
||||
shadowViewport.Width = static_cast<float>(640);
|
||||
shadowViewport.Height = static_cast<float>(480);
|
||||
shadowViewport.MinDepth = 0.0f;
|
||||
shadowViewport.MaxDepth = 1.0f;
|
||||
devicePtr->RSSetViewports(1, &shadowViewport);
|
||||
|
||||
|
||||
devicePtr->OMSetRenderTargets(1, &renderTargetViewPtr, depthStencilViewPtr);
|
||||
ColorRGB DirectXClearColor{ .39f * 255.f, .59f * 255.f, .93f * 255.f };
|
||||
|
||||
const float clearColor[] = {
|
||||
static_cast<float>(DirectXClearColor.r) / 255.f,
|
||||
static_cast<float>(DirectXClearColor.g) / 255.f,
|
||||
static_cast<float>(DirectXClearColor.b) / 255.f,
|
||||
1.0f
|
||||
};
|
||||
devicePtr->ClearRenderTargetView(renderTargetViewPtr, clearColor);
|
||||
devicePtr->ClearDepthStencilView(depthStencilViewPtr, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
|
||||
for (auto* mesh : m_shadowMeshes) {
|
||||
Matrix worldViewProj = mesh->GetWorldMatrix() * camera.GetViewProjectionMatrix();
|
||||
Matrix lightWorldViewProj = mesh->GetWorldMatrix() * lightViewProjection;
|
||||
|
||||
auto* effect = dynamic_cast<ShadowMesh*>(mesh)->GetColorEffectPtr() ;
|
||||
// effect->SetLightWorldViewProjMatrix(m_Light.GetViewProjectionMatrix());
|
||||
|
||||
dynamic_cast<Effect*>(effect)->SetWorldMatrix(worldViewProj);
|
||||
dynamic_cast<Effect*>(effect)->SetWorldViewProjMatrix(worldViewProj);
|
||||
dynamic_cast<Effect*>(effect)->SetWorldMatrix(mesh->GetWorldMatrix());
|
||||
dynamic_cast<Effect*>(effect)->SetShadowMapSampler(shadowSampler);
|
||||
dynamic_cast<Effect*>(effect)->SetShadowMap(shadowMap);
|
||||
dynamic_cast<Effect*>(effect)->SetLightViewProjMatrix(lightWorldViewProj);
|
||||
|
||||
|
||||
dynamic_cast<ShadowMesh*>(mesh)->RenderFinal(devicePtr, worldViewProj);
|
||||
}
|
||||
|
||||
@@ -21,17 +21,20 @@ public:
|
||||
|
||||
std::vector<std::shared_ptr<Material>> &GetMaterials() override;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
std::vector<Mesh *> m_Meshes;
|
||||
std::vector<std::shared_ptr<Material>> m_Materials;
|
||||
|
||||
std::vector<ShadowMesh *> m_shadowMeshes;
|
||||
std::vector<std::shared_ptr<Material>> m_shadowMaterials;
|
||||
|
||||
|
||||
ShadowMapBuffer *m_ShadowMapBuffer{nullptr};
|
||||
Light m_Light;
|
||||
|
||||
float angle = 0.0f;
|
||||
|
||||
void RenderShadowMapToScreen(ID3D11DeviceContext *devicePtr, ID3D11RenderTargetView *renderTargetViewPtr);
|
||||
};
|
||||
|
||||
|
||||
@@ -17,6 +17,10 @@ ShadowMesh::ShadowMesh(ID3D11Device* devicePtr,
|
||||
|
||||
HRESULT result;
|
||||
|
||||
m_Material = material;
|
||||
|
||||
m_ColorEffectPtr->SetMaterial(material.get());
|
||||
|
||||
|
||||
// Create input layout
|
||||
D3D11_INPUT_ELEMENT_DESC vertexDesc[] = {
|
||||
@@ -71,7 +75,6 @@ ShadowMesh::~ShadowMesh() {
|
||||
|
||||
void ShadowMesh::RenderShadow(ID3D11DeviceContext* deviceContextPtr, const Matrix& lightWorldViewProj) {
|
||||
m_ShadowEffectPtr->SetLightWorldViewProjMatrix(lightWorldViewProj);
|
||||
deviceContextPtr->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
deviceContextPtr->IASetInputLayout(m_InputLayoutPtr);
|
||||
|
||||
const UINT stride = sizeof(VertexIn);
|
||||
@@ -90,7 +93,6 @@ void ShadowMesh::RenderShadow(ID3D11DeviceContext* deviceContextPtr, const Matri
|
||||
|
||||
void ShadowMesh::RenderFinal(ID3D11DeviceContext* deviceContextPtr, const Matrix& worldViewProj) {
|
||||
m_ColorEffectPtr->SetWorldViewProjMatrix(worldViewProj);
|
||||
deviceContextPtr->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
deviceContextPtr->IASetInputLayout(m_InputLayoutPtr);
|
||||
|
||||
const UINT stride = sizeof(VertexIn);
|
||||
@@ -100,11 +102,11 @@ void ShadowMesh::RenderFinal(ID3D11DeviceContext* deviceContextPtr, const Matrix
|
||||
|
||||
D3DX11_TECHNIQUE_DESC techniqueDesc;
|
||||
m_ColorEffectPtr->GetTechniquePtr()->GetDesc(&techniqueDesc);
|
||||
|
||||
for (UINT p = 0; p < techniqueDesc.Passes; ++p) {
|
||||
m_ColorEffectPtr->GetTechniquePtr()->GetPassByIndex(p)->Apply(0, deviceContextPtr);
|
||||
deviceContextPtr->DrawIndexed(m_IndicesCount, 0, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ShadowMesh::SetWorldMatrix(const Matrix& matrix) {
|
||||
|
||||
@@ -41,6 +41,7 @@ private:
|
||||
ID3D11Buffer* m_VertexBufferPtr;
|
||||
ID3D11Buffer* m_IndexBufferPtr;
|
||||
|
||||
|
||||
//Shadow buffers
|
||||
ID3D11InputLayout* m_ShadowInputLayoutPtr;
|
||||
ID3D11Buffer* m_ShadowVertexBufferPtr;
|
||||
|
||||
@@ -133,6 +133,7 @@ int main(int argc, char *args[]) {
|
||||
const uint32_t height = 480;
|
||||
|
||||
|
||||
|
||||
SDL_Window *pWindow = SDL_CreateWindow(
|
||||
"DirectX - Bram Verhulst - 2GD11E",
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
|
||||
Reference in New Issue
Block a user