diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index f98a6054..7ba730e0 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -335,11 +335,37 @@ When reviewing documentation, do the following: - Don't fix pre-existing issues unrelated to your task. However, if you discover bugs directly caused by or tightly coupled to the code you're changing, fix those too. - Update documentation if it is directly related to the changes you are making. - Always validate that your changes don't break existing behavior. -- Only run linters, builds and tests that already exist. Do not add new linting, building or testing tools unless necessary. -- Use the smallest targeted test, build, or lint command that covers the changed behavior. + +### Linting, Building, Testing + +- Only run linters, builds and tests that already exist. Do not add new linting, building or testing tools unless necessary for the task. +- Use the smallest targeted test, build, or lint command that covers the changed behavior. When related targeted selectors use the same runner, include them in one invocation; escalate to full-suite or baseline runs only when targeted validation shows they are needed. +- Documentation changes do not need to be linted, built or tested unless there are specific tests for documentation. + +### Using Ecosystem Tools + - Prefer ecosystem tools (package managers, scaffolding, refactoring tools, linters) over manual changes. -- Only comment code that needs clarification. Do not comment otherwise. +- Install packages only when changing dependencies or after a missing-dependency failure. + +### Code Commenting Style + +- Only comment code that needs a bit of clarification. Do not comment otherwise. ## Release Process The release process is documented in the [release skill](.github/skills/release/SKILL.md). Invoke the `release` skill for step-by-step guidance when performing a release. + +## CoPilot Skills + +The project includes published CoPilot skills for developers: + +- **Release-Process**: Guide for performing the DirectX Tool Kit release process. Invoked when asked to help with releasing a new version, publishing packages, or updating ports. See [Release Process skill](.github/skills/release/SKILL.md) for details. +- **directxtk12-usage**: Provides usage guidance for the DirectX Tool Kit for DX12 library. Located in the `skills/directxtk12-usage/` directory. +- **directxtk12-tutorial**: Provides an interactive tutorial which can create a project, add the toolkit, and implement features in a step-by-step fashion. Located in the `skills/directxtk12-tutorial` directory. + +To use these skills in the Copilot CLI: + +```bash +/skills list +/skills search directxtk12 +``` diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ff1e161..2d783008 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -151,6 +151,7 @@ set(LIBRARY_SOURCES Src/ModelLoadSDKMESH.cpp Src/ModelLoadVBO.cpp Src/NormalMapEffect.cpp + Src/NPREffect.cpp Src/PBREffect.cpp Src/PBREffectFactory.cpp Src/pch.h @@ -172,6 +173,7 @@ set(SHADER_SOURCES Src/Shaders/EnvironmentMapEffect.fx Src/Shaders/GenerateMips.hlsl Src/Shaders/NormalMapEffect.fx + Src/Shaders/NPREffect.fx Src/Shaders/PBREffect.fx Src/Shaders/PostProcess.fx Src/Shaders/RootSig.fxh diff --git a/DirectXTK_Desktop_2022_Win10.vcxproj b/DirectXTK_Desktop_2022_Win10.vcxproj index 89db95de..4965e855 100644 --- a/DirectXTK_Desktop_2022_Win10.vcxproj +++ b/DirectXTK_Desktop_2022_Win10.vcxproj @@ -111,6 +111,7 @@ + @@ -193,6 +194,11 @@ Document + + + Document + + {3E0E8608-CD9B-4C76-AF33-29CA38F2C9F0} Win32Proj diff --git a/DirectXTK_Desktop_2022_Win10.vcxproj.filters b/DirectXTK_Desktop_2022_Win10.vcxproj.filters index 1ec33539..5116af65 100644 --- a/DirectXTK_Desktop_2022_Win10.vcxproj.filters +++ b/DirectXTK_Desktop_2022_Win10.vcxproj.filters @@ -281,6 +281,9 @@ Src + + Src + Src @@ -376,6 +379,9 @@ Src\Shaders + + Src\Shaders + Src\Shaders\Shared diff --git a/DirectXTK_Desktop_2026.vcxproj b/DirectXTK_Desktop_2026.vcxproj index fd498f0d..5704fd65 100644 --- a/DirectXTK_Desktop_2026.vcxproj +++ b/DirectXTK_Desktop_2026.vcxproj @@ -111,6 +111,7 @@ + @@ -193,6 +194,11 @@ Document + + + Document + + {3E0E8608-CD9B-4C76-AF33-29CA38F2C9F0} Win32Proj diff --git a/DirectXTK_Desktop_2026.vcxproj.filters b/DirectXTK_Desktop_2026.vcxproj.filters index 1ec33539..5116af65 100644 --- a/DirectXTK_Desktop_2026.vcxproj.filters +++ b/DirectXTK_Desktop_2026.vcxproj.filters @@ -281,6 +281,9 @@ Src + + Src + Src @@ -376,6 +379,9 @@ Src\Shaders + + Src\Shaders + Src\Shaders\Shared diff --git a/DirectXTK_GDKW_2022.vcxproj b/DirectXTK_GDKW_2022.vcxproj index bf83e1a1..d83bf563 100644 --- a/DirectXTK_GDKW_2022.vcxproj +++ b/DirectXTK_GDKW_2022.vcxproj @@ -438,6 +438,7 @@ + @@ -511,6 +512,11 @@ Document + + + Document + + diff --git a/DirectXTK_GDKW_2022.vcxproj.filters b/DirectXTK_GDKW_2022.vcxproj.filters index cb5d5384..8a878fbe 100644 --- a/DirectXTK_GDKW_2022.vcxproj.filters +++ b/DirectXTK_GDKW_2022.vcxproj.filters @@ -260,6 +260,9 @@ Src + + Src + Src @@ -346,6 +349,9 @@ Src\Shaders + + Src\Shaders + Src\Shaders diff --git a/DirectXTK_GDKX_2022.vcxproj b/DirectXTK_GDKX_2022.vcxproj index fef34f47..60aec220 100644 --- a/DirectXTK_GDKX_2022.vcxproj +++ b/DirectXTK_GDKX_2022.vcxproj @@ -612,6 +612,7 @@ + @@ -693,6 +694,11 @@ Document + + + Document + + diff --git a/DirectXTK_GDKX_2022.vcxproj.filters b/DirectXTK_GDKX_2022.vcxproj.filters index b3e20206..efb30072 100644 --- a/DirectXTK_GDKX_2022.vcxproj.filters +++ b/DirectXTK_GDKX_2022.vcxproj.filters @@ -266,6 +266,9 @@ Src + + Src + Src @@ -355,6 +358,9 @@ Src\Shaders + + Src\Shaders + Src\Shaders diff --git a/DirectXTK_GDKX_2026.vcxproj b/DirectXTK_GDKX_2026.vcxproj index 60e1b528..9f85832f 100644 --- a/DirectXTK_GDKX_2026.vcxproj +++ b/DirectXTK_GDKX_2026.vcxproj @@ -612,6 +612,7 @@ + @@ -693,6 +694,11 @@ Document + + + Document + + diff --git a/DirectXTK_GDKX_2026.vcxproj.filters b/DirectXTK_GDKX_2026.vcxproj.filters index b3e20206..efb30072 100644 --- a/DirectXTK_GDKX_2026.vcxproj.filters +++ b/DirectXTK_GDKX_2026.vcxproj.filters @@ -266,6 +266,9 @@ Src + + Src + Src @@ -355,6 +358,9 @@ Src\Shaders + + Src\Shaders + Src\Shaders diff --git a/DirectXTK_GDK_2022.vcxproj b/DirectXTK_GDK_2022.vcxproj index 1542f005..fdbd09bf 100644 --- a/DirectXTK_GDK_2022.vcxproj +++ b/DirectXTK_GDK_2022.vcxproj @@ -597,6 +597,7 @@ + @@ -678,6 +679,11 @@ Document + + + Document + + diff --git a/DirectXTK_GDK_2022.vcxproj.filters b/DirectXTK_GDK_2022.vcxproj.filters index b3e20206..efb30072 100644 --- a/DirectXTK_GDK_2022.vcxproj.filters +++ b/DirectXTK_GDK_2022.vcxproj.filters @@ -266,6 +266,9 @@ Src + + Src + Src @@ -355,6 +358,9 @@ Src\Shaders + + Src\Shaders + Src\Shaders diff --git a/DirectXTK_Windows10_2022.vcxproj b/DirectXTK_Windows10_2022.vcxproj index 473be188..6a19fdd2 100644 --- a/DirectXTK_Windows10_2022.vcxproj +++ b/DirectXTK_Windows10_2022.vcxproj @@ -124,6 +124,7 @@ + @@ -195,6 +196,11 @@ Document + + + Document + + {945B8F0E-AE5F-447C-933A-9D069532D3E4} StaticLibrary diff --git a/DirectXTK_Windows10_2022.vcxproj.filters b/DirectXTK_Windows10_2022.vcxproj.filters index 8bfddbfc..9f01fe06 100644 --- a/DirectXTK_Windows10_2022.vcxproj.filters +++ b/DirectXTK_Windows10_2022.vcxproj.filters @@ -221,6 +221,9 @@ Src\Shaders + + Src\Shaders + Src\Shaders\Shared @@ -350,6 +353,9 @@ Src + + Src + Src diff --git a/Inc/Effects.h b/Inc/Effects.h index aa0343d5..3fd7a300 100644 --- a/Inc/Effects.h +++ b/Inc/Effects.h @@ -556,7 +556,7 @@ namespace DirectX DIRECTX_TOOLKIT_API void __cdecl SetFogEnd(float value) override; DIRECTX_TOOLKIT_API void XM_CALLCONV SetFogColor(FXMVECTOR value) override; - // Texture setting - albedo, normal and specular intensity + // Texture settings - albedo, normal and specular intensity. DIRECTX_TOOLKIT_API void __cdecl SetTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor); DIRECTX_TOOLKIT_API void __cdecl SetNormalTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor); DIRECTX_TOOLKIT_API void __cdecl SetSpecularTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor); @@ -751,6 +751,90 @@ namespace DirectX }; + //------------------------------------------------------------------------------ + // Built-in shader for non-photorealistic rendering + class NPREffect : public IEffect, public IEffectMatrices, public IEffectLights + { + public: + enum Mode : uint32_t + { + Mode_Cel = 0, // Cel (toon) shading + Mode_Gooch, // Gooch shading + Mode_MatCap, // Material Capture shading + }; + + DIRECTX_TOOLKIT_API NPREffect( + _In_ ID3D12Device* device, + uint32_t effectFlags, + const EffectPipelineStateDescription& pipelineDescription, + Mode nprMode = Mode_Cel); + + DIRECTX_TOOLKIT_API NPREffect(NPREffect&&) noexcept; + DIRECTX_TOOLKIT_API NPREffect& operator= (NPREffect&&) noexcept; + + NPREffect(NPREffect const&) = delete; + NPREffect& operator= (NPREffect const&) = delete; + + DIRECTX_TOOLKIT_API ~NPREffect() override; + + // IEffect methods. + DIRECTX_TOOLKIT_API void __cdecl Apply(_In_ ID3D12GraphicsCommandList* commandList) override; + + // Camera settings. + DIRECTX_TOOLKIT_API void XM_CALLCONV SetWorld(FXMMATRIX value) override; + DIRECTX_TOOLKIT_API void XM_CALLCONV SetView(FXMMATRIX value) override; + DIRECTX_TOOLKIT_API void XM_CALLCONV SetProjection(FXMMATRIX value) override; + DIRECTX_TOOLKIT_API void XM_CALLCONV SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection) override; + + // Material settings. + DIRECTX_TOOLKIT_API void XM_CALLCONV SetDiffuseColor(FXMVECTOR value); + DIRECTX_TOOLKIT_API void XM_CALLCONV SetSpecularColor(FXMVECTOR value); + DIRECTX_TOOLKIT_API void __cdecl SetSpecularThreshold(float threshold, float smoothing); + DIRECTX_TOOLKIT_API void __cdecl DisableSpecular(); + DIRECTX_TOOLKIT_API void __cdecl SetAlpha(float value); + DIRECTX_TOOLKIT_API void XM_CALLCONV SetColorAndAlpha(FXMVECTOR value); + + // Light settings. + void XM_CALLCONV SetLightDirection(int whichLight, FXMVECTOR value) override; + DIRECTX_TOOLKIT_API void __cdecl EnableDefaultLighting() override; + + static constexpr int MaxDirectionalLights = 1; + + // Texture setting. + DIRECTX_TOOLKIT_API void __cdecl SetTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor); + + // Cel shading setting. + DIRECTX_TOOLKIT_API void __cdecl SetCelShaderBands(int bands); + + // Gooch shading settings. + DIRECTX_TOOLKIT_API void XM_CALLCONV SetGoochCoolColor(FXMVECTOR value, float alpha = 0.25f); + DIRECTX_TOOLKIT_API void XM_CALLCONV SetGoochWarmColor(FXMVECTOR value, float beta = 0.25f); + + // MatCap shading settings. + DIRECTX_TOOLKIT_API void __cdecl SetMatCap(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor); + DIRECTX_TOOLKIT_API void __cdecl SetMatCap(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor); + + // Rim lighting settings. + DIRECTX_TOOLKIT_API void XM_CALLCONV SetRimLightingColor(FXMVECTOR value); + DIRECTX_TOOLKIT_API void __cdecl SetRimLightingPower(float power); + DIRECTX_TOOLKIT_API void __cdecl SetRimLightingIntensity(float strength); + DIRECTX_TOOLKIT_API void __cdecl SetRimLightingRange(float start, float end); + DIRECTX_TOOLKIT_API void __cdecl DisableRimLighting(); + + private: + // Private implementation. + class Impl; + + std::unique_ptr pImpl; + + // Unsupported interface methods. + DIRECTX_TOOLKIT_API void XM_CALLCONV SetAmbientLightColor(FXMVECTOR value) override; + DIRECTX_TOOLKIT_API void __cdecl SetLightEnabled(int whichLight, bool value) override; + DIRECTX_TOOLKIT_API void XM_CALLCONV SetLightDiffuseColor(int whichLight, FXMVECTOR value) override; + DIRECTX_TOOLKIT_API void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) override; + }; + + //------------------------------------------------------------------------------ // Abstract interface to factory texture resources class DIRECTX_TOOLKIT_API IEffectTextureFactory diff --git a/Src/DebugEffect.cpp b/Src/DebugEffect.cpp index 25d1c939..02329903 100644 --- a/Src/DebugEffect.cpp +++ b/Src/DebugEffect.cpp @@ -369,22 +369,13 @@ int DebugEffect::Impl::GetPipelineStatePermutation(DebugEffect::Mode debugMode, void DebugEffect::Impl::Apply(_In_ ID3D12GraphicsCommandList* commandList) { // Compute derived parameter values. - matrices.SetConstants(dirtyFlags, constants.worldViewProj); - - // World inverse transpose matrix. - if (dirtyFlags & EffectDirtyFlags::WorldInverseTranspose) - { - constants.world = XMMatrixTranspose(matrices.world); - - const XMMATRIX worldInverse = XMMatrixInverse(nullptr, matrices.world); - - constants.worldInverseTranspose[0] = worldInverse.r[0]; - constants.worldInverseTranspose[1] = worldInverse.r[1]; - constants.worldInverseTranspose[2] = worldInverse.r[2]; - - dirtyFlags &= ~EffectDirtyFlags::WorldInverseTranspose; - dirtyFlags |= EffectDirtyFlags::ConstantBuffer; - } + XMVECTOR eyePosition{}; + matrices.SetConstants( + dirtyFlags, + constants.world, + constants.worldInverseTranspose, + constants.worldViewProj, + eyePosition); UpdateConstants(); diff --git a/Src/EffectCommon.cpp b/Src/EffectCommon.cpp index a662ad3d..584b0816 100644 --- a/Src/EffectCommon.cpp +++ b/Src/EffectCommon.cpp @@ -37,7 +37,8 @@ EffectMatrices::EffectMatrices() noexcept // Lazily recomputes the combined world+view+projection matrix. -_Use_decl_annotations_ void EffectMatrices::SetConstants(int& dirtyFlags, XMMATRIX& worldViewProjConstant) +_Use_decl_annotations_ +void EffectMatrices::SetConstants(int& dirtyFlags, XMMATRIX& worldViewProjConstant) { if (dirtyFlags & EffectDirtyFlags::WorldViewProj) { @@ -51,6 +52,54 @@ _Use_decl_annotations_ void EffectMatrices::SetConstants(int& dirtyFlags, XMMATR } +// Lazily recomputes the combined world+view+projection matrix, inverse, eyePosition, etc. +// This version is used for effects that do not use the EffectLights helper. +_Use_decl_annotations_ +void EffectMatrices::SetConstants( + int& dirtyFlags, + XMMATRIX& worldConstant, + XMVECTOR worldInverseTransposeConstant[3], + XMMATRIX& worldViewProjConstant, + XMVECTOR& eyePositionConstant) +{ + // Combined world+view+projection matrix. + if (dirtyFlags & EffectDirtyFlags::WorldViewProj) + { + worldView = XMMatrixMultiply(world, view); + + worldViewProjConstant = XMMatrixTranspose(XMMatrixMultiply(worldView, projection)); + + dirtyFlags &= ~EffectDirtyFlags::WorldViewProj; + dirtyFlags |= EffectDirtyFlags::ConstantBuffer; + } + + // World inverse transpose matrix. + if (dirtyFlags & EffectDirtyFlags::WorldInverseTranspose) + { + worldConstant = XMMatrixTranspose(world); + + const XMMATRIX worldInverse = XMMatrixInverse(nullptr, world); + + worldInverseTransposeConstant[0] = worldInverse.r[0]; + worldInverseTransposeConstant[1] = worldInverse.r[1]; + worldInverseTransposeConstant[2] = worldInverse.r[2]; + + dirtyFlags &= ~EffectDirtyFlags::WorldInverseTranspose; + dirtyFlags |= EffectDirtyFlags::ConstantBuffer; + } + + // Eye position. + if (dirtyFlags & EffectDirtyFlags::EyePosition) + { + const XMMATRIX viewInverse = XMMatrixInverse(nullptr, view); + eyePositionConstant = viewInverse.r[3]; + + dirtyFlags &= ~EffectDirtyFlags::EyePosition; + dirtyFlags |= EffectDirtyFlags::ConstantBuffer; + } +} + + // Constructor initializes default fog settings. EffectFog::EffectFog() noexcept : enabled(false), @@ -156,7 +205,12 @@ EffectLights::EffectLights() noexcept : #endif // Initializes constant buffer fields to match the current lighting state. -_Use_decl_annotations_ void EffectLights::InitializeConstants(XMVECTOR& specularColorAndPowerConstant, XMVECTOR* lightDirectionConstant, XMVECTOR* lightDiffuseConstant, XMVECTOR* lightSpecularConstant) const +_Use_decl_annotations_ +void EffectLights::InitializeConstants( + XMVECTOR& specularColorAndPowerConstant, + XMVECTOR* lightDirectionConstant, + XMVECTOR* lightDiffuseConstant, + XMVECTOR* lightSpecularConstant) const { static const XMVECTORF32 defaultSpecular = { { { 1, 1, 1, 16 } } }; static const XMVECTORF32 defaultLightDirection = { { { 0, -1, 0, 0 } } }; @@ -179,7 +233,15 @@ _Use_decl_annotations_ void EffectLights::InitializeConstants(XMVECTOR& specular // Lazily recomputes derived parameter values used by shader lighting calculations. _Use_decl_annotations_ -void EffectLights::SetConstants(int& dirtyFlags, EffectMatrices const& matrices, XMMATRIX& worldConstant, XMVECTOR worldInverseTransposeConstant[3], XMVECTOR& eyePositionConstant, XMVECTOR& diffuseColorConstant, XMVECTOR& emissiveColorConstant, bool lightingEnabled) +void EffectLights::SetConstants( + int& dirtyFlags, + EffectMatrices const& matrices, + XMMATRIX& worldConstant, + XMVECTOR worldInverseTransposeConstant[3], + XMVECTOR& eyePositionConstant, + XMVECTOR& diffuseColorConstant, + XMVECTOR& emissiveColorConstant, + bool lightingEnabled) { if (lightingEnabled) { @@ -263,7 +325,12 @@ void EffectLights::SetConstants(int& dirtyFlags, EffectMatrices const& matrices, #endif // Helper for turning one of the directional lights on or off. -_Use_decl_annotations_ int EffectLights::SetLightEnabled(int whichLight, bool value, XMVECTOR* lightDiffuseConstant, XMVECTOR* lightSpecularConstant) +_Use_decl_annotations_ +int EffectLights::SetLightEnabled( + int whichLight, + bool value, + XMVECTOR* lightDiffuseConstant, + XMVECTOR* lightSpecularConstant) { ValidateLightIndex(whichLight); diff --git a/Src/EffectCommon.h b/Src/EffectCommon.h index c5bae970..54381752 100644 --- a/Src/EffectCommon.h +++ b/Src/EffectCommon.h @@ -63,6 +63,14 @@ namespace DirectX XMMATRIX worldView; void SetConstants(_Inout_ int& dirtyFlags, _Inout_ XMMATRIX& worldViewProjConstant); + + // Helper for effects that don't use EffectLights, but have eye position. + void SetConstants( + _Inout_ int& dirtyFlags, + _Inout_ XMMATRIX& worldConstant, + _Inout_updates_(3) XMVECTOR worldInverseTransposeConstant[3], + _Inout_ XMMATRIX& worldViewProjConstant, + _Inout_ XMVECTOR& eyePositionConstant); }; @@ -75,7 +83,10 @@ namespace DirectX float start; float end; - void XM_CALLCONV SetConstants(_Inout_ int& dirtyFlags, _In_ FXMMATRIX worldView, _Inout_ XMVECTOR& fogVectorConstant); + void XM_CALLCONV SetConstants( + _Inout_ int& dirtyFlags, + _In_ FXMMATRIX worldView, + _Inout_ XMVECTOR& fogVectorConstant); }; @@ -109,12 +120,34 @@ namespace DirectX // Methods. - void InitializeConstants(_Out_ XMVECTOR& specularColorAndPowerConstant, _Out_writes_all_(MaxDirectionalLights) XMVECTOR* lightDirectionConstant, _Out_writes_all_(MaxDirectionalLights) XMVECTOR* lightDiffuseConstant, _Out_writes_all_(MaxDirectionalLights) XMVECTOR* lightSpecularConstant) const; - void SetConstants(_Inout_ int& dirtyFlags, _In_ EffectMatrices const& matrices, _Inout_ XMMATRIX& worldConstant, _Inout_updates_(3) XMVECTOR worldInverseTransposeConstant[3], _Inout_ XMVECTOR& eyePositionConstant, _Inout_ XMVECTOR& diffuseColorConstant, _Inout_ XMVECTOR& emissiveColorConstant, bool lightingEnabled); - - int SetLightEnabled(int whichLight, bool value, _Inout_updates_(MaxDirectionalLights) XMVECTOR* lightDiffuseConstant, _Inout_updates_(MaxDirectionalLights) XMVECTOR* lightSpecularConstant); - int XM_CALLCONV SetLightDiffuseColor(int whichLight, FXMVECTOR value, _Inout_updates_(MaxDirectionalLights) XMVECTOR* lightDiffuseConstant); - int XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value, _Inout_updates_(MaxDirectionalLights) XMVECTOR* lightSpecularConstant); + void InitializeConstants( + _Out_ XMVECTOR& specularColorAndPowerConstant, + _Out_writes_all_(MaxDirectionalLights) XMVECTOR* lightDirectionConstant, + _Out_writes_all_(MaxDirectionalLights) XMVECTOR* lightDiffuseConstant, + _Out_writes_all_(MaxDirectionalLights) XMVECTOR* lightSpecularConstant) const; + void SetConstants( + _Inout_ int& dirtyFlags, + _In_ EffectMatrices const& matrices, + _Inout_ XMMATRIX& worldConstant, + _Inout_updates_(3) XMVECTOR worldInverseTransposeConstant[3], + _Inout_ XMVECTOR& eyePositionConstant, + _Inout_ XMVECTOR& diffuseColorConstant, + _Inout_ XMVECTOR& emissiveColorConstant, + bool lightingEnabled); + + int SetLightEnabled( + int whichLight, + bool value, + _Inout_updates_(MaxDirectionalLights) XMVECTOR* lightDiffuseConstant, + _Inout_updates_(MaxDirectionalLights) XMVECTOR* lightSpecularConstant); + int XM_CALLCONV SetLightDiffuseColor( + int whichLight, + FXMVECTOR value, + _Inout_updates_(MaxDirectionalLights) XMVECTOR* lightDiffuseConstant); + int XM_CALLCONV SetLightSpecularColor( + int whichLight, + FXMVECTOR value, + _Inout_updates_(MaxDirectionalLights) XMVECTOR* lightSpecularConstant); static void ValidateLightIndex(int whichLight); static void EnableDefaultLighting(_In_ IEffectLights* effect); diff --git a/Src/NPREffect.cpp b/Src/NPREffect.cpp new file mode 100644 index 00000000..62ac253b --- /dev/null +++ b/Src/NPREffect.cpp @@ -0,0 +1,1019 @@ +//-------------------------------------------------------------------------------------- +// File: NPREffect.cpp +// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// +// https://go.microsoft.com/fwlink/?LinkID=615561 +//-------------------------------------------------------------------------------------- + +#include "pch.h" +#include "EffectCommon.h" + +using namespace DirectX; + +namespace +{ + // Constant buffer layout. Must match the shader! + struct NPREffectConstants + { + XMVECTOR lightDirectionAndCelBands; + XMVECTOR diffuseColorAndAlpha; + XMVECTOR specularColorAndSpecularThreshold; + XMVECTOR rimColorAndPower; + XMVECTOR extraSettings; // .x = SpecularSmoothing, .y = RimStrength, .z = RimStart, .w = RimEnd + XMVECTOR goochCoolColorAndAlpha; + XMVECTOR goochWarmColorAndBeta; + XMVECTOR eyePosition; + XMMATRIX world; + XMVECTOR worldInverseTranspose[3]; + XMMATRIX worldViewProj; + }; + + static_assert((sizeof(NPREffectConstants) % 16) == 0, "CB size not padded correctly"); + + + // Traits type describes our characteristics to the EffectBase template. + struct NPREffectTraits + { + using ConstantBufferType = NPREffectConstants; + + static constexpr int VertexShaderCount = 32; + static constexpr int PixelShaderCount = 6; + static constexpr int ShaderPermutationCount = 48; + static constexpr int RootSignatureCount = 3; + }; + + + // Default values + constexpr XMVECTORF32 s_defaultLightDir = { { { 0.f, -1.f, 0.f, 4.f } } }; + constexpr XMVECTORF32 s_defaultDiffuse = { { { 1.f, 1.f, 1.f, 1.f } } }; + constexpr XMVECTORF32 s_defaultSpecular = { { { 1.f, 1.f, 1.f, 0.95f } } }; + constexpr XMVECTORF32 s_defaultRim = { { { 0.f, 0.f, 0.f, 4.f } } }; + constexpr XMVECTORF32 s_defaultExtraSettings = { { { 0.004f, 0.75f, 0.2f, 0.6f } } }; + constexpr XMVECTORF32 s_defaultCool = { { { 0.f, 0.f, 0.55f, 0.25f } } }; + constexpr XMVECTORF32 s_defaultWarm = { { { 0.3f, 0.3f, 0.f, 0.25f } } }; +} + + +// Internal NPREffect implementation class. +class NPREffect::Impl : public EffectBase +{ +public: + Impl(_In_ ID3D12Device* device, uint32_t effectFlags, const EffectPipelineStateDescription& pipelineDescription, + NPREffect::Mode nprMode); + + Impl(const Impl&) = delete; + Impl& operator=(const Impl&) = delete; + + Impl(Impl&&) = default; + Impl& operator=(Impl&&) = default; + + enum RootParameterIndex + { + ConstantBuffer, + TextureSRV, + TextureSampler, + Texture2SRV, + RootParameterCount + }; + + bool matCapEnabled; + bool textureEnabled; + + D3D12_GPU_DESCRIPTOR_HANDLE texture; + D3D12_GPU_DESCRIPTOR_HANDLE sampler; + D3D12_GPU_DESCRIPTOR_HANDLE matcap; + + int GetPipelineStatePermutation(NPREffect::Mode nprMode, uint32_t effectFlags) const noexcept; + + void Apply(_In_ ID3D12GraphicsCommandList* commandList); +}; + + +#pragma region Shaders +// Include the precompiled shader code. +namespace +{ +#ifdef _GAMING_XBOX_SCARLETT +#include "XboxGamingScarlettNPREffect_VSNPREffect.inc" +#include "XboxGamingScarlettNPREffect_VSNPREffectInst.inc" + +#include "XboxGamingScarlettNPREffect_VSNPREffectVc.inc" +#include "XboxGamingScarlettNPREffect_VSNPREffectVcInst.inc" + +#include "XboxGamingScarlettNPREffect_VSNPREffectBn.inc" +#include "XboxGamingScarlettNPREffect_VSNPREffectBnInst.inc" + +#include "XboxGamingScarlettNPREffect_VSNPREffectVcBn.inc" +#include "XboxGamingScarlettNPREffect_VSNPREffectVcBnInst.inc" + +#include "XboxGamingScarlettNPREffect_VSNPREffectTx.inc" +#include "XboxGamingScarlettNPREffect_VSNPREffectInstTx.inc" + +#include "XboxGamingScarlettNPREffect_VSNPREffectVcTx.inc" +#include "XboxGamingScarlettNPREffect_VSNPREffectVcInstTx.inc" + +#include "XboxGamingScarlettNPREffect_VSNPREffectBnTx.inc" +#include "XboxGamingScarlettNPREffect_VSNPREffectBnInstTx.inc" + +#include "XboxGamingScarlettNPREffect_VSNPREffectVcBnTx.inc" +#include "XboxGamingScarlettNPREffect_VSNPREffectVcBnInstTx.inc" + +#include "XboxGamingScarlettNPREffect_PSCelShading.inc" +#include "XboxGamingScarlettNPREffect_PSCelShadingTx.inc" + +#include "XboxGamingScarlettNPREffect_PSGoochShading.inc" +#include "XboxGamingScarlettNPREffect_PSGoochShadingTx.inc" + +#include "XboxGamingScarlettNPREffect_VSNPREffectMC.inc" +#include "XboxGamingScarlettNPREffect_VSNPREffectInstMC.inc" + +#include "XboxGamingScarlettNPREffect_VSNPREffectVcMC.inc" +#include "XboxGamingScarlettNPREffect_VSNPREffectVcInstMC.inc" + +#include "XboxGamingScarlettNPREffect_VSNPREffectBnMC.inc" +#include "XboxGamingScarlettNPREffect_VSNPREffectBnInstMC.inc" + +#include "XboxGamingScarlettNPREffect_VSNPREffectVcBnMC.inc" +#include "XboxGamingScarlettNPREffect_VSNPREffectVcBnInstMC.inc" + +#include "XboxGamingScarlettNPREffect_VSNPREffectTxMC.inc" +#include "XboxGamingScarlettNPREffect_VSNPREffectInstTxMC.inc" + +#include "XboxGamingScarlettNPREffect_VSNPREffectVcTxMC.inc" +#include "XboxGamingScarlettNPREffect_VSNPREffectVcInstTxMC.inc" + +#include "XboxGamingScarlettNPREffect_VSNPREffectBnTxMC.inc" +#include "XboxGamingScarlettNPREffect_VSNPREffectBnInstTxMC.inc" + +#include "XboxGamingScarlettNPREffect_VSNPREffectVcBnTxMC.inc" +#include "XboxGamingScarlettNPREffect_VSNPREffectVcBnInstTxMC.inc" + +#include "XboxGamingScarlettNPREffect_PSMatCapShading.inc" +#include "XboxGamingScarlettNPREffect_PSMatCapShadingTx.inc" +#elif defined(_GAMING_XBOX) +#include "XboxGamingXboxOneNPREffect_VSNPREffect.inc" +#include "XboxGamingXboxOneNPREffect_VSNPREffectInst.inc" + +#include "XboxGamingXboxOneNPREffect_VSNPREffectVc.inc" +#include "XboxGamingXboxOneNPREffect_VSNPREffectVcInst.inc" + +#include "XboxGamingXboxOneNPREffect_VSNPREffectBn.inc" +#include "XboxGamingXboxOneNPREffect_VSNPREffectBnInst.inc" + +#include "XboxGamingXboxOneNPREffect_VSNPREffectVcBn.inc" +#include "XboxGamingXboxOneNPREffect_VSNPREffectVcBnInst.inc" + +#include "XboxGamingXboxOneNPREffect_VSNPREffectTx.inc" +#include "XboxGamingXboxOneNPREffect_VSNPREffectInstTx.inc" + +#include "XboxGamingXboxOneNPREffect_VSNPREffectVcTx.inc" +#include "XboxGamingXboxOneNPREffect_VSNPREffectVcInstTx.inc" + +#include "XboxGamingXboxOneNPREffect_VSNPREffectBnTx.inc" +#include "XboxGamingXboxOneNPREffect_VSNPREffectBnInstTx.inc" + +#include "XboxGamingXboxOneNPREffect_VSNPREffectVcBnTx.inc" +#include "XboxGamingXboxOneNPREffect_VSNPREffectVcBnInstTx.inc" + +#include "XboxGamingXboxOneNPREffect_PSCelShading.inc" +#include "XboxGamingXboxOneNPREffect_PSCelShadingTx.inc" + +#include "XboxGamingXboxOneNPREffect_PSGoochShading.inc" +#include "XboxGamingXboxOneNPREffect_PSGoochShadingTx.inc" + +#include "XboxGamingXboxOneNPREffect_VSNPREffectMC.inc" +#include "XboxGamingXboxOneNPREffect_VSNPREffectInstMC.inc" + +#include "XboxGamingXboxOneNPREffect_VSNPREffectVcMC.inc" +#include "XboxGamingXboxOneNPREffect_VSNPREffectVcInstMC.inc" + +#include "XboxGamingXboxOneNPREffect_VSNPREffectBnMC.inc" +#include "XboxGamingXboxOneNPREffect_VSNPREffectBnInstMC.inc" + +#include "XboxGamingXboxOneNPREffect_VSNPREffectVcBnMC.inc" +#include "XboxGamingXboxOneNPREffect_VSNPREffectVcBnInstMC.inc" + +#include "XboxGamingXboxOneNPREffect_VSNPREffectTxMC.inc" +#include "XboxGamingXboxOneNPREffect_VSNPREffectInstTxMC.inc" + +#include "XboxGamingXboxOneNPREffect_VSNPREffectVcTxMC.inc" +#include "XboxGamingXboxOneNPREffect_VSNPREffectVcInstTxMC.inc" + +#include "XboxGamingXboxOneNPREffect_VSNPREffectBnTxMC.inc" +#include "XboxGamingXboxOneNPREffect_VSNPREffectBnInstTxMC.inc" + +#include "XboxGamingXboxOneNPREffect_VSNPREffectVcBnTxMC.inc" +#include "XboxGamingXboxOneNPREffect_VSNPREffectVcBnInstTxMC.inc" + +#include "XboxGamingXboxOneNPREffect_PSMatCapShading.inc" +#include "XboxGamingXboxOneNPREffect_PSMatCapShadingTx.inc" +#elif defined(_XBOX_ONE) && defined(_TITLE) +#include "XboxOneNPREffect_VSNPREffect.inc" +#include "XboxOneNPREffect_VSNPREffectInst.inc" + +#include "XboxOneNPREffect_VSNPREffectVc.inc" +#include "XboxOneNPREffect_VSNPREffectVcInst.inc" + +#include "XboxOneNPREffect_VSNPREffectBn.inc" +#include "XboxOneNPREffect_VSNPREffectBnInst.inc" + +#include "XboxOneNPREffect_VSNPREffectVcBn.inc" +#include "XboxOneNPREffect_VSNPREffectVcBnInst.inc" + +#include "XboxOneNPREffect_VSNPREffectTx.inc" +#include "XboxOneNPREffect_VSNPREffectInstTx.inc" + +#include "XboxOneNPREffect_VSNPREffectVcTx.inc" +#include "XboxOneNPREffect_VSNPREffectVcInstTx.inc" + +#include "XboxOneNPREffect_VSNPREffectBnTx.inc" +#include "XboxOneNPREffect_VSNPREffectBnInstTx.inc" + +#include "XboxOneNPREffect_VSNPREffectVcBnTx.inc" +#include "XboxOneNPREffect_VSNPREffectVcBnInstTx.inc" + +#include "XboxOneNPREffect_PSCelShading.inc" +#include "XboxOneNPREffect_PSCelShadingTx.inc" + +#include "XboxOneNPREffect_PSGoochShading.inc" +#include "XboxOneNPREffect_PSGoochShadingTx.inc" + +#include "XboxOneNPREffect_VSNPREffectMC.inc" +#include "XboxOneNPREffect_VSNPREffectInstMC.inc" + +#include "XboxOneNPREffect_VSNPREffectVcMC.inc" +#include "XboxOneNPREffect_VSNPREffectVcInstMC.inc" + +#include "XboxOneNPREffect_VSNPREffectBnMC.inc" +#include "XboxOneNPREffect_VSNPREffectBnInstMC.inc" + +#include "XboxOneNPREffect_VSNPREffectVcBnMC.inc" +#include "XboxOneNPREffect_VSNPREffectVcBnInstMC.inc" + +#include "XboxOneNPREffect_VSNPREffectTxMC.inc" +#include "XboxOneNPREffect_VSNPREffectInstTxMC.inc" + +#include "XboxOneNPREffect_VSNPREffectVcTxMC.inc" +#include "XboxOneNPREffect_VSNPREffectVcInstTxMC.inc" + +#include "XboxOneNPREffect_VSNPREffectBnTxMC.inc" +#include "XboxOneNPREffect_VSNPREffectBnInstTxMC.inc" + +#include "XboxOneNPREffect_VSNPREffectVcBnTxMC.inc" +#include "XboxOneNPREffect_VSNPREffectVcBnInstTxMC.inc" + +#include "XboxOneNPREffect_PSMatCapShading.inc" +#include "XboxOneNPREffect_PSMatCapShadingTx.inc" +#else +#include "NPREffect_VSNPREffect.inc" +#include "NPREffect_VSNPREffectInst.inc" + +#include "NPREffect_VSNPREffectVc.inc" +#include "NPREffect_VSNPREffectVcInst.inc" + +#include "NPREffect_VSNPREffectBn.inc" +#include "NPREffect_VSNPREffectBnInst.inc" + +#include "NPREffect_VSNPREffectVcBn.inc" +#include "NPREffect_VSNPREffectVcBnInst.inc" + +#include "NPREffect_VSNPREffectTx.inc" +#include "NPREffect_VSNPREffectInstTx.inc" + +#include "NPREffect_VSNPREffectVcTx.inc" +#include "NPREffect_VSNPREffectVcInstTx.inc" + +#include "NPREffect_VSNPREffectBnTx.inc" +#include "NPREffect_VSNPREffectBnInstTx.inc" + +#include "NPREffect_VSNPREffectVcBnTx.inc" +#include "NPREffect_VSNPREffectVcBnInstTx.inc" + +#include "NPREffect_PSCelShading.inc" +#include "NPREffect_PSCelShadingTx.inc" + +#include "NPREffect_PSGoochShading.inc" +#include "NPREffect_PSGoochShadingTx.inc" + +#include "NPREffect_VSNPREffectMC.inc" +#include "NPREffect_VSNPREffectInstMC.inc" + +#include "NPREffect_VSNPREffectVcMC.inc" +#include "NPREffect_VSNPREffectVcInstMC.inc" + +#include "NPREffect_VSNPREffectBnMC.inc" +#include "NPREffect_VSNPREffectBnInstMC.inc" + +#include "NPREffect_VSNPREffectVcBnMC.inc" +#include "NPREffect_VSNPREffectVcBnInstMC.inc" + +#include "NPREffect_VSNPREffectTxMC.inc" +#include "NPREffect_VSNPREffectInstTxMC.inc" + +#include "NPREffect_VSNPREffectVcTxMC.inc" +#include "NPREffect_VSNPREffectVcInstTxMC.inc" + +#include "NPREffect_VSNPREffectBnTxMC.inc" +#include "NPREffect_VSNPREffectBnInstTxMC.inc" + +#include "NPREffect_VSNPREffectVcBnTxMC.inc" +#include "NPREffect_VSNPREffectVcBnInstTxMC.inc" + +#include "NPREffect_PSMatCapShading.inc" +#include "NPREffect_PSMatCapShadingTx.inc" +#endif +} + + +template<> +const D3D12_SHADER_BYTECODE EffectBase::VertexShaderBytecode[] = +{ + { NPREffect_VSNPREffect, sizeof(NPREffect_VSNPREffect) }, + { NPREffect_VSNPREffectVc, sizeof(NPREffect_VSNPREffectVc) }, + { NPREffect_VSNPREffectBn, sizeof(NPREffect_VSNPREffectBn) }, + { NPREffect_VSNPREffectVcBn, sizeof(NPREffect_VSNPREffectVcBn) }, + { NPREffect_VSNPREffectInst, sizeof(NPREffect_VSNPREffectInst) }, + { NPREffect_VSNPREffectVcInst, sizeof(NPREffect_VSNPREffectVcInst) }, + { NPREffect_VSNPREffectBnInst, sizeof(NPREffect_VSNPREffectBnInst) }, + { NPREffect_VSNPREffectVcBnInst, sizeof(NPREffect_VSNPREffectVcBnInst) }, + { NPREffect_VSNPREffectTx, sizeof(NPREffect_VSNPREffectTx) }, + { NPREffect_VSNPREffectVcTx, sizeof(NPREffect_VSNPREffectVcTx) }, + { NPREffect_VSNPREffectBnTx, sizeof(NPREffect_VSNPREffectBnTx) }, + { NPREffect_VSNPREffectVcBnTx, sizeof(NPREffect_VSNPREffectVcBnTx) }, + { NPREffect_VSNPREffectInstTx, sizeof(NPREffect_VSNPREffectInstTx) }, + { NPREffect_VSNPREffectVcInstTx, sizeof(NPREffect_VSNPREffectVcInstTx) }, + { NPREffect_VSNPREffectBnInstTx, sizeof(NPREffect_VSNPREffectBnInstTx) }, + { NPREffect_VSNPREffectVcBnInstTx, sizeof(NPREffect_VSNPREffectVcBnInstTx) }, + { NPREffect_VSNPREffectMC, sizeof(NPREffect_VSNPREffectMC) }, // Different rootsig + { NPREffect_VSNPREffectVcMC, sizeof(NPREffect_VSNPREffectVcMC) }, + { NPREffect_VSNPREffectBnMC, sizeof(NPREffect_VSNPREffectBnMC) }, + { NPREffect_VSNPREffectVcBnMC, sizeof(NPREffect_VSNPREffectVcBnMC) }, + { NPREffect_VSNPREffectInstMC, sizeof(NPREffect_VSNPREffectInstMC) }, + { NPREffect_VSNPREffectVcInstMC, sizeof(NPREffect_VSNPREffectVcInstMC) }, + { NPREffect_VSNPREffectBnInstMC, sizeof(NPREffect_VSNPREffectBnInstMC) }, + { NPREffect_VSNPREffectVcBnInstMC, sizeof(NPREffect_VSNPREffectVcBnInstMC) }, + { NPREffect_VSNPREffectTxMC, sizeof(NPREffect_VSNPREffectTxMC) }, + { NPREffect_VSNPREffectVcTxMC, sizeof(NPREffect_VSNPREffectVcTxMC) }, + { NPREffect_VSNPREffectBnTxMC, sizeof(NPREffect_VSNPREffectBnTxMC) }, + { NPREffect_VSNPREffectVcBnTxMC, sizeof(NPREffect_VSNPREffectVcBnTxMC) }, + { NPREffect_VSNPREffectInstTxMC, sizeof(NPREffect_VSNPREffectInstTxMC) }, + { NPREffect_VSNPREffectVcInstTxMC, sizeof(NPREffect_VSNPREffectVcInstTxMC) }, + { NPREffect_VSNPREffectBnInstTxMC, sizeof(NPREffect_VSNPREffectBnInstTxMC) }, + { NPREffect_VSNPREffectVcBnInstTxMC, sizeof(NPREffect_VSNPREffectVcBnInstTxMC) }, +}; + + +template<> +const int EffectBase::VertexShaderIndices[] = +{ + 0, // cel shading + 0, // gooch shading + 16, // matcap shading + + 1, // vertex color + cel shading + 1, // vertex color + gooch shading + 17, // vertex color + matcap shading + + 2, // cel shading (biased vertex normal) + 2, // gooch shading (biased vertex normal) + 18, // matcap shading (biased vertex normal) + + 3, // vertex color (biased vertex normal) + cel shading + 3, // vertex color (biased vertex normal) + gooch shading + 19, // vertex color (biased vertex normal) + matcap shading + + 4, // instancing + cel shading + 4, // instancing + gooch shading + 20, // instancing + matcap shading + + 5, // instancing + vertex color + cel shading + 5, // instancing + vertex color + gooch shading + 21, // instancing + vertex color + matcap shading + + 6, // instancing (biased vertex normal) + cel shading + 6, // instancing (biased vertex normal) + gooch shading + 22, // instancing (biased vertex normal) + matcap shading + + 7, // instancing + vertex color (biased vertex normal) + cel shading + 7, // instancing + vertex color (biased vertex normal) + gooch shading + 23, // instancing + vertex color (biased vertex normal) + matcap shading + + 8, // cel shading + texture + 8, // gooch shading + texture + 24, // matcap shading + texture + + 9, // vertex color + cel shading + texture + 9, // vertex color + gooch shading + texture + 25, // vertex color + matcap shading + texture + + 10, // cel shading (biased vertex normal) + texture + 10, // gooch shading (biased vertex normal) + texture + 26, // matcap shading (biased vertex normal) + texture + + 11, // vertex color (biased vertex normal) + cel shading + texture + 11, // vertex color (biased vertex normal) + gooch shading + texture + 27, // vertex color (biased vertex normal) + matcap shading + texture + + 12, // instancing + cel shading + texture + 12, // instancing + gooch shading + texture + 28, // instancing + matcap shading + texture + + 13, // instancing + vertex color + cel shading + texture + 13, // instancing + vertex color + gooch shading + texture + 29, // instancing + vertex color + matcap shading + texture + + 14, // instancing (biased vertex normal) + cel shading + texture + 14, // instancing (biased vertex normal) + gooch shading + texture + 30, // instancing (biased vertex normal) + matcap shading + texture + + 15, // instancing + vertex color (biased vertex normal) + cel shading + texture + 15, // instancing + vertex color (biased vertex normal) + gooch shading + texture + 31, // instancing + vertex color (biased vertex normal) + matcap shading + texture +}; + + +template<> +const D3D12_SHADER_BYTECODE EffectBase::PixelShaderBytecode[] = +{ + { NPREffect_PSCelShading, sizeof(NPREffect_PSCelShading) }, + { NPREffect_PSGoochShading, sizeof(NPREffect_PSGoochShading) }, + { NPREffect_PSMatCapShading, sizeof(NPREffect_PSMatCapShading) }, + { NPREffect_PSCelShadingTx, sizeof(NPREffect_PSCelShadingTx) }, + { NPREffect_PSGoochShadingTx, sizeof(NPREffect_PSGoochShadingTx) }, + { NPREffect_PSMatCapShadingTx, sizeof(NPREffect_PSMatCapShadingTx) }, +}; + + +template<> +const int EffectBase::PixelShaderIndices[] = +{ + 0, // cel shading + 1, // gooch shading + 2, // matcap shading + + 0, // vertex color + cel shading + 1, // vertex color + gooch shading + 2, // vertex color + matcap shading + + 0, // cel shading (biased vertex normal) + 1, // gooch shading (biased vertex normal) + 2, // matcap shading (biased vertex normal) + + 0, // vertex color (biased vertex normal) + cel shading + 1, // vertex color (biased vertex normal) + gooch shading + 2, // vertex color (biased vertex normal) + matcap shading + + 0, // instancing + cel shading + 1, // instancing + gooch shading + 2, // instancing + matcap shading + + 0, // instancing + vertex color + cel shading + 1, // instancing + vertex color + gooch shading + 2, // instancing + vertex color + matcap shading + + 0, // instancing (biased vertex normal) + cel shading + 1, // instancing (biased vertex normal) + gooch shading + 2, // instancing (biased vertex normal) + matcap shading + + 0, // instancing + vertex color (biased vertex normal) + cel shading + 1, // instancing + vertex color (biased vertex normal) + gooch shading + 2, // instancing + vertex color (biased vertex normal) + matcap shading + + 3, // cel shading + texture + 4, // gooch shading + texture + 5, // matcap shading + texture + + 3, // vertex color + cel shading + texture + 4, // vertex color + gooch shading + texture + 5, // vertex color + matcap shading + texture + + 3, // cel shading (biased vertex normal) + texture + 4, // gooch shading (biased vertex normal) + texture + 5, // matcap shading (biased vertex normal) + texture + + 3, // vertex color (biased vertex normal) + cel shading + texture + 4, // vertex color (biased vertex normal) + gooch shading + texture + 5, // vertex color (biased vertex normal) + matcap shading + texture + + 3, // instancing + cel shading + texture + 4, // instancing + gooch shading + texture + 5, // instancing + matcap shading + texture + + 3, // instancing + vertex color + cel shading + texture + 4, // instancing + vertex color + gooch shading + texture + 5, // instancing + vertex color + matcap shading + texture + + 3, // instancing (biased vertex normal) + cel shading + texture + 4, // instancing (biased vertex normal) + gooch shading + texture + 5, // instancing (biased vertex normal) + matcap shading + texture + + 3, // instancing + vertex color (biased vertex normal) + cel shading + texture + 4, // instancing + vertex color (biased vertex normal) + gooch shading + texture + 5, // instancing + vertex color (biased vertex normal) + matcap shading + texture +}; +#pragma endregion + +// Global pool of per-device NPREffect resources. +template<> +SharedResourcePool::DeviceResources> EffectBase::deviceResourcesPool = {}; + + +// Constructor. +NPREffect::Impl::Impl( + _In_ ID3D12Device* device, + uint32_t effectFlags, + const EffectPipelineStateDescription& pipelineDescription, + NPREffect::Mode nprMode) + : EffectBase(device), + texture{}, + sampler{}, + matcap{} +{ + static_assert(static_cast(std::size(EffectBase::VertexShaderIndices)) == NPREffectTraits::ShaderPermutationCount, "array/max mismatch"); + static_assert(static_cast(std::size(EffectBase::VertexShaderBytecode)) == NPREffectTraits::VertexShaderCount, "array/max mismatch"); + static_assert(static_cast(std::size(EffectBase::PixelShaderBytecode)) == NPREffectTraits::PixelShaderCount, "array/max mismatch"); + static_assert(static_cast(std::size(EffectBase::PixelShaderIndices)) == NPREffectTraits::ShaderPermutationCount, "array/max mismatch"); + + constants.lightDirectionAndCelBands = s_defaultLightDir; + constants.diffuseColorAndAlpha = s_defaultDiffuse; + constants.specularColorAndSpecularThreshold = s_defaultSpecular; + constants.rimColorAndPower = s_defaultRim; + constants.extraSettings = s_defaultExtraSettings; + constants.goochCoolColorAndAlpha = s_defaultCool; + constants.goochWarmColorAndBeta = s_defaultWarm; + constants.eyePosition = g_XMZero; + + switch (nprMode) + { + case Mode_Cel: + case Mode_Gooch: + matCapEnabled = false; + break; + + case Mode_MatCap: + matCapEnabled = true; + break; + + default: + throw std::invalid_argument("Invalid nprMode"); + } + + textureEnabled = (effectFlags & EffectFlags::Texture) != 0; + + // Create root signature. + { + ENUM_FLAGS_CONSTEXPR D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags = + D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT + | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS + | D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS + | D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS + #ifdef _GAMING_XBOX_SCARLETT + | D3D12_ROOT_SIGNATURE_FLAG_DENY_AMPLIFICATION_SHADER_ROOT_ACCESS + | D3D12_ROOT_SIGNATURE_FLAG_DENY_MESH_SHADER_ROOT_ACCESS + #endif + ; + + // Create root parameters and initialize first (constants) + CD3DX12_ROOT_PARAMETER rootParameters[RootParameterIndex::RootParameterCount] = {}; + rootParameters[RootParameterIndex::ConstantBuffer].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_ALL); + + // Root parameter descriptor - conditionally initialized + CD3DX12_ROOT_SIGNATURE_DESC rsigDesc = {}; + + if (textureEnabled && matCapEnabled) + { + // Include two textures and one sampler + const CD3DX12_DESCRIPTOR_RANGE textureSRV(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0); + const CD3DX12_DESCRIPTOR_RANGE textureSampler(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0); + + rootParameters[RootParameterIndex::TextureSRV].InitAsDescriptorTable(1, &textureSRV, D3D12_SHADER_VISIBILITY_PIXEL); + rootParameters[RootParameterIndex::TextureSampler].InitAsDescriptorTable(1, &textureSampler, D3D12_SHADER_VISIBILITY_PIXEL); + + const CD3DX12_DESCRIPTOR_RANGE texture2Range(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 1); + rootParameters[RootParameterIndex::Texture2SRV].InitAsDescriptorTable(1, &texture2Range, D3D12_SHADER_VISIBILITY_PIXEL); + + // use all parameters + rsigDesc.Init(static_cast(std::size(rootParameters)), rootParameters, 0, nullptr, rootSignatureFlags); + + mRootSignature = GetRootSignature(2, rsigDesc); + } + else if (textureEnabled || matCapEnabled) + { + // Include texture and sampler + const CD3DX12_DESCRIPTOR_RANGE textureSRV(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0); + const CD3DX12_DESCRIPTOR_RANGE textureSampler(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0); + + rootParameters[RootParameterIndex::TextureSRV].InitAsDescriptorTable(1, &textureSRV, D3D12_SHADER_VISIBILITY_PIXEL); + rootParameters[RootParameterIndex::TextureSampler].InitAsDescriptorTable(1, &textureSampler, D3D12_SHADER_VISIBILITY_PIXEL); + + // use all but last parameter + rsigDesc.Init(static_cast(std::size(rootParameters) - 1), rootParameters, 0, nullptr, rootSignatureFlags); + + mRootSignature = GetRootSignature(1, rsigDesc); + } + else + { + // only use constant + rsigDesc.Init(1, rootParameters, 0, nullptr, rootSignatureFlags); + + mRootSignature = GetRootSignature(0, rsigDesc); + } + } + + assert(mRootSignature != nullptr); + + // Create pipeline state. + const int sp = GetPipelineStatePermutation(nprMode, effectFlags); + assert(sp >= 0 && sp < NPREffectTraits::ShaderPermutationCount); + _Analysis_assume_(sp >= 0 && sp < NPREffectTraits::ShaderPermutationCount); + + const int vi = EffectBase::VertexShaderIndices[sp]; + assert(vi >= 0 && vi < NPREffectTraits::VertexShaderCount); + _Analysis_assume_(vi >= 0 && vi < NPREffectTraits::VertexShaderCount); + const int pi = EffectBase::PixelShaderIndices[sp]; + assert(pi >= 0 && pi < NPREffectTraits::PixelShaderCount); + _Analysis_assume_(pi >= 0 && pi < NPREffectTraits::PixelShaderCount); + + pipelineDescription.CreatePipelineState( + device, + mRootSignature, + EffectBase::VertexShaderBytecode[vi], + EffectBase::PixelShaderBytecode[pi], + mPipelineState.GetAddressOf()); + + SetDebugObjectName(mPipelineState.Get(), L"NPREffect"); +} + + +int NPREffect::Impl::GetPipelineStatePermutation(NPREffect::Mode nprMode, uint32_t effectFlags) const noexcept +{ + int permutation = static_cast(nprMode); + + // Support vertex coloring? + if (effectFlags & EffectFlags::VertexColor) + { + permutation += 3; + } + + if (effectFlags & EffectFlags::BiasedVertexNormals) + { + // Compressed normals need to be scaled and biased in the vertex shader. + permutation += 6; + } + + if (effectFlags & EffectFlags::Instancing) + { + // Vertex shader needs to use vertex matrix transform. + permutation += 12; + } + + // Use shaders without texture coordinates? + if (textureEnabled) + { + permutation += 24; + } + + return permutation; +} + + +// Sets our state onto the D3D device. +void NPREffect::Impl::Apply(_In_ ID3D12GraphicsCommandList* commandList) +{ + // Compute derived parameter values. + matrices.SetConstants( + dirtyFlags, + constants.world, + constants.worldInverseTranspose, + constants.worldViewProj, + constants.eyePosition); + + UpdateConstants(); + + // Set the root signature + commandList->SetGraphicsRootSignature(mRootSignature); + + // Set the texture + if (textureEnabled) + { + if (!texture.ptr || !sampler.ptr) + { + DebugTrace("ERROR: Missing texture or sampler for NPREffect (texture %llu, sampler %llu)\n", + texture.ptr, sampler.ptr); + throw std::runtime_error("NPREffect"); + } + + // **NOTE** If D3D asserts or crashes here, you probably need to call commandList->SetDescriptorHeaps() + // with the required descriptor heaps. + commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSRV, texture); + commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSampler, sampler); + } + + if (matCapEnabled) + { + if (!matcap.ptr || !sampler.ptr) + { + DebugTrace("ERROR: Missing matcap texture or sampler for NPREffect (texture %llu, sampler %llu)\n", + matcap.ptr, sampler.ptr); + throw std::runtime_error("NPREffect"); + } + + // **NOTE** If D3D asserts or crashes here, you probably need to call commandList->SetDescriptorHeaps() + // with the required descriptor heaps. + commandList->SetGraphicsRootDescriptorTable( + textureEnabled ? RootParameterIndex::Texture2SRV : RootParameterIndex::TextureSRV, + matcap); + commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSampler, sampler); + } + + // Set constants + commandList->SetGraphicsRootConstantBufferView(RootParameterIndex::ConstantBuffer, GetConstantBufferGpuAddress()); + + // Set the pipeline state + commandList->SetPipelineState(EffectBase::mPipelineState.Get()); +} + + +// Public constructor. +NPREffect::NPREffect( + _In_ ID3D12Device* device, + uint32_t effectFlags, + const EffectPipelineStateDescription& pipelineDescription, + Mode nprMode) + : pImpl(std::make_unique(device, effectFlags, pipelineDescription, nprMode)) +{} + + +NPREffect::NPREffect(NPREffect&&) noexcept = default; +NPREffect& NPREffect::operator= (NPREffect&&) noexcept = default; +NPREffect::~NPREffect() = default; + + +// IEffect methods. +void NPREffect::Apply(_In_ ID3D12GraphicsCommandList* commandList) +{ + pImpl->Apply(commandList); +} + + +// Camera settings. +void NPREffect::SetWorld(FXMMATRIX value) +{ + pImpl->matrices.world = value; + + pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose; +} + + +void NPREffect::SetView(FXMMATRIX value) +{ + pImpl->matrices.view = value; + + pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::EyePosition; +} + + +void NPREffect::SetProjection(FXMMATRIX value) +{ + pImpl->matrices.projection = value; + + pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj; +} + + +void NPREffect::SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection) +{ + pImpl->matrices.world = world; + pImpl->matrices.view = view; + pImpl->matrices.projection = projection; + + pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose | EffectDirtyFlags::EyePosition; +} + + +// Light settings. +void NPREffect::SetAmbientLightColor(FXMVECTOR) +{ + // Unsupported interface. +} + + +void NPREffect::SetLightEnabled(int, bool) +{ + // Unsupported interface. +} + + +void NPREffect::SetLightDirection(int whichLight, FXMVECTOR value) +{ + if (whichLight != 0) + { + // Only support one light + return; + } + + // Set xyz to new value, but preserve existing w (cel bands). + pImpl->constants.lightDirectionAndCelBands = XMVectorSelect(pImpl->constants.lightDirectionAndCelBands, value, g_XMSelect1110); + + pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer; +} + + +void NPREffect::SetLightDiffuseColor(int, FXMVECTOR) +{ + // Unsupported interface. +} + + +void NPREffect::SetLightSpecularColor(int, FXMVECTOR) +{ + // Unsupported interface. +} + + +void NPREffect::EnableDefaultLighting() +{ + // Set xyz to new value, but preserve existing w (cel bands). + pImpl->constants.lightDirectionAndCelBands = XMVectorSelect(pImpl->constants.lightDirectionAndCelBands, s_defaultLightDir, g_XMSelect1110); + + pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer; +} + + +// Material settings. +void NPREffect::SetDiffuseColor(FXMVECTOR value) +{ + // Set xyz, preserve w (alpha). + pImpl->constants.diffuseColorAndAlpha = XMVectorSelect(pImpl->constants.diffuseColorAndAlpha, value, g_XMSelect1110); + + pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer; +} + + +void NPREffect::SetSpecularColor(FXMVECTOR value) +{ + // Set xyz, preserve w (specular threshold). + pImpl->constants.specularColorAndSpecularThreshold = XMVectorSelect(pImpl->constants.specularColorAndSpecularThreshold, value, g_XMSelect1110); + + pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer; +} + + +void NPREffect::SetSpecularThreshold(float threshold, float smoothing) +{ + if (threshold < 0.f || threshold > 1.f) + { + throw std::invalid_argument("Specular threshold must be between 0 and 1"); + } + + if (smoothing < 0.f || smoothing > 1.f) + { + throw std::invalid_argument("Specular smoothing must be between 0 and 1"); + } + + // Set w of specularColorAndSpecularThreshold. + pImpl->constants.specularColorAndSpecularThreshold = XMVectorSetW(pImpl->constants.specularColorAndSpecularThreshold, threshold); + + // Set x of extraSettings. + pImpl->constants.extraSettings = XMVectorSetX(pImpl->constants.extraSettings, smoothing); + + pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer; +} + + +void NPREffect::DisableSpecular() +{ + // Set specular color to black, threshold to 1 + pImpl->constants.specularColorAndSpecularThreshold = g_XMIdentityR3; + + pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer; +} + + +void NPREffect::SetAlpha(float value) +{ + // Set w of diffuseColorAndAlpha. + pImpl->constants.diffuseColorAndAlpha = XMVectorSetW(pImpl->constants.diffuseColorAndAlpha, value); + + pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer; +} + + +void NPREffect::SetColorAndAlpha(FXMVECTOR value) +{ + pImpl->constants.diffuseColorAndAlpha = value; + + pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer; +} + + +// Texture setting. +void NPREffect::SetTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor) +{ + pImpl->texture = srvDescriptor; + pImpl->sampler = samplerDescriptor; +} + + +// Cel shading setting. +void NPREffect::SetCelShaderBands(int bands) +{ + if (bands < 1) + { + throw std::invalid_argument("Cel shading bands must be greater than 0"); + } + + // Set w of lightDirectionAndCelBands. + pImpl->constants.lightDirectionAndCelBands = XMVectorSetW(pImpl->constants.lightDirectionAndCelBands, static_cast(bands)); + + pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer; +} + + +// Gooch shading settings. +void NPREffect::SetGoochCoolColor(FXMVECTOR value, float alpha) +{ + pImpl->constants.goochCoolColorAndAlpha = XMVectorSetW(value, alpha); + + pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer; +} + + +void NPREffect::SetGoochWarmColor(FXMVECTOR value, float beta) +{ + pImpl->constants.goochWarmColorAndBeta = XMVectorSetW(value, beta); + + pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer; +} + + +// MatCap shading setting. +void NPREffect::SetMatCap(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor) +{ + pImpl->matcap = srvDescriptor; +} + + +void NPREffect::SetMatCap(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor, D3D12_GPU_DESCRIPTOR_HANDLE samplerDescriptor) +{ + pImpl->matcap = srvDescriptor; + pImpl->sampler = samplerDescriptor; +} + + +// Rim lighting settings. +void NPREffect::SetRimLightingColor(FXMVECTOR value) +{ + // Set xyz, preserve w (rim power). + pImpl->constants.rimColorAndPower = XMVectorSelect(pImpl->constants.rimColorAndPower, value, g_XMSelect1110); + + pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer; +} + + +void NPREffect::SetRimLightingPower(float power) +{ + // Set w of rimColorAndPower. + pImpl->constants.rimColorAndPower = XMVectorSetW(pImpl->constants.rimColorAndPower, power); + + pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer; +} + + +void NPREffect::SetRimLightingIntensity(float strength) +{ + if (strength < 0.f || strength > 1.f) + { + throw std::invalid_argument("Rim lighting strength must be between 0 and 1"); + } + + // Set y of extraSettings. + pImpl->constants.extraSettings = XMVectorSetY(pImpl->constants.extraSettings, strength); + + pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer; +} + + +void NPREffect::SetRimLightingRange(float start, float end) +{ + if (start < 0.f || end > 1.f || start > end) + { + throw std::invalid_argument("Rim lighting start/end must be between 0 and 1"); + } + + // Set zw of extraSettings. + XMVECTORF32 range = { { { 0.f, 0.f, start, end } } }; + pImpl->constants.extraSettings = XMVectorSelect(range, pImpl->constants.extraSettings, g_XMSelect1100); + + pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer; +} + + +void NPREffect::DisableRimLighting() +{ + pImpl->constants.rimColorAndPower = g_XMIdentityR3; + + pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer; +} diff --git a/Src/PBREffect.cpp b/Src/PBREffect.cpp index dcbe1be0..59b98f7a 100644 --- a/Src/PBREffect.cpp +++ b/Src/PBREffect.cpp @@ -521,33 +521,12 @@ void PBREffect::Impl::Apply(_In_ ID3D12GraphicsCommandList* commandList) constants.prevWorldViewProj = constants.worldViewProj; // Compute derived parameter values. - matrices.SetConstants(dirtyFlags, constants.worldViewProj); - - // World inverse transpose matrix. - if (dirtyFlags & EffectDirtyFlags::WorldInverseTranspose) - { - constants.world = XMMatrixTranspose(matrices.world); - - const XMMATRIX worldInverse = XMMatrixInverse(nullptr, matrices.world); - - constants.worldInverseTranspose[0] = worldInverse.r[0]; - constants.worldInverseTranspose[1] = worldInverse.r[1]; - constants.worldInverseTranspose[2] = worldInverse.r[2]; - - dirtyFlags &= ~EffectDirtyFlags::WorldInverseTranspose; - dirtyFlags |= EffectDirtyFlags::ConstantBuffer; - } - - // Eye position vector. - if (dirtyFlags & EffectDirtyFlags::EyePosition) - { - const XMMATRIX viewInverse = XMMatrixInverse(nullptr, matrices.view); - - constants.eyePosition = viewInverse.r[3]; - - dirtyFlags &= ~EffectDirtyFlags::EyePosition; - dirtyFlags |= EffectDirtyFlags::ConstantBuffer; - } + matrices.SetConstants( + dirtyFlags, + constants.world, + constants.worldInverseTranspose, + constants.worldViewProj, + constants.eyePosition); // Set constants to GPU UpdateConstants(); @@ -874,6 +853,7 @@ void PBREffect::SetRenderTargetSizeInPixels(int width, int height) SkinnedPBREffect::~SkinnedPBREffect() {} + // Animation settings. void SkinnedPBREffect::SetBoneTransforms(_In_reads_(count) XMMATRIX const* value, size_t count) { diff --git a/Src/Shaders/CompileShaders.cmd b/Src/Shaders/CompileShaders.cmd index f1f2317a..3a817f0b 100644 --- a/Src/Shaders/CompileShaders.cmd +++ b/Src/Shaders/CompileShaders.cmd @@ -258,6 +258,55 @@ call :CompileShader%1 DebugEffect ps PSRGBNormals call :CompileShader%1 DebugEffect ps PSRGBTangents call :CompileShader%1 DebugEffect ps PSRGBBiTangents +call :CompileShader%1 NPREffect vs VSNPREffect +call :CompileShader%1 NPREffect vs VSNPREffectBn +call :CompileShader%1 NPREffect vs VSNPREffectVc +call :CompileShader%1 NPREffect vs VSNPREffectVcBn + +call :CompileShader%1 NPREffect vs VSNPREffectInst +call :CompileShader%1 NPREffect vs VSNPREffectBnInst +call :CompileShader%1 NPREffect vs VSNPREffectVcInst +call :CompileShader%1 NPREffect vs VSNPREffectVcBnInst + +call :CompileShader%1 NPREffect vs VSNPREffectTx +call :CompileShader%1 NPREffect vs VSNPREffectBnTx +call :CompileShader%1 NPREffect vs VSNPREffectVcTx +call :CompileShader%1 NPREffect vs VSNPREffectVcBnTx + +call :CompileShader%1 NPREffect vs VSNPREffectInstTx +call :CompileShader%1 NPREffect vs VSNPREffectBnInstTx +call :CompileShader%1 NPREffect vs VSNPREffectVcInstTx +call :CompileShader%1 NPREffect vs VSNPREffectVcBnInstTx + +call :CompileShader%1 NPREffect vs VSNPREffectMC +call :CompileShader%1 NPREffect vs VSNPREffectBnMC +call :CompileShader%1 NPREffect vs VSNPREffectVcMC +call :CompileShader%1 NPREffect vs VSNPREffectVcBnMC + +call :CompileShader%1 NPREffect vs VSNPREffectInstMC +call :CompileShader%1 NPREffect vs VSNPREffectBnInstMC +call :CompileShader%1 NPREffect vs VSNPREffectVcInstMC +call :CompileShader%1 NPREffect vs VSNPREffectVcBnInstMC + +call :CompileShader%1 NPREffect vs VSNPREffectTxMC +call :CompileShader%1 NPREffect vs VSNPREffectBnTxMC +call :CompileShader%1 NPREffect vs VSNPREffectVcTxMC +call :CompileShader%1 NPREffect vs VSNPREffectVcBnTxMC + +call :CompileShader%1 NPREffect vs VSNPREffectInstTxMC +call :CompileShader%1 NPREffect vs VSNPREffectBnInstTxMC +call :CompileShader%1 NPREffect vs VSNPREffectVcInstTxMC +call :CompileShader%1 NPREffect vs VSNPREffectVcBnInstTxMC + +call :CompileShader%1 NPREffect ps PSCelShading +call :CompileShader%1 NPREffect ps PSCelShadingTx + +call :CompileShader%1 NPREffect ps PSGoochShading +call :CompileShader%1 NPREffect ps PSGoochShadingTx + +call :CompileShader%1 NPREffect ps PSMatCapShading +call :CompileShader%1 NPREffect ps PSMatCapShadingTx + call :CompileShader%1 SpriteEffect vs SpriteVertexShader call :CompileShader%1 SpriteEffect ps SpritePixelShader diff --git a/Src/Shaders/NPREffect.fx b/Src/Shaders/NPREffect.fx new file mode 100644 index 00000000..b33d495c --- /dev/null +++ b/Src/Shaders/NPREffect.fx @@ -0,0 +1,544 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// +// https://go.microsoft.com/fwlink/?LinkID=615561 + + +Texture2D Texture : register(t0); +SamplerState Sampler : register(s0); +Texture2D Texture2 : register(t1); + + +cbuffer Parameters : register(b0) +{ + float3 LightDirection : packoffset(c0); + float CelBands : packoffset(c0.w); + + float3 DiffuseColor : packoffset(c1); + float Alpha : packoffset(c1.w); + + float3 SpecularColor : packoffset(c2); + float SpecularThreshold : packoffset(c2.w); + + float3 RimColor : packoffset(c3); + float RimPower : packoffset(c3.w); + + float SpecularSmoothing : packoffset(c4.x); + float RimStrength : packoffset(c4.y); + float RimStart : packoffset(c4.z); + float RimEnd : packoffset(c4.w); + + float3 GoochCoolColor : packoffset(c5); + float GoochAlpha : packoffset(c5.w); + + float3 GoochWarmColor : packoffset(c6); + float GoochBeta : packoffset(c6.w); + + float3 EyePosition : packoffset(c7); + + float4x4 World : packoffset(c8); + float3x3 WorldInverseTranspose : packoffset(c12); + float4x4 WorldViewProj : packoffset(c15); +}; + + +#include "RootSig.fxh" +#include "Structures.fxh" +#include "Utilities.fxh" + +VSOutputPixelLighting ComputeCommonVS(float4 position, float3 normal) +{ + VSOutputPixelLighting vout; + vout.PositionPS = mul(position, WorldViewProj); + vout.PositionWS = float4(mul(position, World).xyz, 1); + vout.NormalWS = normalize(mul(normal, WorldInverseTranspose)); + return vout; +} + +VSOutputPixelLightingTx ComputeCommonVSTx(float4 position, float3 normal, float2 texcoord) +{ + VSOutputPixelLightingTx vout; + vout.TexCoord = texcoord; + vout.PositionPS = mul(position, WorldViewProj); + vout.PositionWS = float4(mul(position, World).xyz, 1); + vout.NormalWS = normalize(mul(normal, WorldInverseTranspose)); + return vout; +} + +// Vertex shader: basic. +[RootSignature(NoTextureRS)] +VSOutputPixelLighting VSNPREffect(VSInputNm vin) +{ + VSOutputPixelLighting vout = ComputeCommonVS(vin.Position, vin.Normal); + vout.Diffuse = float4(DiffuseColor, Alpha); + return vout; +} + +[RootSignature(MainRS)] +VSOutputPixelLighting VSNPREffectMC(VSInputNm vin) +{ + return VSNPREffect(vin); +} + +[RootSignature(NoTextureRS)] +VSOutputPixelLighting VSNPREffectBn(VSInputNm vin) +{ + float3 normal = BiasX2(vin.Normal); + + VSOutputPixelLighting vout = ComputeCommonVS(vin.Position, normal); + vout.Diffuse = float4(DiffuseColor, Alpha); + return vout; +} + +[RootSignature(MainRS)] +VSOutputPixelLighting VSNPREffectBnMC(VSInputNm vin) +{ + return VSNPREffectBn(vin); +} + + +// Vertex shader: vertex color. +[RootSignature(NoTextureRS)] +VSOutputPixelLighting VSNPREffectVc(VSInputNmVc vin) +{ + VSOutputPixelLighting vout = ComputeCommonVS(vin.Position, vin.Normal); + vout.Diffuse.rgb = vin.Color.rgb * DiffuseColor; + vout.Diffuse.a = vin.Color.a * Alpha; + return vout; +} + +[RootSignature(MainRS)] +VSOutputPixelLighting VSNPREffectVcMC(VSInputNmVc vin) +{ + return VSNPREffectVc(vin); +} + +[RootSignature(NoTextureRS)] +VSOutputPixelLighting VSNPREffectVcBn(VSInputNmVc vin) +{ + float3 normal = BiasX2(vin.Normal); + + VSOutputPixelLighting vout = ComputeCommonVS(vin.Position, normal); + vout.Diffuse.rgb = vin.Color.rgb * DiffuseColor; + vout.Diffuse.a = vin.Color.a * Alpha; + return vout; +} + +[RootSignature(MainRS)] +VSOutputPixelLighting VSNPREffectVcBnMC(VSInputNmVc vin) +{ + return VSNPREffectVcBn(vin); + +} + + +// Vertex shader: instancing. +[RootSignature(NoTextureRS)] +VSOutputPixelLighting VSNPREffectInst(VSInputNmInst vin) +{ + CommonInstancing inst = ComputeCommonInstancing(vin.Position, vin.Normal, vin.Transform); + VSOutputPixelLighting vout = ComputeCommonVS(inst.Position, inst.Normal); + vout.Diffuse = float4(DiffuseColor, Alpha); + return vout; +} + +[RootSignature(MainRS)] +VSOutputPixelLighting VSNPREffectInstMC(VSInputNmInst vin) +{ + return VSNPREffectInst(vin); +} + +[RootSignature(NoTextureRS)] +VSOutputPixelLighting VSNPREffectBnInst(VSInputNmInst vin) +{ + float3 normal = BiasX2(vin.Normal); + + CommonInstancing inst = ComputeCommonInstancing(vin.Position, normal, vin.Transform); + VSOutputPixelLighting vout = ComputeCommonVS(inst.Position, inst.Normal); + vout.Diffuse = float4(DiffuseColor, Alpha); + return vout; +} + +[RootSignature(MainRS)] +VSOutputPixelLighting VSNPREffectBnInstMC(VSInputNmInst vin) +{ + return VSNPREffectBnInst(vin); +} + + +// Vertex shader: vertex color + instancing. +[RootSignature(NoTextureRS)] +VSOutputPixelLighting VSNPREffectVcInst(VSInputNmVcInst vin) +{ + CommonInstancing inst = ComputeCommonInstancing(vin.Position, vin.Normal, vin.Transform); + VSOutputPixelLighting vout = ComputeCommonVS(inst.Position, inst.Normal); + vout.Diffuse.rgb = vin.Color.rgb * DiffuseColor; + vout.Diffuse.a = vin.Color.a * Alpha; + return vout; +} + +[RootSignature(MainRS)] +VSOutputPixelLighting VSNPREffectVcInstMC(VSInputNmVcInst vin) +{ + return VSNPREffectVcInst(vin); +} + +[RootSignature(NoTextureRS)] +VSOutputPixelLighting VSNPREffectVcBnInst(VSInputNmVcInst vin) +{ + float3 normal = BiasX2(vin.Normal); + + CommonInstancing inst = ComputeCommonInstancing(vin.Position, normal, vin.Transform); + VSOutputPixelLighting vout = ComputeCommonVS(inst.Position, inst.Normal); + vout.Diffuse.rgb = vin.Color.rgb * DiffuseColor; + vout.Diffuse.a = vin.Color.a * Alpha; + return vout; +} + +[RootSignature(MainRS)] +VSOutputPixelLighting VSNPREffectVcBnInstMC(VSInputNmVcInst vin) +{ + return VSNPREffectVcBnInst(vin); + +} + + +// Vertex shader: texture. +[RootSignature(MainRS)] +VSOutputPixelLightingTx VSNPREffectTx(VSInputNmTx vin) +{ + VSOutputPixelLightingTx vout = ComputeCommonVSTx(vin.Position, vin.Normal, vin.TexCoord); + vout.Diffuse = float4(DiffuseColor, Alpha); + return vout; +} + +[RootSignature(DualTextureOneSamplerRS)] +VSOutputPixelLightingTx VSNPREffectTxMC(VSInputNmTx vin) +{ + return VSNPREffectTx(vin); +} + +[RootSignature(MainRS)] +VSOutputPixelLightingTx VSNPREffectBnTx(VSInputNmTx vin) +{ + float3 normal = BiasX2(vin.Normal); + + VSOutputPixelLightingTx vout = ComputeCommonVSTx(vin.Position, normal, vin.TexCoord); + vout.Diffuse = float4(DiffuseColor, Alpha); + return vout; +} + +[RootSignature(DualTextureOneSamplerRS)] +VSOutputPixelLightingTx VSNPREffectBnTxMC(VSInputNmTx vin) +{ + return VSNPREffectBnTx(vin); + +} + + +// Vertex shader: texture + vertex color. +[RootSignature(MainRS)] +VSOutputPixelLightingTx VSNPREffectVcTx(VSInputNmTxVc vin) +{ + VSOutputPixelLightingTx vout = ComputeCommonVSTx(vin.Position, vin.Normal, vin.TexCoord); + vout.Diffuse.rgb = vin.Color.rgb * DiffuseColor; + vout.Diffuse.a = vin.Color.a * Alpha; + return vout; +} + +[RootSignature(DualTextureOneSamplerRS)] +VSOutputPixelLightingTx VSNPREffectVcTxMC(VSInputNmTxVc vin) +{ + return VSNPREffectVcTx(vin); +} + +[RootSignature(MainRS)] +VSOutputPixelLightingTx VSNPREffectVcBnTx(VSInputNmTxVc vin) +{ + float3 normal = BiasX2(vin.Normal); + + VSOutputPixelLightingTx vout = ComputeCommonVSTx(vin.Position, normal, vin.TexCoord); + vout.Diffuse.rgb = vin.Color.rgb * DiffuseColor; + vout.Diffuse.a = vin.Color.a * Alpha; + return vout; +} + +[RootSignature(DualTextureOneSamplerRS)] +VSOutputPixelLightingTx VSNPREffectVcBnTxMC(VSInputNmTxVc vin) +{ + return VSNPREffectVcBnTx(vin); + +} + + +// Vertex shader: texture + instancing. +[RootSignature(MainRS)] +VSOutputPixelLightingTx VSNPREffectInstTx(VSInputNmTxInst vin) +{ + CommonInstancing inst = ComputeCommonInstancing(vin.Position, vin.Normal, vin.Transform); + VSOutputPixelLightingTx vout = ComputeCommonVSTx(inst.Position, inst.Normal, vin.TexCoord); + vout.Diffuse = float4(DiffuseColor, Alpha); + return vout; +} + +[RootSignature(DualTextureOneSamplerRS)] +VSOutputPixelLightingTx VSNPREffectInstTxMC(VSInputNmTxInst vin) +{ + return VSNPREffectInstTx(vin); +} + +[RootSignature(MainRS)] +VSOutputPixelLightingTx VSNPREffectBnInstTx(VSInputNmTxInst vin) +{ + float3 normal = BiasX2(vin.Normal); + + CommonInstancing inst = ComputeCommonInstancing(vin.Position, normal, vin.Transform); + VSOutputPixelLightingTx vout = ComputeCommonVSTx(inst.Position, inst.Normal, vin.TexCoord); + vout.Diffuse = float4(DiffuseColor, Alpha); + return vout; +} + +[RootSignature(DualTextureOneSamplerRS)] +VSOutputPixelLightingTx VSNPREffectBnInstTxMC(VSInputNmTxInst vin) +{ + return VSNPREffectBnInstTx(vin); + +} + + +// Vertex shader: texture + vertex color + instancing. +[RootSignature(MainRS)] +VSOutputPixelLightingTx VSNPREffectVcInstTx(VSInputNmTxVcInst vin) +{ + CommonInstancing inst = ComputeCommonInstancing(vin.Position, vin.Normal, vin.Transform); + VSOutputPixelLightingTx vout = ComputeCommonVSTx(inst.Position, inst.Normal, vin.TexCoord); + vout.Diffuse.rgb = vin.Color.rgb * DiffuseColor; + vout.Diffuse.a = vin.Color.a * Alpha; + return vout; +} + +[RootSignature(DualTextureOneSamplerRS)] +VSOutputPixelLightingTx VSNPREffectVcInstTxMC(VSInputNmTxVcInst vin) +{ + return VSNPREffectVcInstTx(vin); +} + +[RootSignature(MainRS)] +VSOutputPixelLightingTx VSNPREffectVcBnInstTx(VSInputNmTxVcInst vin) +{ + float3 normal = BiasX2(vin.Normal); + + CommonInstancing inst = ComputeCommonInstancing(vin.Position, normal, vin.Transform); + VSOutputPixelLightingTx vout = ComputeCommonVSTx(inst.Position, inst.Normal, vin.TexCoord); + vout.Diffuse.rgb = vin.Color.rgb * DiffuseColor; + vout.Diffuse.a = vin.Color.a * Alpha; + return vout; +} + +[RootSignature(DualTextureOneSamplerRS)] +VSOutputPixelLightingTx VSNPREffectVcBnInstTxMC(VSInputNmTxVcInst vin) +{ + return VSNPREffectVcBnInstTx(vin); + +} + + +//--- Cel shading --- +float Quantize(float intensity, float bands) +{ + intensity = max(0, intensity); + return floor(intensity * bands) / bands; +} + +float HardEdgeSpecular(float dot1) +{ + return smoothstep(SpecularThreshold - SpecularSmoothing, SpecularThreshold + SpecularSmoothing, dot1); +} + +float RimLighting(float dot1) +{ + float fresnel = pow(1.0 - saturate(dot1), RimPower); + return smoothstep(RimStart, RimEnd, fresnel) * RimStrength; +} + + +// Pixel shader: cel shading. +[RootSignature(NoTextureRS)] +float4 PSCelShading(PSInputPixelLighting pin) : SV_Target0 +{ + float3 normal = normalize(pin.NormalWS); + + float3 lightDir = normalize(-LightDirection); + float NdotL = dot(normal, lightDir); + + float3 viewDir = normalize(EyePosition - pin.PositionWS.xyz); + float NdotV = max(0, dot(normal, viewDir)); + + float3 halfVec = normalize(lightDir + viewDir); + float NdotH = max(0, dot(normal, halfVec)); + + // Quantize the diffuse lighting into discrete bands + float quantized = Quantize(NdotL, CelBands); + float3 color = pin.Diffuse.rgb * quantized; + + // Rim lighting + float outline = RimLighting(NdotV); + color = lerp(color, RimColor, outline); + + // Specular highlight (hard edge) + float specular = HardEdgeSpecular(NdotH); + color += SpecularColor * specular; + + return float4(color, pin.Diffuse.a); +} + + +// Pixel shader: cel shading + texture. +[RootSignature(MainRS)] +float4 PSCelShadingTx(PSInputPixelLightingTx pin) : SV_Target0 +{ + float3 normal = normalize(pin.NormalWS); + + float3 lightDir = normalize(-LightDirection); + float NdotL = dot(normal, lightDir); + + float3 viewDir = normalize(EyePosition - pin.PositionWS.xyz); + float NdotV = max(0, dot(normal, viewDir)); + float VdotL = max(0, dot(viewDir, lightDir)); + + float3 halfVec = normalize(lightDir + viewDir); + float NdotH = max(0, dot(normal, halfVec)); + + // Sample base texture + float4 texColor = Texture.Sample(Sampler, pin.TexCoord); + + // Quantize the diffuse lighting into discrete bands + float quantized = Quantize(NdotL, CelBands); + float3 color = pin.Diffuse.rgb * texColor.rgb * quantized; + + // Rim lighting + float outline = RimLighting(NdotV); + color = lerp(color, RimColor, outline); + + // Specular highlight (hard edge) + float specular = HardEdgeSpecular(NdotH); + color += SpecularColor * specular; + + return float4(color, pin.Diffuse.a * texColor.a); +} + + +//--- Gooch shading --- +float3 GoochShading(float dot1, float3 color) +{ + float t = (1.0 + dot1) * 0.5; + + float3 coolContrib = GoochCoolColor + GoochAlpha * color; + float3 warmContrib = GoochWarmColor + GoochBeta * color; + + return lerp(coolContrib, warmContrib, t); +} + + +// Pixel shader: Gooch shading. +[RootSignature(NoTextureRS)] +float4 PSGoochShading(PSInputPixelLighting pin) : SV_Target0 +{ + float3 normal = normalize(pin.NormalWS); + float3 lightDir = normalize(-LightDirection); + float NdotL = dot(normal, lightDir); + + float3 viewDir = normalize(EyePosition - pin.PositionWS.xyz); + float NdotV = max(0, dot(normal, viewDir)); + + float3 reflectDir = reflect(LightDirection, normal); + float RdotV = max(0, dot(viewDir, reflectDir)); + + // Gooch diffuse term: blend between cool and warm based + float3 color = GoochShading(NdotL, pin.Diffuse.rgb); + + // Rim lighting + float outline = RimLighting(NdotV); + color += lerp(color, RimColor, outline); + + // Specular highlight (hard edge) + float specular = HardEdgeSpecular(RdotV); + color += SpecularColor * specular; + + return float4(color, pin.Diffuse.a); +} + + +// Pixel shader: Gooch shading + texture. +[RootSignature(MainRS)] +float4 PSGoochShadingTx(PSInputPixelLightingTx pin) : SV_Target0 +{ + float3 normal = normalize(pin.NormalWS); + float3 lightDir = normalize(-LightDirection); + float NdotL = dot(normal, lightDir); + + float3 viewDir = normalize(EyePosition - pin.PositionWS.xyz); + float NdotV = max(0, dot(normal, viewDir)); + + float3 reflectDir = reflect(LightDirection, normal); + float RdotV = max(0, dot(viewDir, reflectDir)); + + // Sample base texture + float4 texColor = Texture.Sample(Sampler, pin.TexCoord); + + // Gooch diffuse term: blend between cool and warm based + float3 color = GoochShading(NdotL, pin.Diffuse.rgb * texColor.rgb); + + // Rim lighting + float outline = RimLighting(NdotV); + color += lerp(color, RimColor, outline); + + // Specular highlight + float specular = HardEdgeSpecular(RdotV); + color += SpecularColor * specular; + + return float4(color, pin.Diffuse.a * texColor.a); +} + + +//--- MatCap shading --- + +// Pixel shader: MatCap shading. +[RootSignature(MainRS)] +float4 PSMatCapShading(PSInputPixelLighting pin) : SV_Target0 +{ + float3 normal = normalize(pin.NormalWS); + float3 viewDir = normalize(EyePosition - pin.PositionWS.xyz); + float3 reflectDir = reflect(viewDir, normal); + + float2 uv = reflectDir.xy * 0.5 + 0.5; + + // Sample matcap texture + float4 matcap = Texture.Sample(Sampler, uv); + + float3 color = pin.Diffuse.rgb * matcap.rgb; + + return float4(color, pin.Diffuse.a); +} + + +// Pixel shader: MatCap shading + texture. +[RootSignature(DualTextureOneSamplerRS)] +float4 PSMatCapShadingTx(PSInputPixelLightingTx pin) : SV_Target0 +{ + float3 normal = normalize(pin.NormalWS); + float3 viewDir = normalize(EyePosition - pin.PositionWS.xyz); + float3 reflectDir = reflect(viewDir, normal); + + float2 uv = reflectDir.xy * 0.5 + 0.5; + + // Sample base texture + float4 texColor = Texture.Sample(Sampler, pin.TexCoord); + + // Sample matcap texture + float4 matcap = Texture2.Sample(Sampler, uv); + + float3 color = pin.Diffuse.rgb * texColor.rgb * matcap.rgb; + + return float4(color, pin.Diffuse.a * texColor.a); +} diff --git a/Src/Shaders/RootSig.fxh b/Src/Shaders/RootSig.fxh index 45e3198a..416d2509 100644 --- a/Src/Shaders/RootSig.fxh +++ b/Src/Shaders/RootSig.fxh @@ -202,6 +202,18 @@ " DENY_MESH_SHADER_ROOT_ACCESS )," \ "CBV(b0)" +#define DualTextureOneSamplerRS \ +"RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" \ +" DENY_AMPLIFICATION_SHADER_ROOT_ACCESS |" \ +" DENY_DOMAIN_SHADER_ROOT_ACCESS |" \ +" DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \ +" DENY_HULL_SHADER_ROOT_ACCESS |" \ +" DENY_MESH_SHADER_ROOT_ACCESS )," \ +"CBV(b0),"\ +"DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),"\ +"DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL ),"\ +"DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL )" + #else // !__XBOX_SCARLETT #define NoTextureRS \ @@ -371,4 +383,14 @@ " DENY_HULL_SHADER_ROOT_ACCESS )," \ "CBV(b0)" +#define DualTextureOneSamplerRS \ +"RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" \ +" DENY_DOMAIN_SHADER_ROOT_ACCESS |" \ +" DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \ +" DENY_HULL_SHADER_ROOT_ACCESS )," \ +"CBV(b0),"\ +"DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),"\ +"DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL ),"\ +"DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL )" + #endif diff --git a/Src/Shaders/Structures.fxh b/Src/Shaders/Structures.fxh index 0b49c2c3..cf0cc067 100644 --- a/Src/Shaders/Structures.fxh +++ b/Src/Shaders/Structures.fxh @@ -60,6 +60,21 @@ struct VSInputNmTxVc float4 Color : COLOR; }; +struct VSInputNmInst +{ + float4 Position : SV_Position; + float3 Normal : NORMAL; + float4x3 Transform : InstMatrix; +}; + +struct VSInputNmVcInst +{ + float4 Position : SV_Position; + float3 Normal : NORMAL; + float4 Color : COLOR; + float4x3 Transform : InstMatrix; +}; + struct VSInputNmTxInst { float4 Position : SV_Position;