From 6cbd6c54828df63c8409a6e96b55d1093d43f1ba Mon Sep 17 00:00:00 2001 From: Lightling Date: Sat, 19 Mar 2022 14:18:08 -0400 Subject: [PATCH 01/17] shader structs and helpers relocation to includes --- DX11Starter.vcxproj | 3 + DX11Starter.vcxproj.filters | 5 ++ Includes.hlsli | 124 ++++++++++++++++++++++++++++++++++++ PixelShader.hlsl | 20 +----- RandomPixelShader.hlsl | 105 +----------------------------- VertexShader.hlsl | 37 +---------- 6 files changed, 140 insertions(+), 154 deletions(-) create mode 100644 Includes.hlsli diff --git a/DX11Starter.vcxproj b/DX11Starter.vcxproj index 3479be6..17469ca 100644 --- a/DX11Starter.vcxproj +++ b/DX11Starter.vcxproj @@ -285,6 +285,9 @@ $(OutDir)/Assets/Models + + + diff --git a/DX11Starter.vcxproj.filters b/DX11Starter.vcxproj.filters index f39a2d5..1959b75 100644 --- a/DX11Starter.vcxproj.filters +++ b/DX11Starter.vcxproj.filters @@ -121,4 +121,9 @@ Assets\Models + + + Shaders + + \ No newline at end of file diff --git a/Includes.hlsli b/Includes.hlsli new file mode 100644 index 0000000..80f696b --- /dev/null +++ b/Includes.hlsli @@ -0,0 +1,124 @@ +#ifndef __SHADER_INCLUDES__ +#define __SHADER_INCLUDES__ + +// Struct representing the data we expect to receive from earlier pipeline stages +// - Should match the output of our corresponding vertex shader +// - The name of the struct itself is unimportant +// - The variable names don't have to match other shaders (just the semantics) +// - Each variable must have a semantic, which defines its usage +struct VertexToPixel +{ + // Data type + // | + // | Name Semantic + // | | | + // v v v + float4 screenPosition : SV_POSITION; + float2 uv : TEXCOORD; +}; + +// Struct representing a single vertex worth of data +// - This should match the vertex definition in our C++ code +// - By "match", I mean the size, order and number of members +// - The name of the struct itself is unimportant, but should be descriptive +// - Each variable must have a semantic, which defines its usage +struct VertexShaderInput +{ + // Data type + // | + // | Name Semantic + // | | | + // v v v + float3 localPosition : POSITION; + float3 normal : NORMAL; + float2 uv : UV; +}; + +/// BEGIN THIRD PARTY /// +/// SOURCE: https://thebookofshaders.com/edit.php#11/2d-snoise-clear.frag /// + +// Some useful functions +float3 mod289(float3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } +float2 mod289(float2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } +float3 permute(float3 x) { return mod289(((x * 34.0) + 1.0) * x); } + +// +// Description : GLSL 2D simplex noise function +// Author : Ian McEwan, Ashima Arts +// Maintainer : ijm +// Lastmod : 20110822 (ijm) +// License : +// Copyright (C) 2011 Ashima Arts. All rights reserved. +// Distributed under the MIT License. See LICENSE file. +// https://github.com/ashima/webgl-noise +// +float snoise(float2 v) +{ + // Precompute values for skewed triangular grid + const float4 C = float4(0.211324865405187, + // (3.0-sqrt(3.0))/6.0 + 0.366025403784439, + // 0.5*(sqrt(3.0)-1.0) + -0.577350269189626, + // -1.0 + 2.0 * C.x + 0.024390243902439); + // 1.0 / 41.0 + + // First corner (x0) + float2 i = floor(v + dot(v, C.yy)); + float2 x0 = v - i + dot(i, C.xx); + + // Other two corners (x1, x2) + float2 i1 = float2(0, 0); + i1 = (x0.x > x0.y) ? float2(1.0, 0.0) : float2(0.0, 1.0); + float2 x1 = x0.xy + C.xx - i1; + float2 x2 = x0.xy + C.zz; + + // Do some permutations to avoid + // truncation effects in permutation + i = mod289(i); + float3 p = permute( + permute(i.y + float3(0.0, i1.y, 1.0)) + + i.x + float3(0.0, i1.x, 1.0)); + + float3 m = max(0.5 - float3( + dot(x0, x0), + dot(x1, x1), + dot(x2, x2) + ), 0.0); + + m = m * m; + m = m * m; + + // Gradients: + // 41 pts uniformly over a line, mapped onto a diamond + // The ring size 17*17 = 289 is close to a multiple + // of 41 (41*7 = 287) + + float3 x = 2.0 * frac(p * C.www) - 1.0; + float3 h = abs(x) - 0.5; + float3 ox = floor(x + 0.5); + float3 a0 = x - ox; + + // Normalise gradients implicitly by scaling m + // Approximation of: m *= inversesqrt(a0*a0 + h*h); + m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h); + + // Compute final noise value at P + float3 g = float3(0, 0, 0); + g.x = a0.x * x0.x + h.x * x0.y; + g.yz = a0.yz * float2(x1.x, x2.x) + h.yz * float2(x1.y, x2.y); + return 130.0 * dot(m, g); +} + +/// SOURCE: https://thebookofshaders.com/10/ /// +float random(float2 st) +{ + return frac(sin(dot(st.xy, + float2(12.9898, 78.233))) * + 43758.5453123); +} + +/// END THIRD PARTY /// + +#endif diff --git a/PixelShader.hlsl b/PixelShader.hlsl index fbc68fb..302a409 100644 --- a/PixelShader.hlsl +++ b/PixelShader.hlsl @@ -1,24 +1,10 @@ +#include "Includes.hlsli" + cbuffer ExternalData : register(b0) { float4 tint; } -// Struct representing the data we expect to receive from earlier pipeline stages -// - Should match the output of our corresponding vertex shader -// - The name of the struct itself is unimportant -// - The variable names don't have to match other shaders (just the semantics) -// - Each variable must have a semantic, which defines its usage -struct VertexToPixel -{ - // Data type - // | - // | Name Semantic - // | | | - // v v v - float4 screenPosition : SV_POSITION; - float2 uv : TEXCOORD; -}; - // -------------------------------------------------------- // The entry point (main method) for our pixel shader // @@ -35,4 +21,4 @@ float4 main(VertexToPixel input) : SV_TARGET // interpolated for each pixel between the corresponding vertices // of the triangle we're rendering return tint; -} \ No newline at end of file +} diff --git a/RandomPixelShader.hlsl b/RandomPixelShader.hlsl index ad0ec8b..addc7b7 100644 --- a/RandomPixelShader.hlsl +++ b/RandomPixelShader.hlsl @@ -1,89 +1,4 @@ -/// BEGIN THIRD PARTY /// -/// SOURCE: https://thebookofshaders.com/edit.php#11/2d-snoise-clear.frag /// - -// Some useful functions -float3 mod289(float3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } -float2 mod289(float2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } -float3 permute(float3 x) { return mod289(((x * 34.0) + 1.0) * x); } - -// -// Description : GLSL 2D simplex noise function -// Author : Ian McEwan, Ashima Arts -// Maintainer : ijm -// Lastmod : 20110822 (ijm) -// License : -// Copyright (C) 2011 Ashima Arts. All rights reserved. -// Distributed under the MIT License. See LICENSE file. -// https://github.com/ashima/webgl-noise -// -float snoise(float2 v) -{ - // Precompute values for skewed triangular grid - const float4 C = float4(0.211324865405187, - // (3.0-sqrt(3.0))/6.0 - 0.366025403784439, - // 0.5*(sqrt(3.0)-1.0) - -0.577350269189626, - // -1.0 + 2.0 * C.x - 0.024390243902439); - // 1.0 / 41.0 - - // First corner (x0) - float2 i = floor(v + dot(v, C.yy)); - float2 x0 = v - i + dot(i, C.xx); - - // Other two corners (x1, x2) - float2 i1 = float2(0, 0); - i1 = (x0.x > x0.y) ? float2(1.0, 0.0) : float2(0.0, 1.0); - float2 x1 = x0.xy + C.xx - i1; - float2 x2 = x0.xy + C.zz; - - // Do some permutations to avoid - // truncation effects in permutation - i = mod289(i); - float3 p = permute( - permute(i.y + float3(0.0, i1.y, 1.0)) - + i.x + float3(0.0, i1.x, 1.0)); - - float3 m = max(0.5 - float3( - dot(x0, x0), - dot(x1, x1), - dot(x2, x2) - ), 0.0); - - m = m * m; - m = m * m; - - // Gradients: - // 41 pts uniformly over a line, mapped onto a diamond - // The ring size 17*17 = 289 is close to a multiple - // of 41 (41*7 = 287) - - float3 x = 2.0 * frac(p * C.www) - 1.0; - float3 h = abs(x) - 0.5; - float3 ox = floor(x + 0.5); - float3 a0 = x - ox; - - // Normalise gradients implicitly by scaling m - // Approximation of: m *= inversesqrt(a0*a0 + h*h); - m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h); - - // Compute final noise value at P - float3 g = float3(0, 0, 0); - g.x = a0.x * x0.x + h.x * x0.y; - g.yz = a0.yz * float2(x1.x, x2.x) + h.yz * float2(x1.y, x2.y); - return 130.0 * dot(m, g); -} - -/// SOURCE: https://thebookofshaders.com/10/ /// -float random(float2 st) -{ - return frac(sin(dot(st.xy, - float2(12.9898, 78.233))) * - 43758.5453123); -} - -/// END THIRD PARTY /// +#include "Includes.hlsli" cbuffer ExternalData : register(b0) { @@ -91,22 +6,6 @@ cbuffer ExternalData : register(b0) float noise; } -// Struct representing the data we expect to receive from earlier pipeline stages -// - Should match the output of our corresponding vertex shader -// - The name of the struct itself is unimportant -// - The variable names don't have to match other shaders (just the semantics) -// - Each variable must have a semantic, which defines its usage -struct VertexToPixel -{ - // Data type - // | - // | Name Semantic - // | | | - // v v v - float4 screenPosition : SV_POSITION; - float2 uv : TEXCOORD; -}; - // -------------------------------------------------------- // The entry point (main method) for our pixel shader // @@ -127,4 +26,4 @@ float4 main(VertexToPixel input) : SV_TARGET sin(snoise(input.uv * noise) + tint.g - random(input.uv)) + (tint.g * 0.5), sin(snoise(input.uv * noise) + tint.b - random(input.uv)) + (tint.b * 0.5), cos(random(input.screenPosition))); -} \ No newline at end of file +} diff --git a/VertexShader.hlsl b/VertexShader.hlsl index 471a4d8..cd0ab93 100644 --- a/VertexShader.hlsl +++ b/VertexShader.hlsl @@ -1,3 +1,5 @@ +#include "Includes.hlsli" + cbuffer ExternalData : register(b0) { matrix world; @@ -5,39 +7,6 @@ cbuffer ExternalData : register(b0) matrix projection; } -// Struct representing a single vertex worth of data -// - This should match the vertex definition in our C++ code -// - By "match", I mean the size, order and number of members -// - The name of the struct itself is unimportant, but should be descriptive -// - Each variable must have a semantic, which defines its usage -struct VertexShaderInput -{ - // Data type - // | - // | Name Semantic - // | | | - // v v v - float3 localPosition : POSITION; - float3 normal : NORMAL; - float2 uv : UV; -}; - -// Struct representing the data we're sending down the pipeline -// - Should match our pixel shader's input (hence the name: Vertex to Pixel) -// - At a minimum, we need a piece of data defined tagged as SV_POSITION -// - The name of the struct itself is unimportant, but should be descriptive -// - Each variable must have a semantic, which defines its usage -struct VertexToPixel -{ - // Data type - // | - // | Name Semantic - // | | | - // v v v - float4 screenPosition : SV_POSITION; - float2 uv : TEXCOORD; -}; - // -------------------------------------------------------- // The entry point (main method) for our vertex shader // @@ -71,4 +40,4 @@ VertexToPixel main( VertexShaderInput input ) // Whatever we return will make its way through the pipeline to the // next programmable stage we're using (the pixel shader for now) return output; -} \ No newline at end of file +} From 15bf4521b4d74d2da80fadb17d36bc084020537b Mon Sep 17 00:00:00 2001 From: Lightling Date: Sat, 19 Mar 2022 14:32:21 -0400 Subject: [PATCH 02/17] begin working on new pixel shader with roughness --- DX11Starter.vcxproj | 6 ++++++ DX11Starter.vcxproj.filters | 3 +++ Game.cpp | 14 ++++++++------ Material.cpp | 28 +++++++++++++++++++++++++++- Material.h | 4 ++++ SimplePixelShader.hlsl | 12 ++++++++++++ 6 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 SimplePixelShader.hlsl diff --git a/DX11Starter.vcxproj b/DX11Starter.vcxproj index 17469ca..a2e915d 100644 --- a/DX11Starter.vcxproj +++ b/DX11Starter.vcxproj @@ -167,6 +167,12 @@ 5.0 5.0 + + Pixel + Pixel + Pixel + Pixel + Vertex 5.0 diff --git a/DX11Starter.vcxproj.filters b/DX11Starter.vcxproj.filters index 1959b75..da4fb1a 100644 --- a/DX11Starter.vcxproj.filters +++ b/DX11Starter.vcxproj.filters @@ -97,6 +97,9 @@ Shaders + + Shaders + diff --git a/Game.cpp b/Game.cpp index 278fa0a..0c01a7c 100644 --- a/Game.cpp +++ b/Game.cpp @@ -80,7 +80,8 @@ void Game::LoadShaders() { vertexShader = std::make_shared(device, context, GetFullPathTo_Wide(L"VertexShader.cso").c_str()); pixelShader = //std::make_shared(device, context, GetFullPathTo_Wide(L"PixelShader.cso").c_str()); - std::make_shared(device, context, GetFullPathTo_Wide(L"RandomPixelShader.cso").c_str()); + //std::make_shared(device, context, GetFullPathTo_Wide(L"RandomPixelShader.cso").c_str()); + std::make_shared(device, context, GetFullPathTo_Wide(L"SimplePixelShader.cso").c_str()); // thanks to https://harry7557558.github.io/tools/colorpicker.html for having the only 0f-1f picker i could find XMFLOAT4 white = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f); @@ -88,9 +89,9 @@ void Game::LoadShaders() XMFLOAT4 deepcoral = XMFLOAT4(1.0f, 0.39f, 0.22f, 1.0f); materials = { - std::make_shared(white, vertexShader, pixelShader), - std::make_shared(deeppink, vertexShader, pixelShader), - std::make_shared(deepcoral, vertexShader, pixelShader), + std::make_shared(white, 0, vertexShader, pixelShader), + std::make_shared(deeppink, 0, vertexShader, pixelShader), + std::make_shared(deepcoral, 0, vertexShader, pixelShader), }; } @@ -168,6 +169,7 @@ void Game::Update(float deltaTime, float totalTime) for (int i = 0; i < entities.size(); ++i) { entities[i]->GetTransform()->SetRotation(1.0f * (i + 1) * sin(totalTime), 1.0f * (i + 1) * sin(totalTime), 1.0f * (i + 1) * sin(totalTime)); + entities[i]->GetMaterial()->SetRoughness(sin(totalTime) * 0.5f + 0.5f); } } @@ -198,8 +200,8 @@ void Game::Draw(float deltaTime, float totalTime) vs->CopyAllBufferData(); std::shared_ptr ps = entity->GetMaterial()->GetPixelShader(); - ps->SetFloat4("tint", entity->GetMaterial()->GetTint()); - ps->SetFloat("noise", 2.5f + cos(totalTime)); + ps->SetFloat3("cameraPosition", camera->GetTransform()->GetPosition()); + ps->SetFloat("roughness", entity->GetMaterial()->GetRoughness()); ps->CopyAllBufferData(); entity->GetMaterial()->GetVertexShader()->SetShader(); diff --git a/Material.cpp b/Material.cpp index 0c328e0..2d6ad6a 100644 --- a/Material.cpp +++ b/Material.cpp @@ -1,8 +1,13 @@ #include "Material.h" -Material::Material(DirectX::XMFLOAT4 _tint, std::shared_ptr _vertexShader, std::shared_ptr _pixelShader) +Material::Material( + DirectX::XMFLOAT4 _tint, + float _roughness, + std::shared_ptr _vertexShader, + std::shared_ptr _pixelShader) { tint = _tint; + roughness = _roughness; vertexShader = _vertexShader; pixelShader = _pixelShader; } @@ -16,6 +21,11 @@ DirectX::XMFLOAT4 Material::GetTint() return tint; } +float Material::GetRoughness() +{ + return roughness; +} + std::shared_ptr Material::GetVertexShader() { return vertexShader; @@ -31,6 +41,22 @@ void Material::SetTint(DirectX::XMFLOAT4 _tint) tint = _tint; } +void Material::SetRoughness(float _roughness) +{ + if (_roughness > 1) + { + roughness = 1; + } + else if (_roughness < 0) + { + roughness = 0; + } + else + { + roughness = _roughness; + } +} + void Material::SetVertexShader(std::shared_ptr _vertexShader) { vertexShader = _vertexShader; diff --git a/Material.h b/Material.h index b04804d..03d2616 100644 --- a/Material.h +++ b/Material.h @@ -9,20 +9,24 @@ class Material public: Material( DirectX::XMFLOAT4 _tint, + float _roughness, std::shared_ptr _vertexShader, std::shared_ptr _pixelShader); ~Material(); DirectX::XMFLOAT4 GetTint(); + float GetRoughness(); std::shared_ptr GetVertexShader(); std::shared_ptr GetPixelShader(); void SetTint(DirectX::XMFLOAT4 _tint); + void SetRoughness(float _roughness); void SetVertexShader(std::shared_ptr _vertexShader); void SetPixelShader(std::shared_ptr _pixelShader); private: DirectX::XMFLOAT4 tint; + float roughness; std::shared_ptr vertexShader; std::shared_ptr pixelShader; }; diff --git a/SimplePixelShader.hlsl b/SimplePixelShader.hlsl new file mode 100644 index 0000000..3829b3c --- /dev/null +++ b/SimplePixelShader.hlsl @@ -0,0 +1,12 @@ +#include "Includes.hlsli" + +cbuffer ExternalData : register(b0) +{ + float3 cameraPosition; + float roughness; +} + +float4 main() : SV_TARGET +{ + return float4(roughness.rrr, 1); +} From e28af67f2d824cbc4a2c3bc0f199e66abd5264bc Mon Sep 17 00:00:00 2001 From: Lightling Date: Sat, 19 Mar 2022 14:36:47 -0400 Subject: [PATCH 03/17] editor config --- .editorconfig | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..a54d21c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,3 @@ +[*] +indent_style = tab +indent_size = 4 From 948fafec16846030026ab52ff785368bbd382545 Mon Sep 17 00:00:00 2001 From: Lightling Date: Sat, 19 Mar 2022 14:41:21 -0400 Subject: [PATCH 04/17] define ambient for shader --- Game.cpp | 2 ++ SimplePixelShader.hlsl | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Game.cpp b/Game.cpp index 0c01a7c..b9b241f 100644 --- a/Game.cpp +++ b/Game.cpp @@ -180,6 +180,7 @@ void Game::Draw(float deltaTime, float totalTime) { // Background color (Cornflower Blue in this case) for clearing static const float color[4] = { 0.4f, 0.6f, 0.75f, 0.0f }; + static const DirectX::XMFLOAT3 ambient = XMFLOAT3(0.1f, 0.1f, 0.25f); // Clear the render target and depth buffer (erases what's on the screen) // - Do this ONCE PER FRAME @@ -202,6 +203,7 @@ void Game::Draw(float deltaTime, float totalTime) std::shared_ptr ps = entity->GetMaterial()->GetPixelShader(); ps->SetFloat3("cameraPosition", camera->GetTransform()->GetPosition()); ps->SetFloat("roughness", entity->GetMaterial()->GetRoughness()); + ps->SetFloat3("ambient", ambient); ps->CopyAllBufferData(); entity->GetMaterial()->GetVertexShader()->SetShader(); diff --git a/SimplePixelShader.hlsl b/SimplePixelShader.hlsl index 3829b3c..88bca2f 100644 --- a/SimplePixelShader.hlsl +++ b/SimplePixelShader.hlsl @@ -4,9 +4,10 @@ cbuffer ExternalData : register(b0) { float3 cameraPosition; float roughness; + float3 ambient; } float4 main() : SV_TARGET { - return float4(roughness.rrr, 1); + return float4(ambient.rgb, 1); } From 096923a5aaea70b126b4b6331aa123600ecd3942 Mon Sep 17 00:00:00 2001 From: Lightling Date: Sat, 19 Mar 2022 14:47:50 -0400 Subject: [PATCH 05/17] pass normals and worldPosition to pixel shader --- Game.cpp | 1 + Includes.hlsli | 2 ++ SimplePixelShader.hlsl | 5 +++-- VertexShader.hlsl | 5 +++++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Game.cpp b/Game.cpp index b9b241f..9ecca3a 100644 --- a/Game.cpp +++ b/Game.cpp @@ -198,6 +198,7 @@ void Game::Draw(float deltaTime, float totalTime) vs->SetMatrix4x4("world", entity->GetTransform()->GetWorldMatrix()); vs->SetMatrix4x4("view", camera->GetViewMatrix()); vs->SetMatrix4x4("projection", camera->GetProjectionMatrix()); + vs->SetMatrix4x4("worldInvTranspose", camera->GetTransform()->GetWorldMatrixInverseTranspose()); vs->CopyAllBufferData(); std::shared_ptr ps = entity->GetMaterial()->GetPixelShader(); diff --git a/Includes.hlsli b/Includes.hlsli index 80f696b..e5002e5 100644 --- a/Includes.hlsli +++ b/Includes.hlsli @@ -15,6 +15,8 @@ struct VertexToPixel // v v v float4 screenPosition : SV_POSITION; float2 uv : TEXCOORD; + float3 normal : NORMAL; + float3 worldPosition : POSITION; }; // Struct representing a single vertex worth of data diff --git a/SimplePixelShader.hlsl b/SimplePixelShader.hlsl index 88bca2f..a85c019 100644 --- a/SimplePixelShader.hlsl +++ b/SimplePixelShader.hlsl @@ -7,7 +7,8 @@ cbuffer ExternalData : register(b0) float3 ambient; } -float4 main() : SV_TARGET +float4 main(VertexToPixel input) : SV_TARGET { - return float4(ambient.rgb, 1); + input.normal = normalize(input.normal); + return float4(input.normal, 1); } diff --git a/VertexShader.hlsl b/VertexShader.hlsl index cd0ab93..1bcf48b 100644 --- a/VertexShader.hlsl +++ b/VertexShader.hlsl @@ -5,6 +5,7 @@ cbuffer ExternalData : register(b0) matrix world; matrix view; matrix projection; + matrix worldInvTranspose; } // -------------------------------------------------------- @@ -37,6 +38,10 @@ VertexToPixel main( VertexShaderInput input ) // - We don't need to alter it here, but we do need to send it to the pixel shader output.uv = input.uv; + // Pass normal and world position throuh + output.normal = mul((float3x3)worldInvTranspose, input.normal); + output.worldPosition = mul(world, float4(input.localPosition, 1)).xyz; + // Whatever we return will make its way through the pipeline to the // next programmable stage we're using (the pixel shader for now) return output; From 0d920c3722b079146dab0ecc2ec565c2bef7899a Mon Sep 17 00:00:00 2001 From: Lightling Date: Sat, 19 Mar 2022 14:57:54 -0400 Subject: [PATCH 06/17] begin defining lights --- DX11Starter.vcxproj | 1 + DX11Starter.vcxproj.filters | 3 +++ Game.cpp | 11 +++++++++++ Game.h | 4 ++++ Lights.h | 17 +++++++++++++++++ 5 files changed, 36 insertions(+) create mode 100644 Lights.h diff --git a/DX11Starter.vcxproj b/DX11Starter.vcxproj index a2e915d..9287f20 100644 --- a/DX11Starter.vcxproj +++ b/DX11Starter.vcxproj @@ -140,6 +140,7 @@ + diff --git a/DX11Starter.vcxproj.filters b/DX11Starter.vcxproj.filters index da4fb1a..7b1f5b3 100644 --- a/DX11Starter.vcxproj.filters +++ b/DX11Starter.vcxproj.filters @@ -86,6 +86,9 @@ Header Files + + Header Files + diff --git a/Game.cpp b/Game.cpp index 9ecca3a..e569536 100644 --- a/Game.cpp +++ b/Game.cpp @@ -60,6 +60,7 @@ void Game::Init() // geometry to draw and some simple camera matrices. // - You'll be expanding and/or replacing these later LoadShaders(); + LoadLighting(); CreateBasicGeometry(); // Tell the input assembler stage of the pipeline what kind of @@ -95,6 +96,15 @@ void Game::LoadShaders() }; } +void Game::LoadLighting() +{ + directionalLight1 = {}; + directionalLight1.Type = LIGHT_TYPE_DIRECTIONAL; + directionalLight1.Direction = XMFLOAT3(1, -1, 0); + directionalLight1.Color = XMFLOAT3(0.2f, 0.2f, 1.0f); + directionalLight1.Intensity = 1.0f; +} + // -------------------------------------------------------- // Creates the geometry we're going to draw - a single triangle for now // -------------------------------------------------------- @@ -205,6 +215,7 @@ void Game::Draw(float deltaTime, float totalTime) ps->SetFloat3("cameraPosition", camera->GetTransform()->GetPosition()); ps->SetFloat("roughness", entity->GetMaterial()->GetRoughness()); ps->SetFloat3("ambient", ambient); + ps->SetData("directionalLight1", &directionalLight1, sizeof(Light)); ps->CopyAllBufferData(); entity->GetMaterial()->GetVertexShader()->SetShader(); diff --git a/Game.h b/Game.h index 1ca6c20..5c5b510 100644 --- a/Game.h +++ b/Game.h @@ -6,6 +6,7 @@ #include "Entity.h" #include "SimpleShader.h" #include "Material.h" +#include "Lights.h" #include #include // Used for ComPtr - a smart pointer for COM objects #include @@ -33,6 +34,7 @@ private: // Initialization helper methods - feel free to customize, combine, etc. void LoadShaders(); + void LoadLighting(); void CreateBasicGeometry(); // Note the usage of ComPtr below @@ -52,6 +54,8 @@ private: std::shared_ptr camera; // A6 Materials std::vector> materials; + // A7 Lights + Light directionalLight1; Microsoft::WRL::ComPtr constantBufferVS; }; diff --git a/Lights.h b/Lights.h new file mode 100644 index 0000000..b3085ed --- /dev/null +++ b/Lights.h @@ -0,0 +1,17 @@ +#pragma once +#define LIGHT_TYPE_DIRECTIONAL 0 +#define LIGHT_TYPE_POINT 1 +#define LIGHT_TYPE_SPOT 2 +#include + +struct Light +{ + int Type; + DirectX::XMFLOAT3 Direction; + float Range; + DirectX::XMFLOAT3 Position; + float Intensity; + DirectX::XMFLOAT3 Color; + float SpotFalloff; + DirectX::XMFLOAT3 Padding; +}; From cd4ea05aaeeeb0e97bff80f4f3cb13b8acb8c501 Mon Sep 17 00:00:00 2001 From: Lightling Date: Sat, 19 Mar 2022 15:05:40 -0400 Subject: [PATCH 07/17] define light in shader --- Includes.hlsli | 21 +++++++++++++++++++++ Lights.h | 4 +++- SimplePixelShader.hlsl | 3 ++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Includes.hlsli b/Includes.hlsli index e5002e5..d27c845 100644 --- a/Includes.hlsli +++ b/Includes.hlsli @@ -1,6 +1,27 @@ #ifndef __SHADER_INCLUDES__ #define __SHADER_INCLUDES__ +#define LIGHT_TYPE_DIRECTIONAL 0 +#define LIGHT_TYPE_POINT 1 +#define LIGHT_TYPE_SPOT 2 + +#define MAX_SPECULAR_EXPONENT 256.0f + +struct Light +{ + int Type; + float3 Direction; + + float Range; + float3 Position; + + float Intensity; + float3 Color; + + float SpotFalloff; + float3 Padding; +}; + // Struct representing the data we expect to receive from earlier pipeline stages // - Should match the output of our corresponding vertex shader // - The name of the struct itself is unimportant diff --git a/Lights.h b/Lights.h index b3085ed..546f6f6 100644 --- a/Lights.h +++ b/Lights.h @@ -1,8 +1,10 @@ #pragma once + +#include + #define LIGHT_TYPE_DIRECTIONAL 0 #define LIGHT_TYPE_POINT 1 #define LIGHT_TYPE_SPOT 2 -#include struct Light { diff --git a/SimplePixelShader.hlsl b/SimplePixelShader.hlsl index a85c019..8a34fb8 100644 --- a/SimplePixelShader.hlsl +++ b/SimplePixelShader.hlsl @@ -5,10 +5,11 @@ cbuffer ExternalData : register(b0) float3 cameraPosition; float roughness; float3 ambient; + Light directionalLight1; } float4 main(VertexToPixel input) : SV_TARGET { input.normal = normalize(input.normal); - return float4(input.normal, 1); + return float4(directionalLight1.Color, 1); } From 9ca7b66945b959bc83970abfdea4bf04448ba780 Mon Sep 17 00:00:00 2001 From: Lightling Date: Sat, 19 Mar 2022 16:34:55 -0400 Subject: [PATCH 08/17] figure out why normals weren't correct turns out i was passing camera transpose instead of entity transpose --- Game.cpp | 17 +++++++++-------- Includes.hlsli | 3 ++- Material.cpp | 6 +++--- Material.h | 8 ++++---- SimplePixelShader.hlsl | 3 ++- VertexShader.hlsl | 6 +++--- 6 files changed, 23 insertions(+), 20 deletions(-) diff --git a/Game.cpp b/Game.cpp index e569536..00d5c90 100644 --- a/Game.cpp +++ b/Game.cpp @@ -85,14 +85,14 @@ void Game::LoadShaders() std::make_shared(device, context, GetFullPathTo_Wide(L"SimplePixelShader.cso").c_str()); // thanks to https://harry7557558.github.io/tools/colorpicker.html for having the only 0f-1f picker i could find - XMFLOAT4 white = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f); - XMFLOAT4 deeppink = XMFLOAT4(1.0f, 0.08f, 0.4f, 1.0f); - XMFLOAT4 deepcoral = XMFLOAT4(1.0f, 0.39f, 0.22f, 1.0f); + XMFLOAT3 white = XMFLOAT3(1.0f, 1.0f, 1.0f); + XMFLOAT3 deeppink = XMFLOAT3(1.0f, 0.08f, 0.4f); + XMFLOAT3 deepcoral = XMFLOAT3(1.0f, 0.39f, 0.22f); materials = { std::make_shared(white, 0, vertexShader, pixelShader), - std::make_shared(deeppink, 0, vertexShader, pixelShader), - std::make_shared(deepcoral, 0, vertexShader, pixelShader), + std::make_shared(white, 0, vertexShader, pixelShader), + std::make_shared(white, 0, vertexShader, pixelShader), }; } @@ -100,8 +100,8 @@ void Game::LoadLighting() { directionalLight1 = {}; directionalLight1.Type = LIGHT_TYPE_DIRECTIONAL; - directionalLight1.Direction = XMFLOAT3(1, -1, 0); - directionalLight1.Color = XMFLOAT3(0.2f, 0.2f, 1.0f); + directionalLight1.Direction = XMFLOAT3(1, 0, 0); + directionalLight1.Color = XMFLOAT3(1.0f, 0, 0); directionalLight1.Intensity = 1.0f; } @@ -206,14 +206,15 @@ void Game::Draw(float deltaTime, float totalTime) { std::shared_ptr vs = entity->GetMaterial()->GetVertexShader(); vs->SetMatrix4x4("world", entity->GetTransform()->GetWorldMatrix()); + vs->SetMatrix4x4("worldInvTranspose", entity->GetTransform()->GetWorldMatrixInverseTranspose()); vs->SetMatrix4x4("view", camera->GetViewMatrix()); vs->SetMatrix4x4("projection", camera->GetProjectionMatrix()); - vs->SetMatrix4x4("worldInvTranspose", camera->GetTransform()->GetWorldMatrixInverseTranspose()); vs->CopyAllBufferData(); std::shared_ptr ps = entity->GetMaterial()->GetPixelShader(); ps->SetFloat3("cameraPosition", camera->GetTransform()->GetPosition()); ps->SetFloat("roughness", entity->GetMaterial()->GetRoughness()); + ps->SetFloat3("tint", entity->GetMaterial()->GetTint()); ps->SetFloat3("ambient", ambient); ps->SetData("directionalLight1", &directionalLight1, sizeof(Light)); ps->CopyAllBufferData(); diff --git a/Includes.hlsli b/Includes.hlsli index d27c845..1c84004 100644 --- a/Includes.hlsli +++ b/Includes.hlsli @@ -7,6 +7,7 @@ #define MAX_SPECULAR_EXPONENT 256.0f +// Struct representing the data stored in the Lights.h struct Light struct Light { int Type; @@ -54,7 +55,7 @@ struct VertexShaderInput // v v v float3 localPosition : POSITION; float3 normal : NORMAL; - float2 uv : UV; + float2 uv : TEXCOORD; }; /// BEGIN THIRD PARTY /// diff --git a/Material.cpp b/Material.cpp index 2d6ad6a..e4badf9 100644 --- a/Material.cpp +++ b/Material.cpp @@ -1,7 +1,7 @@ #include "Material.h" Material::Material( - DirectX::XMFLOAT4 _tint, + DirectX::XMFLOAT3 _tint, float _roughness, std::shared_ptr _vertexShader, std::shared_ptr _pixelShader) @@ -16,7 +16,7 @@ Material::~Material() { } -DirectX::XMFLOAT4 Material::GetTint() +DirectX::XMFLOAT3 Material::GetTint() { return tint; } @@ -36,7 +36,7 @@ std::shared_ptr Material::GetPixelShader() return pixelShader; } -void Material::SetTint(DirectX::XMFLOAT4 _tint) +void Material::SetTint(DirectX::XMFLOAT3 _tint) { tint = _tint; } diff --git a/Material.h b/Material.h index 03d2616..cb2a191 100644 --- a/Material.h +++ b/Material.h @@ -8,24 +8,24 @@ class Material { public: Material( - DirectX::XMFLOAT4 _tint, + DirectX::XMFLOAT3 _tint, float _roughness, std::shared_ptr _vertexShader, std::shared_ptr _pixelShader); ~Material(); - DirectX::XMFLOAT4 GetTint(); + DirectX::XMFLOAT3 GetTint(); float GetRoughness(); std::shared_ptr GetVertexShader(); std::shared_ptr GetPixelShader(); - void SetTint(DirectX::XMFLOAT4 _tint); + void SetTint(DirectX::XMFLOAT3 _tint); void SetRoughness(float _roughness); void SetVertexShader(std::shared_ptr _vertexShader); void SetPixelShader(std::shared_ptr _pixelShader); private: - DirectX::XMFLOAT4 tint; + DirectX::XMFLOAT3 tint; float roughness; std::shared_ptr vertexShader; std::shared_ptr pixelShader; diff --git a/SimplePixelShader.hlsl b/SimplePixelShader.hlsl index 8a34fb8..c85fca4 100644 --- a/SimplePixelShader.hlsl +++ b/SimplePixelShader.hlsl @@ -5,11 +5,12 @@ cbuffer ExternalData : register(b0) float3 cameraPosition; float roughness; float3 ambient; + float3 tint; Light directionalLight1; } float4 main(VertexToPixel input) : SV_TARGET { input.normal = normalize(input.normal); - return float4(directionalLight1.Color, 1); + return float4(input.normal, 1); } diff --git a/VertexShader.hlsl b/VertexShader.hlsl index 1bcf48b..ce26f2f 100644 --- a/VertexShader.hlsl +++ b/VertexShader.hlsl @@ -3,9 +3,9 @@ cbuffer ExternalData : register(b0) { matrix world; + matrix worldInvTranspose; matrix view; matrix projection; - matrix worldInvTranspose; } // -------------------------------------------------------- @@ -21,7 +21,7 @@ VertexToPixel main( VertexShaderInput input ) VertexToPixel output; // Convert vertex to world view projection - matrix worldViewProjection = mul(mul(projection, view), world); + matrix worldViewProjection = mul(projection, mul(view, world)); // Here we're essentially passing the input position directly through to the next // stage (rasterizer), though it needs to be a 4-component vector now. @@ -39,7 +39,7 @@ VertexToPixel main( VertexShaderInput input ) output.uv = input.uv; // Pass normal and world position throuh - output.normal = mul((float3x3)worldInvTranspose, input.normal); + output.normal = normalize(mul((float3x3)worldInvTranspose, input.normal)); output.worldPosition = mul(world, float4(input.localPosition, 1)).xyz; // Whatever we return will make its way through the pipeline to the From 57650e310e91449a35f1457e4694f57871130831 Mon Sep 17 00:00:00 2001 From: Lightling Date: Sat, 19 Mar 2022 16:39:01 -0400 Subject: [PATCH 09/17] calculate directional light --- SimplePixelShader.hlsl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/SimplePixelShader.hlsl b/SimplePixelShader.hlsl index c85fca4..9396f9b 100644 --- a/SimplePixelShader.hlsl +++ b/SimplePixelShader.hlsl @@ -12,5 +12,10 @@ cbuffer ExternalData : register(b0) float4 main(VertexToPixel input) : SV_TARGET { input.normal = normalize(input.normal); - return float4(input.normal, 1); + float3 ambientTint = ambient * tint; + float3 directionalLight1Dir = normalize(-directionalLight1.Direction); + float diffuse = saturate(dot(input.normal, directionalLight1Dir)); + float3 final = (diffuse * directionalLight1.Color * tint) + ambientTint; + + return float4(final, 1); } From a4bfd4e0c38f95c879c5f5569318eca567c31a27 Mon Sep 17 00:00:00 2001 From: Lightling Date: Sat, 19 Mar 2022 16:49:03 -0400 Subject: [PATCH 10/17] add specular --- SimplePixelShader.hlsl | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/SimplePixelShader.hlsl b/SimplePixelShader.hlsl index 9396f9b..9f539fc 100644 --- a/SimplePixelShader.hlsl +++ b/SimplePixelShader.hlsl @@ -15,7 +15,18 @@ float4 main(VertexToPixel input) : SV_TARGET float3 ambientTint = ambient * tint; float3 directionalLight1Dir = normalize(-directionalLight1.Direction); float diffuse = saturate(dot(input.normal, directionalLight1Dir)); - float3 final = (diffuse * directionalLight1.Color * tint) + ambientTint; + + float3 view = normalize(cameraPosition - input.worldPosition); + float3 reflection = reflect(directionalLight1Dir, input.normal); + + float specularExponent = (1.0f - roughness) * MAX_SPECULAR_EXPONENT; + float specular = 0; + if (specularExponent > 0.05f) + { + specular = pow(saturate(dot(reflection, view)), specularExponent); + } + + float3 final = (diffuse * directionalLight1.Color * tint) + ambientTint + specular; return float4(final, 1); } From 66e2741912d1088763c008d1554d24ab9fd44d49 Mon Sep 17 00:00:00 2001 From: Lightling Date: Sat, 19 Mar 2022 16:55:22 -0400 Subject: [PATCH 11/17] hlsli reorganization --- DX11Starter.vcxproj | 5 +- DX11Starter.vcxproj.filters | 11 ++- Defines.hlsli | 35 +++++++++ Helpers.hlsli | 6 ++ Includes.hlsli | 148 ------------------------------------ Lights.hlsli | 25 ++++++ PixelShader.hlsl | 2 +- RandomPixelShader.hlsl | 3 +- SimplePixelShader.hlsl | 3 +- ThirdPartyFunctions.hlsli | 91 ++++++++++++++++++++++ VertexShader.hlsl | 2 +- 11 files changed, 177 insertions(+), 154 deletions(-) create mode 100644 Defines.hlsli create mode 100644 Helpers.hlsli delete mode 100644 Includes.hlsli create mode 100644 Lights.hlsli create mode 100644 ThirdPartyFunctions.hlsli diff --git a/DX11Starter.vcxproj b/DX11Starter.vcxproj index 9287f20..bfb095b 100644 --- a/DX11Starter.vcxproj +++ b/DX11Starter.vcxproj @@ -293,7 +293,10 @@ - + + + + diff --git a/DX11Starter.vcxproj.filters b/DX11Starter.vcxproj.filters index 7b1f5b3..c75eb6f 100644 --- a/DX11Starter.vcxproj.filters +++ b/DX11Starter.vcxproj.filters @@ -128,7 +128,16 @@ - + + Shaders + + + Shaders + + + Shaders + + Shaders diff --git a/Defines.hlsli b/Defines.hlsli new file mode 100644 index 0000000..e31b1ae --- /dev/null +++ b/Defines.hlsli @@ -0,0 +1,35 @@ +#ifndef __SHADER_DEFINES__ +#define __SHADER_DEFINES__ + +#define MAX_SPECULAR_EXPONENT 256.0f + +// Struct representing the data we expect to receive from earlier pipeline stages +// - Should match the output of our corresponding vertex shader +struct VertexToPixel +{ + // Data type + // | + // | Name Semantic + // | | | + // v v v + float4 screenPosition : SV_POSITION; + float2 uv : TEXCOORD; + float3 normal : NORMAL; + float3 worldPosition : POSITION; +}; + +// Struct representing a single vertex worth of data +// - This should match Vertex.h +struct VertexShaderInput +{ + // Data type + // | + // | Name Semantic + // | | | + // v v v + float3 localPosition : POSITION; + float3 normal : NORMAL; + float2 uv : TEXCOORD; +}; + +#endif diff --git a/Helpers.hlsli b/Helpers.hlsli new file mode 100644 index 0000000..56c9dca --- /dev/null +++ b/Helpers.hlsli @@ -0,0 +1,6 @@ +#ifndef __SHADER_HELPERS__ +#define __SHADER_HELPERS__ + + + +#endif diff --git a/Includes.hlsli b/Includes.hlsli deleted file mode 100644 index 1c84004..0000000 --- a/Includes.hlsli +++ /dev/null @@ -1,148 +0,0 @@ -#ifndef __SHADER_INCLUDES__ -#define __SHADER_INCLUDES__ - -#define LIGHT_TYPE_DIRECTIONAL 0 -#define LIGHT_TYPE_POINT 1 -#define LIGHT_TYPE_SPOT 2 - -#define MAX_SPECULAR_EXPONENT 256.0f - -// Struct representing the data stored in the Lights.h struct Light -struct Light -{ - int Type; - float3 Direction; - - float Range; - float3 Position; - - float Intensity; - float3 Color; - - float SpotFalloff; - float3 Padding; -}; - -// Struct representing the data we expect to receive from earlier pipeline stages -// - Should match the output of our corresponding vertex shader -// - The name of the struct itself is unimportant -// - The variable names don't have to match other shaders (just the semantics) -// - Each variable must have a semantic, which defines its usage -struct VertexToPixel -{ - // Data type - // | - // | Name Semantic - // | | | - // v v v - float4 screenPosition : SV_POSITION; - float2 uv : TEXCOORD; - float3 normal : NORMAL; - float3 worldPosition : POSITION; -}; - -// Struct representing a single vertex worth of data -// - This should match the vertex definition in our C++ code -// - By "match", I mean the size, order and number of members -// - The name of the struct itself is unimportant, but should be descriptive -// - Each variable must have a semantic, which defines its usage -struct VertexShaderInput -{ - // Data type - // | - // | Name Semantic - // | | | - // v v v - float3 localPosition : POSITION; - float3 normal : NORMAL; - float2 uv : TEXCOORD; -}; - -/// BEGIN THIRD PARTY /// -/// SOURCE: https://thebookofshaders.com/edit.php#11/2d-snoise-clear.frag /// - -// Some useful functions -float3 mod289(float3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } -float2 mod289(float2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } -float3 permute(float3 x) { return mod289(((x * 34.0) + 1.0) * x); } - -// -// Description : GLSL 2D simplex noise function -// Author : Ian McEwan, Ashima Arts -// Maintainer : ijm -// Lastmod : 20110822 (ijm) -// License : -// Copyright (C) 2011 Ashima Arts. All rights reserved. -// Distributed under the MIT License. See LICENSE file. -// https://github.com/ashima/webgl-noise -// -float snoise(float2 v) -{ - // Precompute values for skewed triangular grid - const float4 C = float4(0.211324865405187, - // (3.0-sqrt(3.0))/6.0 - 0.366025403784439, - // 0.5*(sqrt(3.0)-1.0) - -0.577350269189626, - // -1.0 + 2.0 * C.x - 0.024390243902439); - // 1.0 / 41.0 - - // First corner (x0) - float2 i = floor(v + dot(v, C.yy)); - float2 x0 = v - i + dot(i, C.xx); - - // Other two corners (x1, x2) - float2 i1 = float2(0, 0); - i1 = (x0.x > x0.y) ? float2(1.0, 0.0) : float2(0.0, 1.0); - float2 x1 = x0.xy + C.xx - i1; - float2 x2 = x0.xy + C.zz; - - // Do some permutations to avoid - // truncation effects in permutation - i = mod289(i); - float3 p = permute( - permute(i.y + float3(0.0, i1.y, 1.0)) - + i.x + float3(0.0, i1.x, 1.0)); - - float3 m = max(0.5 - float3( - dot(x0, x0), - dot(x1, x1), - dot(x2, x2) - ), 0.0); - - m = m * m; - m = m * m; - - // Gradients: - // 41 pts uniformly over a line, mapped onto a diamond - // The ring size 17*17 = 289 is close to a multiple - // of 41 (41*7 = 287) - - float3 x = 2.0 * frac(p * C.www) - 1.0; - float3 h = abs(x) - 0.5; - float3 ox = floor(x + 0.5); - float3 a0 = x - ox; - - // Normalise gradients implicitly by scaling m - // Approximation of: m *= inversesqrt(a0*a0 + h*h); - m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h); - - // Compute final noise value at P - float3 g = float3(0, 0, 0); - g.x = a0.x * x0.x + h.x * x0.y; - g.yz = a0.yz * float2(x1.x, x2.x) + h.yz * float2(x1.y, x2.y); - return 130.0 * dot(m, g); -} - -/// SOURCE: https://thebookofshaders.com/10/ /// -float random(float2 st) -{ - return frac(sin(dot(st.xy, - float2(12.9898, 78.233))) * - 43758.5453123); -} - -/// END THIRD PARTY /// - -#endif diff --git a/Lights.hlsli b/Lights.hlsli new file mode 100644 index 0000000..3fd4973 --- /dev/null +++ b/Lights.hlsli @@ -0,0 +1,25 @@ +#ifndef __SHADER_LIGHTS__ +#define __SHADER_LIGHTS__ + +#define LIGHT_TYPE_DIRECTIONAL 0 +#define LIGHT_TYPE_POINT 1 +#define LIGHT_TYPE_SPOT 2 + +// Struct representing light data +// - This should match Lights.h +struct Light +{ + int Type; + float3 Direction; + + float Range; + float3 Position; + + float Intensity; + float3 Color; + + float SpotFalloff; + float3 Padding; +}; + +#endif diff --git a/PixelShader.hlsl b/PixelShader.hlsl index 302a409..7404576 100644 --- a/PixelShader.hlsl +++ b/PixelShader.hlsl @@ -1,4 +1,4 @@ -#include "Includes.hlsli" +#include "Defines.hlsli" cbuffer ExternalData : register(b0) { diff --git a/RandomPixelShader.hlsl b/RandomPixelShader.hlsl index addc7b7..3df7ddc 100644 --- a/RandomPixelShader.hlsl +++ b/RandomPixelShader.hlsl @@ -1,4 +1,5 @@ -#include "Includes.hlsli" +#include "Defines.hlsli" +#include "ThirdPartyFunctions.hlsli" cbuffer ExternalData : register(b0) { diff --git a/SimplePixelShader.hlsl b/SimplePixelShader.hlsl index 9f539fc..70db7c4 100644 --- a/SimplePixelShader.hlsl +++ b/SimplePixelShader.hlsl @@ -1,4 +1,5 @@ -#include "Includes.hlsli" +#include "Defines.hlsli" +#include "Lights.hlsli" cbuffer ExternalData : register(b0) { diff --git a/ThirdPartyFunctions.hlsli b/ThirdPartyFunctions.hlsli new file mode 100644 index 0000000..22adbbb --- /dev/null +++ b/ThirdPartyFunctions.hlsli @@ -0,0 +1,91 @@ +#ifndef __SHADER_THIRD_PARTY_FUNCTIONS__ +#define __SHADER_THIRD_PARTY_FUNCTIONS__ + +/// BEGIN THIRD PARTY /// +/// SOURCE: https://thebookofshaders.com/edit.php#11/2d-snoise-clear.frag /// + +// Some useful functions +float3 mod289(float3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } +float2 mod289(float2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } +float3 permute(float3 x) { return mod289(((x * 34.0) + 1.0) * x); } + +// +// Description : GLSL 2D simplex noise function +// Author : Ian McEwan, Ashima Arts +// Maintainer : ijm +// Lastmod : 20110822 (ijm) +// License : +// Copyright (C) 2011 Ashima Arts. All rights reserved. +// Distributed under the MIT License. See LICENSE file. +// https://github.com/ashima/webgl-noise +// +float snoise(float2 v) +{ + // Precompute values for skewed triangular grid + const float4 C = float4(0.211324865405187, + // (3.0-sqrt(3.0))/6.0 + 0.366025403784439, + // 0.5*(sqrt(3.0)-1.0) + -0.577350269189626, + // -1.0 + 2.0 * C.x + 0.024390243902439); + // 1.0 / 41.0 + + // First corner (x0) + float2 i = floor(v + dot(v, C.yy)); + float2 x0 = v - i + dot(i, C.xx); + + // Other two corners (x1, x2) + float2 i1 = float2(0, 0); + i1 = (x0.x > x0.y) ? float2(1.0, 0.0) : float2(0.0, 1.0); + float2 x1 = x0.xy + C.xx - i1; + float2 x2 = x0.xy + C.zz; + + // Do some permutations to avoid + // truncation effects in permutation + i = mod289(i); + float3 p = permute( + permute(i.y + float3(0.0, i1.y, 1.0)) + + i.x + float3(0.0, i1.x, 1.0)); + + float3 m = max(0.5 - float3( + dot(x0, x0), + dot(x1, x1), + dot(x2, x2) + ), 0.0); + + m = m * m; + m = m * m; + + // Gradients: + // 41 pts uniformly over a line, mapped onto a diamond + // The ring size 17*17 = 289 is close to a multiple + // of 41 (41*7 = 287) + + float3 x = 2.0 * frac(p * C.www) - 1.0; + float3 h = abs(x) - 0.5; + float3 ox = floor(x + 0.5); + float3 a0 = x - ox; + + // Normalise gradients implicitly by scaling m + // Approximation of: m *= inversesqrt(a0*a0 + h*h); + m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h); + + // Compute final noise value at P + float3 g = float3(0, 0, 0); + g.x = a0.x * x0.x + h.x * x0.y; + g.yz = a0.yz * float2(x1.x, x2.x) + h.yz * float2(x1.y, x2.y); + return 130.0 * dot(m, g); +} + +/// SOURCE: https://thebookofshaders.com/10/ /// +float random(float2 st) +{ + return frac(sin(dot(st.xy, + float2(12.9898, 78.233))) * + 43758.5453123); +} + +/// END THIRD PARTY /// + +#endif \ No newline at end of file diff --git a/VertexShader.hlsl b/VertexShader.hlsl index ce26f2f..85973ee 100644 --- a/VertexShader.hlsl +++ b/VertexShader.hlsl @@ -1,4 +1,4 @@ -#include "Includes.hlsli" +#include "Defines.hlsli" cbuffer ExternalData : register(b0) { From e96c1c2e55e7905d930ad2efa5176e3214931e38 Mon Sep 17 00:00:00 2001 From: Lightling Date: Sat, 19 Mar 2022 17:09:27 -0400 Subject: [PATCH 12/17] refactor into helpers --- Helpers.hlsli | 28 ++++++++++++++++++++++++++++ SimplePixelShader.hlsl | 25 +++++++++++++------------ 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/Helpers.hlsli b/Helpers.hlsli index 56c9dca..0a6244b 100644 --- a/Helpers.hlsli +++ b/Helpers.hlsli @@ -1,6 +1,34 @@ #ifndef __SHADER_HELPERS__ #define __SHADER_HELPERS__ +float3 getView(float3 cameraPosition, float3 pixelWorldPosition) +{ + return normalize(cameraPosition - pixelWorldPosition); +} +float3 getReflection(float3 direction, float3 normal) +{ + return reflect(direction, normal); +} + +float getSpecularExponent(float roughness, float max) +{ + return (1.0f - roughness) * max; +} + +float getSpecular(float3 view, float3 reflection, float exponent) +{ + float specular = 0; + if (exponent > 0.05f) + { + specular = pow(saturate(dot(reflection, view)), exponent); + } + return specular; +} + +float getDiffuse(float3 normal, float3 direction) +{ + return saturate(dot(normal, direction)); +} #endif diff --git a/SimplePixelShader.hlsl b/SimplePixelShader.hlsl index 70db7c4..2a89796 100644 --- a/SimplePixelShader.hlsl +++ b/SimplePixelShader.hlsl @@ -1,4 +1,5 @@ #include "Defines.hlsli" +#include "Helpers.hlsli" #include "Lights.hlsli" cbuffer ExternalData : register(b0) @@ -10,24 +11,24 @@ cbuffer ExternalData : register(b0) Light directionalLight1; } +float calculateSpecular(float3 normal, float3 worldPosition, float3 cameraPosition, float3 direction, float roughness) +{ + return getSpecular( + getView(cameraPosition, worldPosition), + getReflection(direction, normal), + getSpecularExponent(roughness, MAX_SPECULAR_EXPONENT) + ); +} + float4 main(VertexToPixel input) : SV_TARGET { input.normal = normalize(input.normal); - float3 ambientTint = ambient * tint; float3 directionalLight1Dir = normalize(-directionalLight1.Direction); - float diffuse = saturate(dot(input.normal, directionalLight1Dir)); - float3 view = normalize(cameraPosition - input.worldPosition); - float3 reflection = reflect(directionalLight1Dir, input.normal); + float diffuse = getDiffuse(input.normal, directionalLight1Dir); + float specular = calculateSpecular(input.normal, input.worldPosition, cameraPosition, directionalLight1Dir, roughness); - float specularExponent = (1.0f - roughness) * MAX_SPECULAR_EXPONENT; - float specular = 0; - if (specularExponent > 0.05f) - { - specular = pow(saturate(dot(reflection, view)), specularExponent); - } - - float3 final = (diffuse * directionalLight1.Color * tint) + ambientTint + specular; + float3 final = (diffuse * directionalLight1.Color * tint) + (ambient * tint) + specular; return float4(final, 1); } From db81b3a3b97a778dfb449331ff30aea6dceb2418 Mon Sep 17 00:00:00 2001 From: Lightling Date: Sat, 19 Mar 2022 17:23:25 -0400 Subject: [PATCH 13/17] create helper for directional light --- Game.cpp | 2 +- SimplePixelShader.hlsl | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Game.cpp b/Game.cpp index 00d5c90..ff5aed4 100644 --- a/Game.cpp +++ b/Game.cpp @@ -179,7 +179,7 @@ void Game::Update(float deltaTime, float totalTime) for (int i = 0; i < entities.size(); ++i) { entities[i]->GetTransform()->SetRotation(1.0f * (i + 1) * sin(totalTime), 1.0f * (i + 1) * sin(totalTime), 1.0f * (i + 1) * sin(totalTime)); - entities[i]->GetMaterial()->SetRoughness(sin(totalTime) * 0.5f + 0.5f); + entities[i]->GetMaterial()->SetRoughness(sin(totalTime * 4) * 0.5f + 0.49f); } } diff --git a/SimplePixelShader.hlsl b/SimplePixelShader.hlsl index 2a89796..f95df1a 100644 --- a/SimplePixelShader.hlsl +++ b/SimplePixelShader.hlsl @@ -11,7 +11,7 @@ cbuffer ExternalData : register(b0) Light directionalLight1; } -float calculateSpecular(float3 normal, float3 worldPosition, float3 cameraPosition, float3 direction, float roughness) +float calculateSpecular(float3 normal, float3 direction, float3 worldPosition, float3 cameraPosition, float roughness) { return getSpecular( getView(cameraPosition, worldPosition), @@ -20,15 +20,22 @@ float calculateSpecular(float3 normal, float3 worldPosition, float3 cameraPositi ); } +float3 calculateDirectionalLight(Light light, float3 normal, float3 worldPosition, float3 cameraPosition, float roughness, float3 surfaceColor) +{ + float3 lightDirection = normalize(light.Direction); + float diffuse = getDiffuse(normal, -lightDirection); + float specular = calculateSpecular(normal, lightDirection, worldPosition, cameraPosition, roughness); + + return (diffuse * surfaceColor + specular) * light.Intensity * light.Color; +} + float4 main(VertexToPixel input) : SV_TARGET { input.normal = normalize(input.normal); - float3 directionalLight1Dir = normalize(-directionalLight1.Direction); - float diffuse = getDiffuse(input.normal, directionalLight1Dir); - float specular = calculateSpecular(input.normal, input.worldPosition, cameraPosition, directionalLight1Dir, roughness); - - float3 final = (diffuse * directionalLight1.Color * tint) + (ambient * tint) + specular; + float3 light = calculateDirectionalLight(directionalLight1, input.normal, input.worldPosition, cameraPosition, roughness, tint); + float3 ambientTint = ambient * tint; + float3 final = light + ambientTint; return float4(final, 1); } From 8ec8b16a88fad7c99de61e73480643450c30fa02 Mon Sep 17 00:00:00 2001 From: Lightling Date: Sat, 19 Mar 2022 17:39:52 -0400 Subject: [PATCH 14/17] support 3 directional lights --- DX11Starter.vcxproj | 12 ++++++++++++ Game.cpp | 27 +++++++++++++++++++++------ Game.h | 3 ++- SimplePixelShader.hlsl | 20 +++++++++++++++----- 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/DX11Starter.vcxproj b/DX11Starter.vcxproj index bfb095b..9a57e96 100644 --- a/DX11Starter.vcxproj +++ b/DX11Starter.vcxproj @@ -80,6 +80,9 @@ Windows + + 5.0 + @@ -91,6 +94,9 @@ Windows + + 5.0 + @@ -106,6 +112,9 @@ true true + + 5.0 + @@ -121,6 +130,9 @@ true true + + 5.0 + diff --git a/Game.cpp b/Game.cpp index ff5aed4..49c6853 100644 --- a/Game.cpp +++ b/Game.cpp @@ -98,11 +98,27 @@ void Game::LoadShaders() void Game::LoadLighting() { - directionalLight1 = {}; + ambient = XMFLOAT3(0.05f, 0.05f, 0.20f); + Light directionalLight0 = {}; + directionalLight0.Type = LIGHT_TYPE_DIRECTIONAL; + directionalLight0.Direction = XMFLOAT3(1, 0, 0); + directionalLight0.Color = XMFLOAT3(1, 0, 0); + directionalLight0.Intensity = 1; + Light directionalLight1 = {}; directionalLight1.Type = LIGHT_TYPE_DIRECTIONAL; - directionalLight1.Direction = XMFLOAT3(1, 0, 0); - directionalLight1.Color = XMFLOAT3(1.0f, 0, 0); - directionalLight1.Intensity = 1.0f; + directionalLight1.Direction = XMFLOAT3(0, -1, 0); + directionalLight1.Color = XMFLOAT3(0, 1, 0); + directionalLight1.Intensity = 1; + Light directionalLight2 = {}; + directionalLight2.Type = LIGHT_TYPE_DIRECTIONAL; + directionalLight2.Direction = XMFLOAT3(-1, 1, -0.5f); + directionalLight2.Color = XMFLOAT3(0, 0, 1); + directionalLight2.Intensity = 1; + lights = { + directionalLight0, + directionalLight1, + directionalLight2, + }; } // -------------------------------------------------------- @@ -190,7 +206,6 @@ void Game::Draw(float deltaTime, float totalTime) { // Background color (Cornflower Blue in this case) for clearing static const float color[4] = { 0.4f, 0.6f, 0.75f, 0.0f }; - static const DirectX::XMFLOAT3 ambient = XMFLOAT3(0.1f, 0.1f, 0.25f); // Clear the render target and depth buffer (erases what's on the screen) // - Do this ONCE PER FRAME @@ -216,7 +231,7 @@ void Game::Draw(float deltaTime, float totalTime) ps->SetFloat("roughness", entity->GetMaterial()->GetRoughness()); ps->SetFloat3("tint", entity->GetMaterial()->GetTint()); ps->SetFloat3("ambient", ambient); - ps->SetData("directionalLight1", &directionalLight1, sizeof(Light)); + ps->SetData("lights", &lights[0], sizeof(Light) * (int)lights.size()); ps->CopyAllBufferData(); entity->GetMaterial()->GetVertexShader()->SetShader(); diff --git a/Game.h b/Game.h index 5c5b510..7a58050 100644 --- a/Game.h +++ b/Game.h @@ -55,7 +55,8 @@ private: // A6 Materials std::vector> materials; // A7 Lights - Light directionalLight1; + std::vector lights; + DirectX::XMFLOAT3 ambient; Microsoft::WRL::ComPtr constantBufferVS; }; diff --git a/SimplePixelShader.hlsl b/SimplePixelShader.hlsl index f95df1a..d986fcb 100644 --- a/SimplePixelShader.hlsl +++ b/SimplePixelShader.hlsl @@ -2,13 +2,16 @@ #include "Helpers.hlsli" #include "Lights.hlsli" +// temporary +#define LIGHT_COUNT 3 + cbuffer ExternalData : register(b0) { float3 cameraPosition; float roughness; float3 ambient; float3 tint; - Light directionalLight1; + Light lights[LIGHT_COUNT]; } float calculateSpecular(float3 normal, float3 direction, float3 worldPosition, float3 cameraPosition, float roughness) @@ -33,9 +36,16 @@ float4 main(VertexToPixel input) : SV_TARGET { input.normal = normalize(input.normal); - float3 light = calculateDirectionalLight(directionalLight1, input.normal, input.worldPosition, cameraPosition, roughness, tint); - float3 ambientTint = ambient * tint; - float3 final = light + ambientTint; + float3 light = ambient * tint; + for (int i = 0; i < LIGHT_COUNT; i++) + { + switch (lights[i].Type) + { + case LIGHT_TYPE_DIRECTIONAL: + light += calculateDirectionalLight(lights[i], input.normal, input.worldPosition, cameraPosition, roughness, tint); + break; + } + } - return float4(final, 1); + return float4(light, 1); } From 141df67a72fe9740959c16e80aff32a99cafde1b Mon Sep 17 00:00:00 2001 From: Lightling Date: Sat, 19 Mar 2022 18:00:11 -0400 Subject: [PATCH 15/17] support point lights --- Game.cpp | 38 ++++++++++++++++++++++++++------------ Helpers.hlsli | 7 +++++++ SimplePixelShader.hlsl | 15 ++++++++++++++- 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/Game.cpp b/Game.cpp index 49c6853..bcc27aa 100644 --- a/Game.cpp +++ b/Game.cpp @@ -91,8 +91,8 @@ void Game::LoadShaders() materials = { std::make_shared(white, 0, vertexShader, pixelShader), - std::make_shared(white, 0, vertexShader, pixelShader), - std::make_shared(white, 0, vertexShader, pixelShader), + std::make_shared(deeppink, 0, vertexShader, pixelShader), + std::make_shared(deepcoral, 0, vertexShader, pixelShader), }; } @@ -114,10 +114,24 @@ void Game::LoadLighting() directionalLight2.Direction = XMFLOAT3(-1, 1, -0.5f); directionalLight2.Color = XMFLOAT3(0, 0, 1); directionalLight2.Intensity = 1; + Light pointLight0 = {}; + pointLight0.Type = LIGHT_TYPE_POINT; + pointLight0.Position = XMFLOAT3(-2, -2, 0); + pointLight0.Color = XMFLOAT3(1, 1, 0); + pointLight0.Intensity = 1; + pointLight0.Range = 10; + Light pointLight1 = {}; + pointLight1.Type = LIGHT_TYPE_POINT; + pointLight1.Position = XMFLOAT3(2, 2, 0); + pointLight1.Color = XMFLOAT3(0, 1, 1); + pointLight1.Intensity = 1; + pointLight1.Range = 10; lights = { directionalLight0, directionalLight1, directionalLight2, + pointLight0, + pointLight1, }; } @@ -137,27 +151,27 @@ void Game::CreateBasicGeometry() std::make_shared( GetFullPathTo("Assets/Models/helix.obj").c_str(), device, context), - std::make_shared( - GetFullPathTo("Assets/Models/quad.obj").c_str(), - device, context), - std::make_shared( - GetFullPathTo("Assets/Models/quad_double_sided.obj").c_str(), - device, context), std::make_shared( GetFullPathTo("Assets/Models/sphere.obj").c_str(), device, context), std::make_shared( GetFullPathTo("Assets/Models/torus.obj").c_str(), device, context), + std::make_shared( + GetFullPathTo("Assets/Models/quad.obj").c_str(), + device, context), + std::make_shared( + GetFullPathTo("Assets/Models/quad_double_sided.obj").c_str(), + device, context), }; entities = { std::make_shared(materials[0], shapes[0]), - std::make_shared(materials[1], shapes[1]), - std::make_shared(materials[2], shapes[2]), + std::make_shared(materials[0], shapes[1]), + std::make_shared(materials[0], shapes[2]), std::make_shared(materials[0], shapes[3]), - std::make_shared(materials[1], shapes[4]), - std::make_shared(materials[2], shapes[5]), + std::make_shared(materials[0], shapes[4]), + std::make_shared(materials[0], shapes[5]), std::make_shared(materials[0], shapes[6]), }; diff --git a/Helpers.hlsli b/Helpers.hlsli index 0a6244b..99e296a 100644 --- a/Helpers.hlsli +++ b/Helpers.hlsli @@ -31,4 +31,11 @@ float getDiffuse(float3 normal, float3 direction) return saturate(dot(normal, direction)); } +float getAttenuation(float3 pointPosition, float3 worldPosition, float3 range) +{ + float dist = distance(pointPosition, worldPosition); + float attn = saturate(1.0f - (dist * dist / (range * range))); + return attn * attn; +} + #endif diff --git a/SimplePixelShader.hlsl b/SimplePixelShader.hlsl index d986fcb..2443ab5 100644 --- a/SimplePixelShader.hlsl +++ b/SimplePixelShader.hlsl @@ -3,7 +3,7 @@ #include "Lights.hlsli" // temporary -#define LIGHT_COUNT 3 +#define LIGHT_COUNT 5 cbuffer ExternalData : register(b0) { @@ -32,6 +32,16 @@ float3 calculateDirectionalLight(Light light, float3 normal, float3 worldPositio return (diffuse * surfaceColor + specular) * light.Intensity * light.Color; } +float3 calculatePointLight(Light light, float3 normal, float3 worldPosition, float3 cameraPosition, float roughness, float3 surfaceColor) +{ + float3 lightDirection = normalize(worldPosition - light.Position); + float attenuation = getAttenuation(light.Position, worldPosition, light.Range); + float diffuse = getDiffuse(normal, -lightDirection); + float specular = calculateSpecular(normal, lightDirection, worldPosition, cameraPosition, roughness); + + return (diffuse * surfaceColor + specular) * attenuation * light.Intensity * light.Color; +} + float4 main(VertexToPixel input) : SV_TARGET { input.normal = normalize(input.normal); @@ -44,6 +54,9 @@ float4 main(VertexToPixel input) : SV_TARGET case LIGHT_TYPE_DIRECTIONAL: light += calculateDirectionalLight(lights[i], input.normal, input.worldPosition, cameraPosition, roughness, tint); break; + case LIGHT_TYPE_POINT: + light += calculatePointLight(lights[i], input.normal, input.worldPosition, cameraPosition, roughness, tint); + break; } } From daa850622a174c13ddd41054fd72cc4ab1ed00fe Mon Sep 17 00:00:00 2001 From: Lightling Date: Sat, 19 Mar 2022 18:07:52 -0400 Subject: [PATCH 16/17] shader comments --- Helpers.hlsli | 6 ++++++ SimplePixelShader.hlsl | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/Helpers.hlsli b/Helpers.hlsli index 99e296a..80f6e47 100644 --- a/Helpers.hlsli +++ b/Helpers.hlsli @@ -1,21 +1,25 @@ #ifndef __SHADER_HELPERS__ #define __SHADER_HELPERS__ +// gets view vector, needed once per shader float3 getView(float3 cameraPosition, float3 pixelWorldPosition) { return normalize(cameraPosition - pixelWorldPosition); } +// gets reflection vector, needed per light float3 getReflection(float3 direction, float3 normal) { return reflect(direction, normal); } +// gets specular exponent: (1-roughness) * max float getSpecularExponent(float roughness, float max) { return (1.0f - roughness) * max; } +// gets specular value: clamp(dot(r,v))^e float getSpecular(float3 view, float3 reflection, float exponent) { float specular = 0; @@ -26,11 +30,13 @@ float getSpecular(float3 view, float3 reflection, float exponent) return specular; } +// gets diffuse value: clamp(dot(n,d)) float getDiffuse(float3 normal, float3 direction) { return saturate(dot(normal, direction)); } +// gets attenuation: clamp(1 - (distance^2 / range^2))^2 float getAttenuation(float3 pointPosition, float3 worldPosition, float3 range) { float dist = distance(pointPosition, worldPosition); diff --git a/SimplePixelShader.hlsl b/SimplePixelShader.hlsl index 2443ab5..8667f0e 100644 --- a/SimplePixelShader.hlsl +++ b/SimplePixelShader.hlsl @@ -14,6 +14,7 @@ cbuffer ExternalData : register(b0) Light lights[LIGHT_COUNT]; } +// Gets the specular value for any light float calculateSpecular(float3 normal, float3 direction, float3 worldPosition, float3 cameraPosition, float roughness) { return getSpecular( @@ -23,6 +24,7 @@ float calculateSpecular(float3 normal, float3 direction, float3 worldPosition, f ); } +// Gets the RGB value of a pixel with a directional light float3 calculateDirectionalLight(Light light, float3 normal, float3 worldPosition, float3 cameraPosition, float roughness, float3 surfaceColor) { float3 lightDirection = normalize(light.Direction); @@ -32,6 +34,7 @@ float3 calculateDirectionalLight(Light light, float3 normal, float3 worldPositio return (diffuse * surfaceColor + specular) * light.Intensity * light.Color; } +// Gets the RGB value of a pixel with a point light float3 calculatePointLight(Light light, float3 normal, float3 worldPosition, float3 cameraPosition, float roughness, float3 surfaceColor) { float3 lightDirection = normalize(worldPosition - light.Position); @@ -42,11 +45,15 @@ float3 calculatePointLight(Light light, float3 normal, float3 worldPosition, flo return (diffuse * surfaceColor + specular) * attenuation * light.Intensity * light.Color; } +// shader entry point float4 main(VertexToPixel input) : SV_TARGET { input.normal = normalize(input.normal); + // start with ambient light and material tint float3 light = ambient * tint; + + // loop through lights for (int i = 0; i < LIGHT_COUNT; i++) { switch (lights[i].Type) From 3d7c777db674245cfd768f6945c018909c0cfdaf Mon Sep 17 00:00:00 2001 From: Lightling Date: Sat, 19 Mar 2022 18:12:50 -0400 Subject: [PATCH 17/17] shader optimization: calculate view once per shader --- SimplePixelShader.hlsl | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/SimplePixelShader.hlsl b/SimplePixelShader.hlsl index 8667f0e..bb0bd6a 100644 --- a/SimplePixelShader.hlsl +++ b/SimplePixelShader.hlsl @@ -15,32 +15,32 @@ cbuffer ExternalData : register(b0) } // Gets the specular value for any light -float calculateSpecular(float3 normal, float3 direction, float3 worldPosition, float3 cameraPosition, float roughness) +float calculateSpecular(float3 normal, float3 direction, float3 view, float roughness) { return getSpecular( - getView(cameraPosition, worldPosition), + view, getReflection(direction, normal), getSpecularExponent(roughness, MAX_SPECULAR_EXPONENT) ); } // Gets the RGB value of a pixel with a directional light -float3 calculateDirectionalLight(Light light, float3 normal, float3 worldPosition, float3 cameraPosition, float roughness, float3 surfaceColor) +float3 calculateDirectionalLight(Light light, float3 normal, float3 view, float roughness, float3 surfaceColor) { float3 lightDirection = normalize(light.Direction); float diffuse = getDiffuse(normal, -lightDirection); - float specular = calculateSpecular(normal, lightDirection, worldPosition, cameraPosition, roughness); + float specular = calculateSpecular(normal, lightDirection, view, roughness); return (diffuse * surfaceColor + specular) * light.Intensity * light.Color; } // Gets the RGB value of a pixel with a point light -float3 calculatePointLight(Light light, float3 normal, float3 worldPosition, float3 cameraPosition, float roughness, float3 surfaceColor) +float3 calculatePointLight(Light light, float3 normal, float3 view, float3 worldPosition, float roughness, float3 surfaceColor) { float3 lightDirection = normalize(worldPosition - light.Position); float attenuation = getAttenuation(light.Position, worldPosition, light.Range); float diffuse = getDiffuse(normal, -lightDirection); - float specular = calculateSpecular(normal, lightDirection, worldPosition, cameraPosition, roughness); + float specular = calculateSpecular(normal, lightDirection, view, roughness); return (diffuse * surfaceColor + specular) * attenuation * light.Intensity * light.Color; } @@ -48,8 +48,12 @@ float3 calculatePointLight(Light light, float3 normal, float3 worldPosition, flo // shader entry point float4 main(VertexToPixel input) : SV_TARGET { + // ensure input normals are normalized input.normal = normalize(input.normal); + // view only needs calculated once, so pre-calculate here and pass it to lights + float3 view = getView(cameraPosition, input.worldPosition); + // start with ambient light and material tint float3 light = ambient * tint; @@ -59,10 +63,10 @@ float4 main(VertexToPixel input) : SV_TARGET switch (lights[i].Type) { case LIGHT_TYPE_DIRECTIONAL: - light += calculateDirectionalLight(lights[i], input.normal, input.worldPosition, cameraPosition, roughness, tint); + light += calculateDirectionalLight(lights[i], input.normal, view, roughness, tint); break; case LIGHT_TYPE_POINT: - light += calculatePointLight(lights[i], input.normal, input.worldPosition, cameraPosition, roughness, tint); + light += calculatePointLight(lights[i], input.normal, view, input.worldPosition, roughness, tint); break; } }