diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2d783008..8ede1777 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -152,6 +152,7 @@ set(LIBRARY_SOURCES
Src/ModelLoadVBO.cpp
Src/NormalMapEffect.cpp
Src/NPREffect.cpp
+ Src/NPREffectFactory.cpp
Src/PBREffect.cpp
Src/PBREffectFactory.cpp
Src/pch.h
@@ -346,7 +347,7 @@ if(WIN32 AND BUILD_SHARED_LIBS)
elseif(XBOX_CONSOLE_TARGET MATCHES "durango")
target_link_libraries(${PROJECT_NAME} PRIVATE kernelx.lib combase.lib d3d12_x.lib xi.lib)
else()
- target_link_libraries(${PROJECT_NAME} PRIVATE d3d12.lib)
+ target_link_libraries(${PROJECT_NAME} PRIVATE d3d12.lib dxguid.lib)
endif()
if(MINGW AND BUILD_XINPUT)
diff --git a/DirectXTK_Desktop_2022_Win10.vcxproj b/DirectXTK_Desktop_2022_Win10.vcxproj
index 4965e855..9bfaf1ee 100644
--- a/DirectXTK_Desktop_2022_Win10.vcxproj
+++ b/DirectXTK_Desktop_2022_Win10.vcxproj
@@ -112,6 +112,7 @@
+
diff --git a/DirectXTK_Desktop_2022_Win10.vcxproj.filters b/DirectXTK_Desktop_2022_Win10.vcxproj.filters
index 5116af65..706e9879 100644
--- a/DirectXTK_Desktop_2022_Win10.vcxproj.filters
+++ b/DirectXTK_Desktop_2022_Win10.vcxproj.filters
@@ -314,6 +314,9 @@
Src
+
+ Src
+
diff --git a/DirectXTK_Desktop_2026.slnx b/DirectXTK_Desktop_2026.slnx
index 2bd6738b..100c32d9 100644
--- a/DirectXTK_Desktop_2026.slnx
+++ b/DirectXTK_Desktop_2026.slnx
@@ -7,5 +7,5 @@
-
+
diff --git a/DirectXTK_Desktop_2026.vcxproj b/DirectXTK_Desktop_2026.vcxproj
index 5704fd65..f364348a 100644
--- a/DirectXTK_Desktop_2026.vcxproj
+++ b/DirectXTK_Desktop_2026.vcxproj
@@ -112,6 +112,7 @@
+
diff --git a/DirectXTK_Desktop_2026.vcxproj.filters b/DirectXTK_Desktop_2026.vcxproj.filters
index 5116af65..706e9879 100644
--- a/DirectXTK_Desktop_2026.vcxproj.filters
+++ b/DirectXTK_Desktop_2026.vcxproj.filters
@@ -314,6 +314,9 @@
Src
+
+ Src
+
diff --git a/DirectXTK_GDKW_2022.vcxproj b/DirectXTK_GDKW_2022.vcxproj
index d83bf563..84e5c989 100644
--- a/DirectXTK_GDKW_2022.vcxproj
+++ b/DirectXTK_GDKW_2022.vcxproj
@@ -439,6 +439,7 @@
+
diff --git a/DirectXTK_GDKW_2022.vcxproj.filters b/DirectXTK_GDKW_2022.vcxproj.filters
index 8a878fbe..898d5ab1 100644
--- a/DirectXTK_GDKW_2022.vcxproj.filters
+++ b/DirectXTK_GDKW_2022.vcxproj.filters
@@ -308,6 +308,9 @@
Src
+
+ Src
+
diff --git a/DirectXTK_GDKX_2022.vcxproj b/DirectXTK_GDKX_2022.vcxproj
index 60aec220..0427428c 100644
--- a/DirectXTK_GDKX_2022.vcxproj
+++ b/DirectXTK_GDKX_2022.vcxproj
@@ -613,6 +613,7 @@
+
diff --git a/DirectXTK_GDKX_2022.vcxproj.filters b/DirectXTK_GDKX_2022.vcxproj.filters
index efb30072..5c4adab8 100644
--- a/DirectXTK_GDKX_2022.vcxproj.filters
+++ b/DirectXTK_GDKX_2022.vcxproj.filters
@@ -317,6 +317,9 @@
Src
+
+ Src
+
diff --git a/DirectXTK_GDKX_2026.vcxproj b/DirectXTK_GDKX_2026.vcxproj
index 9f85832f..d2b9141e 100644
--- a/DirectXTK_GDKX_2026.vcxproj
+++ b/DirectXTK_GDKX_2026.vcxproj
@@ -613,6 +613,7 @@
+
diff --git a/DirectXTK_GDKX_2026.vcxproj.filters b/DirectXTK_GDKX_2026.vcxproj.filters
index efb30072..5c4adab8 100644
--- a/DirectXTK_GDKX_2026.vcxproj.filters
+++ b/DirectXTK_GDKX_2026.vcxproj.filters
@@ -317,6 +317,9 @@
Src
+
+ Src
+
diff --git a/DirectXTK_GDK_2022.vcxproj b/DirectXTK_GDK_2022.vcxproj
index fdbd09bf..108e995e 100644
--- a/DirectXTK_GDK_2022.vcxproj
+++ b/DirectXTK_GDK_2022.vcxproj
@@ -598,6 +598,7 @@
+
diff --git a/DirectXTK_GDK_2022.vcxproj.filters b/DirectXTK_GDK_2022.vcxproj.filters
index efb30072..5c4adab8 100644
--- a/DirectXTK_GDK_2022.vcxproj.filters
+++ b/DirectXTK_GDK_2022.vcxproj.filters
@@ -317,6 +317,9 @@
Src
+
+ Src
+
diff --git a/DirectXTK_Windows10_2022.vcxproj b/DirectXTK_Windows10_2022.vcxproj
index 6a19fdd2..25a9c240 100644
--- a/DirectXTK_Windows10_2022.vcxproj
+++ b/DirectXTK_Windows10_2022.vcxproj
@@ -125,6 +125,7 @@
+
diff --git a/DirectXTK_Windows10_2022.vcxproj.filters b/DirectXTK_Windows10_2022.vcxproj.filters
index 9f01fe06..c3f8e0c0 100644
--- a/DirectXTK_Windows10_2022.vcxproj.filters
+++ b/DirectXTK_Windows10_2022.vcxproj.filters
@@ -386,5 +386,8 @@
Src
+
+ Src
+
\ No newline at end of file
diff --git a/Inc/Effects.h b/Inc/Effects.h
index 3fd7a300..c769abee 100644
--- a/Inc/Effects.h
+++ b/Inc/Effects.h
@@ -562,7 +562,7 @@ namespace DirectX
DIRECTX_TOOLKIT_API void __cdecl SetSpecularTexture(D3D12_GPU_DESCRIPTOR_HANDLE srvDescriptor);
protected:
- // Private implementation.
+ // internal implementation.
class Impl;
std::unique_ptr pImpl;
@@ -663,7 +663,7 @@ namespace DirectX
DIRECTX_TOOLKIT_API void __cdecl SetRenderTargetSizeInPixels(int width, int height);
protected:
- // Private implementation.
+ // Internal implementation.
class Impl;
std::unique_ptr pImpl;
@@ -674,6 +674,7 @@ namespace DirectX
const EffectPipelineStateDescription& pipelineDescription,
bool skinningEnabled);
+ private:
// Unsupported interface methods.
DIRECTX_TOOLKIT_API void XM_CALLCONV SetAmbientLightColor(FXMVECTOR value) override;
DIRECTX_TOOLKIT_API void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) override;
@@ -763,11 +764,13 @@ namespace DirectX
Mode_MatCap, // Material Capture shading
};
- DIRECTX_TOOLKIT_API NPREffect(
+ DIRECTX_TOOLKIT_API inline NPREffect(
_In_ ID3D12Device* device,
uint32_t effectFlags,
const EffectPipelineStateDescription& pipelineDescription,
- Mode nprMode = Mode_Cel);
+ Mode nprMode = Mode_Cel) :
+ NPREffect(device, effectFlags, pipelineDescription, nprMode, false)
+ {}
DIRECTX_TOOLKIT_API NPREffect(NPREffect&&) noexcept;
DIRECTX_TOOLKIT_API NPREffect& operator= (NPREffect&&) noexcept;
@@ -821,12 +824,20 @@ namespace DirectX
DIRECTX_TOOLKIT_API void __cdecl SetRimLightingRange(float start, float end);
DIRECTX_TOOLKIT_API void __cdecl DisableRimLighting();
- private:
- // Private implementation.
+ protected:
+ // Internal implementation.
class Impl;
std::unique_ptr pImpl;
+ DIRECTX_TOOLKIT_API NPREffect(
+ _In_ ID3D12Device* device,
+ uint32_t effectFlags,
+ const EffectPipelineStateDescription& pipelineDescription,
+ Mode nprMode,
+ bool skinningEnabled);
+
+ private:
// Unsupported interface methods.
DIRECTX_TOOLKIT_API void XM_CALLCONV SetAmbientLightColor(FXMVECTOR value) override;
DIRECTX_TOOLKIT_API void __cdecl SetLightEnabled(int whichLight, bool value) override;
@@ -834,6 +845,33 @@ namespace DirectX
DIRECTX_TOOLKIT_API void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) override;
};
+ class DIRECTX_TOOLKIT_API SkinnedNPREffect : public NPREffect, public IEffectSkinning
+ {
+ public:
+ SkinnedNPREffect(
+ _In_ ID3D12Device* device,
+ uint32_t effectFlags,
+ const EffectPipelineStateDescription& pipelineDescription,
+ Mode nprMode = Mode_Cel) :
+ NPREffect(device, effectFlags, pipelineDescription, nprMode, true)
+ {}
+
+ SkinnedNPREffect(SkinnedNPREffect&&) = default;
+ SkinnedNPREffect& operator= (SkinnedNPREffect&&) = default;
+
+ SkinnedNPREffect(SkinnedNPREffect const&) = delete;
+ SkinnedNPREffect& operator= (SkinnedNPREffect const&) = delete;
+
+ ~SkinnedNPREffect() override;
+
+ // IEffect methods.
+ void __cdecl Apply(_In_ ID3D12GraphicsCommandList* commandList) override;
+
+ // Animation settings.
+ void __cdecl SetBoneTransforms(_In_reads_(count) XMMATRIX const* value, size_t count) override;
+ void __cdecl ResetBoneTransforms() override;
+ };
+
//------------------------------------------------------------------------------
// Abstract interface to factory texture resources
@@ -1017,6 +1055,9 @@ namespace DirectX
DIRECTX_TOOLKIT_API void __cdecl EnableInstancing(bool enabled) noexcept;
+ // Properties.
+ DIRECTX_TOOLKIT_API ID3D12Device* GetDevice() const noexcept;
+
private:
// Private implementation.
class Impl;
@@ -1058,6 +1099,59 @@ namespace DirectX
DIRECTX_TOOLKIT_API void __cdecl EnableInstancing(bool enabled) noexcept;
+ // Properties.
+ DIRECTX_TOOLKIT_API ID3D12Device* GetDevice() const noexcept;
+
+ private:
+ // Private implementation.
+ class Impl;
+
+ std::shared_ptr pImpl;
+ };
+
+
+ // Factory for Non-Photorealistic Rendering (NPR)
+ class NPREffectFactory : public IEffectFactory
+ {
+ public:
+ DIRECTX_TOOLKIT_API NPREffectFactory(_In_ ID3D12Device* device);
+ DIRECTX_TOOLKIT_API NPREffectFactory(
+ _In_ ID3D12DescriptorHeap* textureDescriptors,
+ _In_ ID3D12DescriptorHeap* samplerDescriptors);
+
+ DIRECTX_TOOLKIT_API NPREffectFactory(NPREffectFactory&&) noexcept;
+ DIRECTX_TOOLKIT_API NPREffectFactory& operator= (NPREffectFactory&&) noexcept;
+
+ NPREffectFactory(NPREffectFactory const&) = delete;
+ NPREffectFactory& operator= (NPREffectFactory const&) = delete;
+
+ DIRECTX_TOOLKIT_API ~NPREffectFactory() override;
+
+ // IEffectFactory methods.
+ DIRECTX_TOOLKIT_API virtual std::shared_ptr __cdecl CreateEffect(
+ const EffectInfo& info,
+ const EffectPipelineStateDescription& opaquePipelineState,
+ const EffectPipelineStateDescription& alphaPipelineState,
+ const D3D12_INPUT_LAYOUT_DESC& inputLayout,
+ int textureDescriptorOffset = 0,
+ int samplerDescriptorOffset = 0) override;
+
+ // Settings.
+ DIRECTX_TOOLKIT_API void __cdecl ReleaseCache();
+
+ DIRECTX_TOOLKIT_API void __cdecl SetSharing(bool enabled) noexcept;
+
+ DIRECTX_TOOLKIT_API void __cdecl EnableInstancing(bool enabled) noexcept;
+
+ DIRECTX_TOOLKIT_API void __cdecl SetMode(NPREffect::Mode mode) noexcept;
+
+ DIRECTX_TOOLKIT_API void __cdecl SetDefaultMatCap(int textureIndex, int samplerIndex) noexcept;
+
+ DIRECTX_TOOLKIT_API void __cdecl SetEmissiveAsMatCap(bool value) noexcept;
+
+ // Properties.
+ DIRECTX_TOOLKIT_API ID3D12Device* GetDevice() const noexcept;
+
private:
// Private implementation.
class Impl;
diff --git a/Src/EffectFactory.cpp b/Src/EffectFactory.cpp
index 35f604c7..058e7a28 100644
--- a/Src/EffectFactory.cpp
+++ b/Src/EffectFactory.cpp
@@ -104,9 +104,9 @@ class EffectFactory::Impl
bool mEnableFog;
bool mEnableInstancing;
-private:
ComPtr mDevice;
+private:
using EffectCache = std::map< std::wstring, std::shared_ptr >;
EffectCache mEffectCache;
@@ -595,3 +595,8 @@ void EffectFactory::EnableNormalMapEffect(bool enabled) noexcept
{
pImpl->mUseNormalMapEffect = enabled;
}
+
+ID3D12Device* EffectFactory::GetDevice() const noexcept
+{
+ return pImpl->mDevice.Get();
+}
diff --git a/Src/NPREffect.cpp b/Src/NPREffect.cpp
index 62ac253b..d9525573 100644
--- a/Src/NPREffect.cpp
+++ b/Src/NPREffect.cpp
@@ -10,6 +10,14 @@
#include "pch.h"
#include "EffectCommon.h"
+namespace DirectX
+{
+ namespace EffectDirtyFlags
+ {
+ constexpr int ConstantBufferBones = 0x100000;
+ }
+}
+
using namespace DirectX;
namespace
@@ -32,16 +40,23 @@ namespace
static_assert((sizeof(NPREffectConstants) % 16) == 0, "CB size not padded correctly");
+ XM_ALIGNED_STRUCT(16) BoneConstants
+ {
+ XMVECTOR Bones[SkinnedNPREffect::MaxBones][3];
+ };
+
+ static_assert((sizeof(BoneConstants) % 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;
+ static constexpr int VertexShaderCount = 36;
+ static constexpr int PixelShaderCount = 9;
+ static constexpr int ShaderPermutationCount = 54;
+ static constexpr int RootSignatureCount = 5;
};
@@ -60,8 +75,7 @@ namespace
class NPREffect::Impl : public EffectBase
{
public:
- Impl(_In_ ID3D12Device* device, uint32_t effectFlags, const EffectPipelineStateDescription& pipelineDescription,
- NPREffect::Mode nprMode);
+ Impl(_In_ ID3D12Device* device);
Impl(const Impl&) = delete;
Impl& operator=(const Impl&) = delete;
@@ -69,6 +83,13 @@ class NPREffect::Impl : public EffectBase
Impl(Impl&&) = default;
Impl& operator=(Impl&&) = default;
+ void Initialize(
+ _In_ ID3D12Device* device,
+ uint32_t effectFlags,
+ const EffectPipelineStateDescription& pipelineDescription,
+ NPREffect::Mode nprMode,
+ bool enableSkinning);
+
enum RootParameterIndex
{
ConstantBuffer,
@@ -78,6 +99,17 @@ class NPREffect::Impl : public EffectBase
RootParameterCount
};
+ enum SkinRootParameterIndex
+ {
+ SkinConstantBuffer,
+ SkinTextureSRV,
+ SkinTextureSampler,
+ SkinConstantBufferBones,
+ SkinTexture2SRV,
+ SkinRootParameterCount
+ };
+
+ int weightsPerVertex;
bool matCapEnabled;
bool textureEnabled;
@@ -88,6 +120,12 @@ class NPREffect::Impl : public EffectBase
int GetPipelineStatePermutation(NPREffect::Mode nprMode, uint32_t effectFlags) const noexcept;
void Apply(_In_ ID3D12GraphicsCommandList* commandList);
+ void ApplySkinning(_In_ ID3D12GraphicsCommandList* commandList);
+
+ BoneConstants boneConstants;
+
+private:
+ GraphicsResource mBones;
};
@@ -152,6 +190,17 @@ namespace
#include "XboxGamingScarlettNPREffect_PSMatCapShading.inc"
#include "XboxGamingScarlettNPREffect_PSMatCapShadingTx.inc"
+
+#include "XboxGamingScarlettNPREffect_VSSkinnedNPREffectTx.inc"
+#include "XboxGamingScarlettNPREffect_VSSkinnedNPREffectTxBn.inc"
+
+#include "XboxGamingScarlettNPREffect_PSCelShadingSkinTx.inc"
+#include "XboxGamingScarlettNPREffect_PSGoochShadingSkinTx.inc"
+
+#include "XboxGamingScarlettNPREffect_VSSkinnedNPREffectTxMC.inc"
+#include "XboxGamingScarlettNPREffect_VSSkinnedNPREffectTxBnMC.inc"
+
+#include "XboxGamingScarlettNPREffect_PSMatCapShadingSkinTx.inc"
#elif defined(_GAMING_XBOX)
#include "XboxGamingXboxOneNPREffect_VSNPREffect.inc"
#include "XboxGamingXboxOneNPREffect_VSNPREffectInst.inc"
@@ -209,6 +258,17 @@ namespace
#include "XboxGamingXboxOneNPREffect_PSMatCapShading.inc"
#include "XboxGamingXboxOneNPREffect_PSMatCapShadingTx.inc"
+
+#include "XboxGamingXboxOneNPREffect_VSSkinnedNPREffectTx.inc"
+#include "XboxGamingXboxOneNPREffect_VSSkinnedNPREffectTxBn.inc"
+
+#include "XboxGamingXboxOneNPREffect_PSCelShadingSkinTx.inc"
+#include "XboxGamingXboxOneNPREffect_PSGoochShadingSkinTx.inc"
+
+#include "XboxGamingXboxOneNPREffect_VSSkinnedNPREffectTxMC.inc"
+#include "XboxGamingXboxOneNPREffect_VSSkinnedNPREffectTxBnMC.inc"
+
+#include "XboxGamingXboxOneNPREffect_PSMatCapShadingSkinTx.inc"
#elif defined(_XBOX_ONE) && defined(_TITLE)
#include "XboxOneNPREffect_VSNPREffect.inc"
#include "XboxOneNPREffect_VSNPREffectInst.inc"
@@ -266,6 +326,17 @@ namespace
#include "XboxOneNPREffect_PSMatCapShading.inc"
#include "XboxOneNPREffect_PSMatCapShadingTx.inc"
+
+#include "XboxOneNPREffect_VSSkinnedNPREffectTx.inc"
+#include "XboxOneNPREffect_VSSkinnedNPREffectTxBn.inc"
+
+#include "XboxOneNPREffect_PSCelShadingSkinTx.inc"
+#include "XboxOneNPREffect_PSGoochShadingSkinTx.inc"
+
+#include "XboxOneNPREffect_VSSkinnedNPREffectTxMC.inc"
+#include "XboxOneNPREffect_VSSkinnedNPREffectTxBnMC.inc"
+
+#include "XboxOneNPREffect_PSMatCapShadingSkinTx.inc"
#else
#include "NPREffect_VSNPREffect.inc"
#include "NPREffect_VSNPREffectInst.inc"
@@ -323,6 +394,17 @@ namespace
#include "NPREffect_PSMatCapShading.inc"
#include "NPREffect_PSMatCapShadingTx.inc"
+
+#include "NPREffect_VSSkinnedNPREffectTx.inc"
+#include "NPREffect_VSSkinnedNPREffectTxBn.inc"
+
+#include "NPREffect_PSCelShadingSkinTx.inc"
+#include "NPREffect_PSGoochShadingSkinTx.inc"
+
+#include "NPREffect_VSSkinnedNPREffectTxMC.inc"
+#include "NPREffect_VSSkinnedNPREffectTxBnMC.inc"
+
+#include "NPREffect_PSMatCapShadingSkinTx.inc"
#endif
}
@@ -330,38 +412,42 @@ namespace
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) },
+ { 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) },
+ { NPREffect_VSSkinnedNPREffectTx, sizeof(NPREffect_VSSkinnedNPREffectTx) },
+ { NPREffect_VSSkinnedNPREffectTxBn, sizeof(NPREffect_VSSkinnedNPREffectTxBn) },
+ { NPREffect_VSSkinnedNPREffectTxMC, sizeof(NPREffect_VSSkinnedNPREffectTxMC) },
+ { NPREffect_VSSkinnedNPREffectTxBnMC, sizeof(NPREffect_VSSkinnedNPREffectTxBnMC) },
};
@@ -431,18 +517,29 @@ const int EffectBase::VertexShaderIndices[] =
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
+
+ 32, // skinning + cel shading
+ 32, // skinning + gooch shading
+ 34, // skinning + matcap shading
+
+ 33, // skinning (biased vertex normal) + cel shading
+ 33, // skinning (biased vertex normal) + gooch shading
+ 35, // skinning (biased vertex normal) + matcap shading
};
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) },
+ { 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) },
+ { NPREffect_PSCelShadingSkinTx, sizeof(NPREffect_PSCelShadingSkinTx) }, // Different rootsig
+ { NPREffect_PSGoochShadingSkinTx, sizeof(NPREffect_PSGoochShadingSkinTx) },
+ { NPREffect_PSMatCapShadingSkinTx, sizeof(NPREffect_PSMatCapShadingSkinTx) },
};
@@ -512,6 +609,14 @@ const int EffectBase::PixelShaderIndices[] =
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
+
+ 6, // skinning + cel shading
+ 7, // skinning + gooch shading
+ 8, // skinning + matcap shading
+
+ 6, // skinning (biased vertex normal) + cel shading
+ 7, // skinning (biased vertex normal) + gooch shading
+ 8, // skinning (biased vertex normal) + matcap shading
};
#pragma endregion
@@ -522,34 +627,33 @@ SharedResourcePool::DeviceResources>
// Constructor.
NPREffect::Impl::Impl(
- _In_ ID3D12Device* device,
- uint32_t effectFlags,
- const EffectPipelineStateDescription& pipelineDescription,
- NPREffect::Mode nprMode)
+ _In_ ID3D12Device* device)
: EffectBase(device),
+ weightsPerVertex(0),
+ matCapEnabled(false),
+ textureEnabled(false),
texture{},
sampler{},
- matcap{}
+ matcap{},
+ boneConstants{}
{
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;
-
+void NPREffect::Impl::Initialize(
+ _In_ ID3D12Device* device,
+ uint32_t effectFlags,
+ const EffectPipelineStateDescription& pipelineDescription,
+ NPREffect::Mode nprMode,
+ bool enableSkinning)
+{
switch (nprMode)
{
case Mode_Cel:
case Mode_Gooch:
- matCapEnabled = false;
break;
case Mode_MatCap:
@@ -562,6 +666,39 @@ NPREffect::Impl::Impl(
textureEnabled = (effectFlags & EffectFlags::Texture) != 0;
+ 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;
+
+ if (enableSkinning)
+ {
+ if (effectFlags & EffectFlags::VertexColor)
+ {
+ DebugTrace("ERROR: SkinnedNPREffect does not implement EffectFlags::VertexColor\n");
+ throw std::invalid_argument("VertexColor effect flag is invalid");
+ }
+ else if (effectFlags & EffectFlags::Instancing)
+ {
+ DebugTrace("ERROR: SkinnedNPREffect does not implement EffectFlags::Instancing\n");
+ throw std::invalid_argument("Instancing effect flag is invalid");
+ }
+
+ weightsPerVertex = 4;
+ textureEnabled = true;
+
+ for (size_t j = 0; j < SkinnedNPREffect::MaxBones; ++j)
+ {
+ boneConstants.Bones[j][0] = g_XMIdentityR0;
+ boneConstants.Bones[j][1] = g_XMIdentityR1;
+ boneConstants.Bones[j][2] = g_XMIdentityR2;
+ }
+ }
+
// Create root signature.
{
ENUM_FLAGS_CONSTEXPR D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =
@@ -575,50 +712,90 @@ NPREffect::Impl::Impl(
#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)
+ if (enableSkinning)
{
- // Include two textures and one sampler
+ // Create root parameters and initialize first (constants)
+ CD3DX12_ROOT_PARAMETER rootParameters[SkinRootParameterIndex::SkinRootParameterCount] = {};
+ rootParameters[SkinRootParameterIndex::SkinConstantBuffer].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_ALL);
+
+ // 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);
+ rootParameters[SkinRootParameterIndex::SkinTextureSRV].InitAsDescriptorTable(1, &textureSRV, D3D12_SHADER_VISIBILITY_PIXEL);
+ rootParameters[SkinRootParameterIndex::SkinTextureSampler].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);
+ rootParameters[SkinRootParameterIndex::SkinConstantBufferBones].InitAsConstantBufferView(1, 0, D3D12_SHADER_VISIBILITY_VERTEX);
- // use all parameters
- rsigDesc.Init(static_cast(std::size(rootParameters)), rootParameters, 0, nullptr, rootSignatureFlags);
+ // Root parameter descriptor - conditionally initialized
+ CD3DX12_ROOT_SIGNATURE_DESC rsigDesc = {};
- 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);
+ if (matCapEnabled)
+ {
+ // Include second texture
+ const CD3DX12_DESCRIPTOR_RANGE texture2Range(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 1);
+ rootParameters[SkinRootParameterIndex::SkinTexture2SRV].InitAsDescriptorTable(1, &texture2Range, D3D12_SHADER_VISIBILITY_PIXEL);
- rootParameters[RootParameterIndex::TextureSRV].InitAsDescriptorTable(1, &textureSRV, D3D12_SHADER_VISIBILITY_PIXEL);
- rootParameters[RootParameterIndex::TextureSampler].InitAsDescriptorTable(1, &textureSampler, D3D12_SHADER_VISIBILITY_PIXEL);
+ // use all parameters
+ rsigDesc.Init(static_cast(std::size(rootParameters)), rootParameters, 0, nullptr, rootSignatureFlags);
- // use all but last parameter
- rsigDesc.Init(static_cast(std::size(rootParameters) - 1), rootParameters, 0, nullptr, rootSignatureFlags);
+ mRootSignature = GetRootSignature(4, rsigDesc);
+ }
+ else
+ {
+ // use all but last parameter
+ rsigDesc.Init(static_cast(std::size(rootParameters) - 1), rootParameters, 0, nullptr, rootSignatureFlags);
- mRootSignature = GetRootSignature(1, rsigDesc);
+ mRootSignature = GetRootSignature(3, rsigDesc);
+ }
}
- else
+ else // !enableSkinning
{
- // only use constant
- rsigDesc.Init(1, rootParameters, 0, nullptr, rootSignatureFlags);
-
- mRootSignature = GetRootSignature(0, rsigDesc);
+ // 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);
+ }
}
}
@@ -643,7 +820,14 @@ NPREffect::Impl::Impl(
EffectBase::PixelShaderBytecode[pi],
mPipelineState.GetAddressOf());
- SetDebugObjectName(mPipelineState.Get(), L"NPREffect");
+ if (enableSkinning)
+ {
+ SetDebugObjectName(mPipelineState.Get(), L"SkinnedNPREffect");
+ }
+ else
+ {
+ SetDebugObjectName(mPipelineState.Get(), L"NPREffect");
+ }
}
@@ -651,6 +835,20 @@ int NPREffect::Impl::GetPipelineStatePermutation(NPREffect::Mode nprMode, uint32
{
int permutation = static_cast(nprMode);
+ if (weightsPerVertex > 0)
+ {
+ if (effectFlags & EffectFlags::BiasedVertexNormals)
+ {
+ // Compressed normals need to be scaled and biased in the vertex shader.
+ permutation += 3;
+ }
+
+ // Vertex skinning does not support vertex colors or instancing, always includes a texture.
+ permutation += 48;
+
+ return permutation;
+ }
+
// Support vertex coloring?
if (effectFlags & EffectFlags::VertexColor)
{
@@ -682,6 +880,8 @@ int NPREffect::Impl::GetPipelineStatePermutation(NPREffect::Mode nprMode, uint32
// Sets our state onto the D3D device.
void NPREffect::Impl::Apply(_In_ ID3D12GraphicsCommandList* commandList)
{
+ assert(weightsPerVertex == 0);
+
// Compute derived parameter values.
matrices.SetConstants(
dirtyFlags,
@@ -695,7 +895,7 @@ void NPREffect::Impl::Apply(_In_ ID3D12GraphicsCommandList* commandList)
// Set the root signature
commandList->SetGraphicsRootSignature(mRootSignature);
- // Set the texture
+ // Set the texture(s)
if (textureEnabled)
{
if (!texture.ptr || !sampler.ptr)
@@ -709,9 +909,21 @@ void NPREffect::Impl::Apply(_In_ ID3D12GraphicsCommandList* commandList)
// with the required descriptor heaps.
commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSRV, texture);
commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSampler, sampler);
- }
- if (matCapEnabled)
+ if (matCapEnabled)
+ {
+ if (!matcap.ptr)
+ {
+ DebugTrace("ERROR: Missing matcap texture or sampler for NPREffect\n");
+ 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::Texture2SRV, matcap);
+ }
+ }
+ else if (matCapEnabled)
{
if (!matcap.ptr || !sampler.ptr)
{
@@ -722,9 +934,7 @@ void NPREffect::Impl::Apply(_In_ ID3D12GraphicsCommandList* commandList)
// **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::TextureSRV, matcap);
commandList->SetGraphicsRootDescriptorTable(RootParameterIndex::TextureSampler, sampler);
}
@@ -736,14 +946,82 @@ void NPREffect::Impl::Apply(_In_ ID3D12GraphicsCommandList* commandList)
}
+void NPREffect::Impl::ApplySkinning(_In_ ID3D12GraphicsCommandList* commandList)
+{
+ assert(weightsPerVertex > 0);
+ assert(textureEnabled);
+
+ // Compute derived parameter values.
+ matrices.SetConstants(
+ dirtyFlags,
+ constants.world,
+ constants.worldInverseTranspose,
+ constants.worldViewProj,
+ constants.eyePosition);
+
+ UpdateConstants();
+
+ if (dirtyFlags & EffectDirtyFlags::ConstantBufferBones)
+ {
+ mBones = GraphicsMemory::Get(GetDevice()).AllocateConstant(boneConstants);
+ dirtyFlags &= ~EffectDirtyFlags::ConstantBufferBones;
+ }
+
+ // Set the root signature
+ commandList->SetGraphicsRootSignature(mRootSignature);
+
+ // Set the texture(s)
+ if (!texture.ptr || !sampler.ptr)
+ {
+ DebugTrace("ERROR: Missing texture or sampler for SkinnedNPREffect (texture %llu, sampler %llu)\n",
+ texture.ptr, sampler.ptr);
+ throw std::runtime_error("SkinnedNPREffect");
+ }
+
+ // **NOTE** If D3D asserts or crashes here, you probably need to call commandList->SetDescriptorHeaps()
+ // with the required descriptor heaps.
+ commandList->SetGraphicsRootDescriptorTable(SkinRootParameterIndex::SkinTextureSRV, texture);
+ commandList->SetGraphicsRootDescriptorTable(SkinRootParameterIndex::SkinTextureSampler, sampler);
+
+ if (matCapEnabled)
+ {
+ if (!matcap.ptr)
+ {
+ DebugTrace("ERROR: Missing matcap texture for SkinnedNPREffect\n");
+ throw std::runtime_error("SkinnedNPREffect");
+ }
+
+ // **NOTE** If D3D asserts or crashes here, you probably need to call commandList->SetDescriptorHeaps()
+ // with the required descriptor heaps.
+ commandList->SetGraphicsRootDescriptorTable(SkinRootParameterIndex::SkinTexture2SRV, matcap);
+ }
+
+ // Set bone constants
+ commandList->SetGraphicsRootConstantBufferView(SkinRootParameterIndex::SkinConstantBufferBones, mBones.GpuAddress());
+
+ // Set constants
+ commandList->SetGraphicsRootConstantBufferView(SkinRootParameterIndex::SkinConstantBuffer, GetConstantBufferGpuAddress());
+
+ // Set the pipeline state
+ commandList->SetPipelineState(EffectBase::mPipelineState.Get());
+}
+
+
+//--------------------------------------------------------------------------------------
+// NPREffect
+//--------------------------------------------------------------------------------------
+
// Public constructor.
NPREffect::NPREffect(
_In_ ID3D12Device* device,
uint32_t effectFlags,
const EffectPipelineStateDescription& pipelineDescription,
- Mode nprMode)
- : pImpl(std::make_unique(device, effectFlags, pipelineDescription, nprMode))
-{}
+ Mode nprMode,
+ bool skinningEnabled)
+ : pImpl(std::make_unique(device))
+{
+ pImpl->Initialize(device, effectFlags, pipelineDescription, nprMode, skinningEnabled);
+}
NPREffect::NPREffect(NPREffect&&) noexcept = default;
@@ -1017,3 +1295,59 @@ void NPREffect::DisableRimLighting()
pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;
}
+
+
+//--------------------------------------------------------------------------------------
+// SkinnedNPREffect
+//--------------------------------------------------------------------------------------
+
+SkinnedNPREffect::~SkinnedNPREffect()
+{}
+
+
+// IEffect methods.
+void SkinnedNPREffect::Apply(_In_ ID3D12GraphicsCommandList* commandList)
+{
+ pImpl->ApplySkinning(commandList);
+}
+
+
+// Animation settings.
+void SkinnedNPREffect::SetBoneTransforms(_In_reads_(count) XMMATRIX const* value, size_t count)
+{
+ if (count > MaxBones)
+ throw std::invalid_argument("count parameter exceeds MaxBones");
+
+ auto boneConstant = pImpl->boneConstants.Bones;
+
+ for (size_t i = 0; i < count; i++)
+ {
+ #if DIRECTX_MATH_VERSION >= 313
+ XMStoreFloat3x4A(reinterpret_cast(&boneConstant[i]), value[i]);
+ #else
+ // Xbox One XDK has an older version of DirectXMath
+ XMMATRIX boneMatrix = XMMatrixTranspose(value[i]);
+
+ boneConstant[i][0] = boneMatrix.r[0];
+ boneConstant[i][1] = boneMatrix.r[1];
+ boneConstant[i][2] = boneMatrix.r[2];
+ #endif
+ }
+
+ pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferBones;
+}
+
+
+void SkinnedNPREffect::ResetBoneTransforms()
+{
+ auto boneConstant = pImpl->boneConstants.Bones;
+
+ for (size_t i = 0; i < MaxBones; ++i)
+ {
+ boneConstant[i][0] = g_XMIdentityR0;
+ boneConstant[i][1] = g_XMIdentityR1;
+ boneConstant[i][2] = g_XMIdentityR2;
+ }
+
+ pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferBones;
+}
diff --git a/Src/NPREffectFactory.cpp b/Src/NPREffectFactory.cpp
new file mode 100644
index 00000000..0311c1f0
--- /dev/null
+++ b/Src/NPREffectFactory.cpp
@@ -0,0 +1,501 @@
+//--------------------------------------------------------------------------------------
+// File: NPREffectFactory.cpp
+//
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+//
+// https://go.microsoft.com/fwlink/?LinkID=615561
+//--------------------------------------------------------------------------------------
+
+#include "pch.h"
+#include "Effects.h"
+#include "CommonStates.h"
+#include "DirectXHelpers.h"
+#include "PlatformHelpers.h"
+#include "DescriptorHeap.h"
+
+#include
+
+
+using namespace DirectX;
+using Microsoft::WRL::ComPtr;
+
+namespace
+{
+ template
+ void SetMaterialProperties(_In_ T* effect, const EffectFactory::EffectInfo& info)
+ {
+ effect->EnableDefaultLighting();
+
+ effect->SetAlpha(info.alphaValue);
+
+ // Most DirectX Tool Kit effects do not have an ambient material color.
+
+ XMVECTOR color = XMLoadFloat3(&info.diffuseColor);
+ effect->SetDiffuseColor(color);
+
+ if (info.specularColor.x != 0 || info.specularColor.y != 0 || info.specularColor.z != 0)
+ {
+ color = XMLoadFloat3(&info.specularColor);
+ effect->SetSpecularColor(color);
+ }
+ else
+ {
+ effect->DisableSpecular();
+ }
+ }
+}
+
+// Internal NPREffectFactory implementation class. Only one of these helpers is allocated
+// per D3D device, even if there are multiple public facing NPREffectFactory instances.
+class NPREffectFactory::Impl
+{
+public:
+ Impl(_In_ ID3D12Device* device, _In_ ID3D12DescriptorHeap* textureDescriptors, _In_ ID3D12DescriptorHeap* samplerDescriptors) noexcept(false)
+ : mTextureDescriptors(nullptr)
+ , mSamplerDescriptors(nullptr)
+ , mMode(NPREffect::Mode_Cel)
+ , mSharing(true)
+ , mEnableInstancing(false)
+ , mUseEmissiveForMatCap(true)
+ , mMatcapTextureIndex(-1)
+ , mMatcapSamplerIndex(-1)
+ , mDevice(device)
+ {
+ if (!device)
+ throw std::invalid_argument("Direct3D device is null");
+
+ if (textureDescriptors)
+ mTextureDescriptors = std::make_unique(textureDescriptors);
+ if (samplerDescriptors)
+ mSamplerDescriptors = std::make_unique(samplerDescriptors);
+ }
+
+ Impl(const Impl&) = delete;
+ Impl& operator=(const Impl&) = delete;
+
+ Impl(Impl&&) = delete;
+ Impl& operator=(Impl&&) = delete;
+
+ std::shared_ptr CreateEffect(
+ const EffectInfo& info,
+ const EffectPipelineStateDescription& opaquePipelineState,
+ const EffectPipelineStateDescription& alphaPipelineState,
+ const D3D12_INPUT_LAYOUT_DESC& inputLayout,
+ int textureDescriptorOffset,
+ int samplerDescriptorOffset);
+
+ void ReleaseCache();
+
+ std::unique_ptr mTextureDescriptors;
+ std::unique_ptr mSamplerDescriptors;
+
+ NPREffect::Mode mMode;
+ bool mSharing;
+ bool mEnableInstancing;
+ bool mUseEmissiveForMatCap;
+ int mMatcapTextureIndex;
+ int mMatcapSamplerIndex;
+
+ ComPtr mDevice;
+
+private:
+ using EffectCache = std::map< std::wstring, std::shared_ptr >;
+
+ EffectCache mEffectCache;
+ EffectCache mEffectCacheSkinning;
+ EffectCache mEffectCacheDualTexture;
+
+ std::mutex mutex;
+};
+
+
+std::shared_ptr NPREffectFactory::Impl::CreateEffect(
+ const EffectInfo& info,
+ const EffectPipelineStateDescription& opaquePipelineState,
+ const EffectPipelineStateDescription& alphaPipelineState,
+ const D3D12_INPUT_LAYOUT_DESC& inputLayoutDesc,
+ int textureDescriptorOffset,
+ int samplerDescriptorOffset)
+{
+ // If textures are required, make sure we have a descriptor heap
+ if (!mTextureDescriptors && (info.diffuseTextureIndex != -1 || info.specularTextureIndex != -1 || info.emissiveTextureIndex != -1))
+ {
+ DebugTrace("ERROR: NPREffectFactory created without texture descriptor heap with texture index set (diffuse %d, specular %d, emissive %d)!\n",
+ info.diffuseTextureIndex, info.specularTextureIndex, info.emissiveTextureIndex);
+ throw std::runtime_error("NPREffectFactory");
+ }
+ if (!mSamplerDescriptors && (info.samplerIndex != -1 || info.samplerIndex2 != -1))
+ {
+ DebugTrace("ERROR: NPREffectFactory created without sampler descriptor heap with sampler index set (samplerIndex %d, samplerIndex2 %d)!\n",
+ info.samplerIndex, info.samplerIndex2);
+ throw std::runtime_error("NPREffectFactory");
+ }
+
+ // If we have descriptors, make sure we have both texture and sampler descriptors
+ if ((mTextureDescriptors == nullptr) != (mSamplerDescriptors == nullptr))
+ {
+ DebugTrace("ERROR: A texture or sampler descriptor heap was provided, but both are required.\n");
+ throw std::runtime_error("NPREffectFactory");
+ }
+
+ // Validate the we have either both texture and sampler descriptors, or neither
+ if ((info.diffuseTextureIndex == -1) != (info.samplerIndex == -1))
+ {
+ DebugTrace("ERROR: Material provides either a texture or sampler, but both are required.\n");
+ throw std::runtime_error("NPREffectFactory");
+ }
+
+ const int diffuseTextureIndex = (info.diffuseTextureIndex != -1 && mTextureDescriptors != nullptr) ? info.diffuseTextureIndex + textureDescriptorOffset : -1;
+ const int specularTextureIndex = (info.specularTextureIndex != -1 && mTextureDescriptors != nullptr) ? info.specularTextureIndex + textureDescriptorOffset : -1;
+ const int emissiveTextureIndex = (info.emissiveTextureIndex != -1 && mTextureDescriptors != nullptr) ? info.emissiveTextureIndex + textureDescriptorOffset : -1;
+ const int samplerIndex = (info.samplerIndex != -1 && mSamplerDescriptors != nullptr) ? info.samplerIndex + samplerDescriptorOffset : -1;
+ const int samplerIndex2 = (info.samplerIndex2 != -1 && mSamplerDescriptors != nullptr) ? info.samplerIndex2 + samplerDescriptorOffset : -1;
+
+ // Modify base pipeline state
+ EffectPipelineStateDescription derivedPSD = (info.alphaValue < 1.0f) ? alphaPipelineState : opaquePipelineState;
+ derivedPSD.inputLayout = inputLayoutDesc;
+
+ std::wstring cacheName;
+ if (info.enableSkinning)
+ {
+ int effectflags = EffectFlags::None;
+
+ if (info.biasedVertexNormals)
+ {
+ effectflags |= EffectFlags::BiasedVertexNormals;
+ }
+
+ // SkinnedNPREffect
+ if (mSharing && !info.name.empty())
+ {
+ const uint32_t hash = derivedPSD.ComputeHash();
+ cacheName = std::to_wstring(effectflags) + std::to_wstring(mMode) + info.name + std::to_wstring(hash);
+
+ auto it = mEffectCacheSkinning.find(cacheName);
+ if (mSharing && it != mEffectCacheSkinning.end())
+ {
+ return it->second;
+ }
+ }
+
+ auto effect = std::make_shared(mDevice.Get(), effectflags, derivedPSD, mMode);
+
+ SetMaterialProperties(effect.get(), info);
+
+ if (diffuseTextureIndex != -1)
+ {
+ effect->SetTexture(
+ mTextureDescriptors->GetGpuHandle(static_cast(diffuseTextureIndex)),
+ mSamplerDescriptors->GetGpuHandle(static_cast(samplerIndex)));
+ }
+
+ if (mMode == NPREffect::Mode_MatCap)
+ {
+ if (mUseEmissiveForMatCap && emissiveTextureIndex != -1)
+ {
+ if (samplerIndex == -1)
+ {
+ DebugTrace("ERROR: SkinnedNPREffect (matcap) requires a sampler (emissive %d)\n", emissiveTextureIndex);
+ throw std::runtime_error("NPREffectFactory");
+ }
+
+ effect->SetMatCap(
+ mTextureDescriptors->GetGpuHandle(static_cast(emissiveTextureIndex)),
+ mSamplerDescriptors->GetGpuHandle(static_cast(samplerIndex)));
+ }
+ else if (mMatcapTextureIndex != -1)
+ {
+ auto matcap = mTextureDescriptors->GetGpuHandle(static_cast(mMatcapTextureIndex));
+ if (samplerIndex != -1)
+ {
+ effect->SetMatCap(matcap,
+ mSamplerDescriptors->GetGpuHandle(static_cast(samplerIndex)));
+ }
+ else if (mMatcapSamplerIndex != -1)
+ {
+ effect->SetMatCap(matcap,
+ mSamplerDescriptors->GetGpuHandle(static_cast(mMatcapSamplerIndex)));
+ }
+ }
+ }
+
+ if (mSharing && !info.name.empty())
+ {
+ std::lock_guard lock(mutex);
+ EffectCache::value_type v(cacheName, effect);
+ mEffectCacheSkinning.insert(v);
+ }
+
+ return std::move(effect);
+ }
+ else if (info.enableDualTexture)
+ {
+ // DualTextureEffect
+ int effectflags = EffectFlags::None;
+
+ if (mSharing && !info.name.empty())
+ {
+ const uint32_t hash = derivedPSD.ComputeHash();
+ cacheName = std::to_wstring(effectflags) + info.name + std::to_wstring(hash);
+
+ auto it = mEffectCacheDualTexture.find(cacheName);
+ if (mSharing && it != mEffectCacheDualTexture.end())
+ {
+ return it->second;
+ }
+ }
+
+ if (info.perVertexColor)
+ {
+ effectflags |= EffectFlags::VertexColor;
+ }
+
+ auto effect = std::make_shared(mDevice.Get(), effectflags, derivedPSD);
+
+ // Dual texture effect doesn't support lighting (usually it's lightmaps)
+ effect->SetAlpha(info.alphaValue);
+
+ const XMVECTOR color = XMLoadFloat3(&info.diffuseColor);
+ effect->SetDiffuseColor(color);
+
+ if (diffuseTextureIndex != -1)
+ {
+ effect->SetTexture(
+ mTextureDescriptors->GetGpuHandle(static_cast(diffuseTextureIndex)),
+ mSamplerDescriptors->GetGpuHandle(static_cast(samplerIndex)));
+ }
+
+ if (emissiveTextureIndex != -1)
+ {
+ if (samplerIndex2 == -1)
+ {
+ DebugTrace("ERROR: Dual-texture requires a second sampler (emissive %d)\n", emissiveTextureIndex);
+ throw std::runtime_error("NPREffectFactory");
+ }
+
+ effect->SetTexture2(
+ mTextureDescriptors->GetGpuHandle(static_cast(emissiveTextureIndex)),
+ mSamplerDescriptors->GetGpuHandle(static_cast(samplerIndex2)));
+ }
+ else if (specularTextureIndex != -1)
+ {
+ // If there's no emissive texture specified, use the specular texture as the second texture
+ if (samplerIndex2 == -1)
+ {
+ DebugTrace("ERROR: Dual-texture requires a second sampler (specular %d)\n", specularTextureIndex);
+ throw std::runtime_error("NPREffectFactory");
+ }
+
+ effect->SetTexture2(
+ mTextureDescriptors->GetGpuHandle(static_cast(specularTextureIndex)),
+ mSamplerDescriptors->GetGpuHandle(static_cast(samplerIndex2)));
+ }
+
+ if (mSharing && !info.name.empty())
+ {
+ std::lock_guard lock(mutex);
+ EffectCache::value_type v(cacheName, effect);
+ mEffectCacheDualTexture.insert(v);
+ }
+
+ return std::move(effect);
+ }
+ else
+ {
+ // set effect flags for creation
+ int effectflags = EffectFlags::None;
+
+ if (info.perVertexColor)
+ {
+ effectflags |= EffectFlags::VertexColor;
+ }
+
+ if (diffuseTextureIndex != -1)
+ {
+ effectflags |= EffectFlags::Texture;
+ }
+
+ if (info.biasedVertexNormals)
+ {
+ effectflags |= EffectFlags::BiasedVertexNormals;
+ }
+
+ // NPREffect
+ if (mSharing && !info.name.empty())
+ {
+ const uint32_t hash = derivedPSD.ComputeHash();
+ cacheName = std::to_wstring(effectflags) + std::to_wstring(mMode) + info.name + std::to_wstring(hash);
+
+ auto it = mEffectCache.find(cacheName);
+ if (mSharing && it != mEffectCache.end())
+ {
+ return it->second;
+ }
+ }
+
+ auto effect = std::make_shared(mDevice.Get(), effectflags, derivedPSD, mMode);
+
+ SetMaterialProperties(effect.get(), info);
+
+ if (diffuseTextureIndex != -1)
+ {
+ effect->SetTexture(
+ mTextureDescriptors->GetGpuHandle(static_cast(diffuseTextureIndex)),
+ mSamplerDescriptors->GetGpuHandle(static_cast(samplerIndex)));
+ }
+
+ if (mMode == NPREffect::Mode_MatCap)
+ {
+ if (mUseEmissiveForMatCap && emissiveTextureIndex != -1)
+ {
+ if (samplerIndex == -1)
+ {
+ DebugTrace("ERROR: NPREffect (matcap) requires a sampler (emissive %d)\n", emissiveTextureIndex);
+ throw std::runtime_error("NPREffectFactory");
+ }
+
+ effect->SetMatCap(
+ mTextureDescriptors->GetGpuHandle(static_cast(emissiveTextureIndex)),
+ mSamplerDescriptors->GetGpuHandle(static_cast(samplerIndex)));
+ }
+ else if (mMatcapTextureIndex != -1)
+ {
+ auto matcap = mTextureDescriptors->GetGpuHandle(static_cast(mMatcapTextureIndex));
+ if (samplerIndex != -1)
+ {
+ effect->SetMatCap(matcap,
+ mSamplerDescriptors->GetGpuHandle(static_cast(samplerIndex)));
+ }
+ else if (mMatcapSamplerIndex != -1)
+ {
+ effect->SetMatCap(matcap,
+ mSamplerDescriptors->GetGpuHandle(static_cast(mMatcapSamplerIndex)));
+ }
+ }
+ }
+
+ if (mSharing && !info.name.empty())
+ {
+ std::lock_guard lock(mutex);
+ EffectCache::value_type v(cacheName, effect);
+ mEffectCache.insert(v);
+ }
+
+ return std::move(effect);
+ }
+}
+
+void NPREffectFactory::Impl::ReleaseCache()
+{
+ std::lock_guard lock(mutex);
+ mEffectCache.clear();
+ mEffectCacheSkinning.clear();
+ mEffectCacheDualTexture.clear();
+}
+
+
+
+//--------------------------------------------------------------------------------------
+// NPREffectFactory
+//--------------------------------------------------------------------------------------
+
+NPREffectFactory::NPREffectFactory(_In_ ID3D12Device* device) :
+ pImpl(std::make_shared(device, nullptr, nullptr))
+{}
+
+NPREffectFactory::NPREffectFactory(_In_ ID3D12DescriptorHeap* textureDescriptors, _In_ ID3D12DescriptorHeap* samplerDescriptors)
+{
+ if (!textureDescriptors)
+ {
+ throw std::invalid_argument("Texture descriptor heap cannot be null if no device is provided. Use the alternative NPREffectFactory constructor instead.");
+ }
+ if (!samplerDescriptors)
+ {
+ throw std::invalid_argument("Descriptor heap cannot be null if no device is provided. Use the alternative NPREffectFactory constructor instead.");
+ }
+
+#if defined(_MSC_VER) || !defined(_WIN32)
+ const D3D12_DESCRIPTOR_HEAP_TYPE textureHeapType = textureDescriptors->GetDesc().Type;
+ const D3D12_DESCRIPTOR_HEAP_TYPE samplerHeapType = samplerDescriptors->GetDesc().Type;
+#else
+ D3D12_DESCRIPTOR_HEAP_DESC tmpDesc1, tmpDesc2;
+ const D3D12_DESCRIPTOR_HEAP_TYPE textureHeapType = textureDescriptors->GetDesc(&tmpDesc1)->Type;
+ const D3D12_DESCRIPTOR_HEAP_TYPE samplerHeapType = samplerDescriptors->GetDesc(&tmpDesc2)->Type;
+#endif
+
+ if (textureHeapType != D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
+ {
+ throw std::invalid_argument("NPREffectFactory::CreateEffect requires a CBV_SRV_UAV descriptor heap for textureDescriptors.");
+ }
+ if (samplerHeapType != D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)
+ {
+ throw std::invalid_argument("NPREffectFactory::CreateEffect requires a SAMPLER descriptor heap for samplerDescriptors.");
+ }
+
+ ComPtr device;
+#if (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)
+ textureDescriptors->GetDevice(IID_GRAPHICS_PPV_ARGS(device.GetAddressOf()));
+#else
+ HRESULT hr = textureDescriptors->GetDevice(IID_PPV_ARGS(device.GetAddressOf()));
+ ThrowIfFailed(hr);
+#endif
+
+ pImpl = std::make_shared(device.Get(), textureDescriptors, samplerDescriptors);
+}
+
+
+NPREffectFactory::NPREffectFactory(NPREffectFactory&&) noexcept = default;
+NPREffectFactory& NPREffectFactory::operator= (NPREffectFactory&&) noexcept = default;
+NPREffectFactory::~NPREffectFactory() = default;
+
+
+std::shared_ptr NPREffectFactory::CreateEffect(
+ const EffectInfo& info,
+ const EffectPipelineStateDescription& opaquePipelineState,
+ const EffectPipelineStateDescription& alphaPipelineState,
+ const D3D12_INPUT_LAYOUT_DESC& inputLayout,
+ int textureDescriptorOffset,
+ int samplerDescriptorOffset)
+{
+ return pImpl->CreateEffect(info, opaquePipelineState, alphaPipelineState, inputLayout, textureDescriptorOffset, samplerDescriptorOffset);
+}
+
+
+void NPREffectFactory::ReleaseCache()
+{
+ pImpl->ReleaseCache();
+}
+
+
+// Properties.
+void NPREffectFactory::SetSharing(bool enabled) noexcept
+{
+ pImpl->mSharing = enabled;
+}
+
+void NPREffectFactory::EnableInstancing(bool enabled) noexcept
+{
+ pImpl->mEnableInstancing = enabled;
+}
+
+void NPREffectFactory::SetMode(NPREffect::Mode mode) noexcept
+{
+ pImpl->mMode = mode;
+}
+
+void NPREffectFactory::SetDefaultMatCap(int textureIndex, int samplerIndex) noexcept
+{
+ pImpl->mMatcapTextureIndex = textureIndex;
+ pImpl->mMatcapSamplerIndex = samplerIndex;
+}
+
+void NPREffectFactory::SetEmissiveAsMatCap(bool value) noexcept
+{
+ pImpl->mUseEmissiveForMatCap = value;
+}
+
+ID3D12Device* NPREffectFactory::GetDevice() const noexcept
+{
+ return pImpl->mDevice.Get();
+}
diff --git a/Src/PBREffect.cpp b/Src/PBREffect.cpp
index 59b98f7a..ac67dd1e 100644
--- a/Src/PBREffect.cpp
+++ b/Src/PBREffect.cpp
@@ -407,12 +407,12 @@ void PBREffect::Impl::Initialize(
for (size_t i = 0; i < std::size(textureSRV); i++)
{
- rootParameters[i].InitAsDescriptorTable(1, &textureSRV[i]);
+ rootParameters[i].InitAsDescriptorTable(1, &textureSRV[i], D3D12_SHADER_VISIBILITY_PIXEL);
}
for (size_t i = 0; i < std::size(textureSampler); i++)
{
- rootParameters[i + SurfaceSampler].InitAsDescriptorTable(1, &textureSampler[i]);
+ rootParameters[i + SurfaceSampler].InitAsDescriptorTable(1, &textureSampler[i], D3D12_SHADER_VISIBILITY_PIXEL);
}
rootParameters[ConstantBuffer].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_ALL);
diff --git a/Src/PBREffectFactory.cpp b/Src/PBREffectFactory.cpp
index 0e0268db..91438ecc 100644
--- a/Src/PBREffectFactory.cpp
+++ b/Src/PBREffectFactory.cpp
@@ -119,9 +119,9 @@ class PBREffectFactory::Impl
std::unique_ptr mTextureDescriptors;
std::unique_ptr mSamplerDescriptors;
-private:
ComPtr mDevice;
+private:
using EffectCache = std::map< std::wstring, std::shared_ptr >;
EffectCache mEffectCache;
@@ -327,3 +327,8 @@ void PBREffectFactory::EnableInstancing(bool enabled) noexcept
{
pImpl->mEnableInstancing = enabled;
}
+
+ID3D12Device* PBREffectFactory::GetDevice() const noexcept
+{
+ return pImpl->mDevice.Get();
+}
diff --git a/Src/Shaders/CompileShaders.cmd b/Src/Shaders/CompileShaders.cmd
index 3a817f0b..20fa6081 100644
--- a/Src/Shaders/CompileShaders.cmd
+++ b/Src/Shaders/CompileShaders.cmd
@@ -278,6 +278,9 @@ call :CompileShader%1 NPREffect vs VSNPREffectBnInstTx
call :CompileShader%1 NPREffect vs VSNPREffectVcInstTx
call :CompileShader%1 NPREffect vs VSNPREffectVcBnInstTx
+call :CompileShader%1 NPREffect vs VSSkinnedNPREffectTx
+call :CompileShader%1 NPREffect vs VSSkinnedNPREffectTxBn
+
call :CompileShader%1 NPREffect vs VSNPREffectMC
call :CompileShader%1 NPREffect vs VSNPREffectBnMC
call :CompileShader%1 NPREffect vs VSNPREffectVcMC
@@ -298,14 +301,20 @@ call :CompileShader%1 NPREffect vs VSNPREffectBnInstTxMC
call :CompileShader%1 NPREffect vs VSNPREffectVcInstTxMC
call :CompileShader%1 NPREffect vs VSNPREffectVcBnInstTxMC
+call :CompileShader%1 NPREffect vs VSSkinnedNPREffectTxMC
+call :CompileShader%1 NPREffect vs VSSkinnedNPREffectTxBnMC
+
call :CompileShader%1 NPREffect ps PSCelShading
call :CompileShader%1 NPREffect ps PSCelShadingTx
+call :CompileShader%1 NPREffect ps PSCelShadingSkinTx
call :CompileShader%1 NPREffect ps PSGoochShading
call :CompileShader%1 NPREffect ps PSGoochShadingTx
+call :CompileShader%1 NPREffect ps PSGoochShadingSkinTx
call :CompileShader%1 NPREffect ps PSMatCapShading
call :CompileShader%1 NPREffect ps PSMatCapShadingTx
+call :CompileShader%1 NPREffect ps PSMatCapShadingSkinTx
call :CompileShader%1 SpriteEffect vs SpriteVertexShader
call :CompileShader%1 SpriteEffect ps SpritePixelShader
diff --git a/Src/Shaders/NPREffect.fx b/Src/Shaders/NPREffect.fx
index b33d495c..561a36c5 100644
--- a/Src/Shaders/NPREffect.fx
+++ b/Src/Shaders/NPREffect.fx
@@ -41,11 +41,18 @@ cbuffer Parameters : register(b0)
float4x4 WorldViewProj : packoffset(c15);
};
+cbuffer SkinningParameters : register(b1)
+{
+ float4x3 Bones[72];
+}
+
#include "RootSig.fxh"
#include "Structures.fxh"
+#include "Skinning.fxh"
#include "Utilities.fxh"
+
VSOutputPixelLighting ComputeCommonVS(float4 position, float3 normal)
{
VSOutputPixelLighting vout;
@@ -343,6 +350,42 @@ VSOutputPixelLightingTx VSNPREffectVcBnInstTxMC(VSInputNmTxVcInst vin)
}
+// Vertex shader: skinning (four bones) + texture.
+[RootSignature(SkinTextureSamplerRS)]
+VSOutputPixelLightingTx VSSkinnedNPREffectTx(VSInputNmTxWeights vin)
+{
+ float3 normal = Skin(vin, vin.Normal, 4);
+
+ VSOutputPixelLightingTx vout = ComputeCommonVSTx(vin.Position, normal, vin.TexCoord);
+ vout.Diffuse = float4(DiffuseColor, Alpha);
+ return vout;
+}
+
+[RootSignature(SkinDualTextureOneSamplerRS)]
+VSOutputPixelLightingTx VSSkinnedNPREffectTxMC(VSInputNmTxWeights vin)
+{
+ return VSSkinnedNPREffectTx(vin);
+}
+
+[RootSignature(SkinTextureSamplerRS)]
+VSOutputPixelLightingTx VSSkinnedNPREffectTxBn(VSInputNmTxWeights vin)
+{
+ float3 normal = BiasX2(vin.Normal);
+
+ normal = Skin(vin, normal, 4);
+
+ VSOutputPixelLightingTx vout = ComputeCommonVSTx(vin.Position, normal, vin.TexCoord);
+ vout.Diffuse = float4(DiffuseColor, Alpha);
+ return vout;
+}
+
+[RootSignature(SkinDualTextureOneSamplerRS)]
+VSOutputPixelLightingTx VSSkinnedNPREffectTxBnMC(VSInputNmTxWeights vin)
+{
+ return VSSkinnedNPREffectTxBn(vin);
+}
+
+
//--- Cel shading ---
float Quantize(float intensity, float bands)
{
@@ -427,6 +470,11 @@ float4 PSCelShadingTx(PSInputPixelLightingTx pin) : SV_Target0
return float4(color, pin.Diffuse.a * texColor.a);
}
+[RootSignature(SkinTextureSamplerRS)]
+float4 PSCelShadingSkinTx(PSInputPixelLightingTx pin) : SV_Target0
+{
+ return PSCelShadingTx(pin);
+}
//--- Gooch shading ---
float3 GoochShading(float dot1, float3 color)
@@ -500,6 +548,12 @@ float4 PSGoochShadingTx(PSInputPixelLightingTx pin) : SV_Target0
return float4(color, pin.Diffuse.a * texColor.a);
}
+[RootSignature(SkinTextureSamplerRS)]
+float4 PSGoochShadingSkinTx(PSInputPixelLightingTx pin) : SV_Target0
+{
+ return PSGoochShadingTx(pin);
+}
+
//--- MatCap shading ---
@@ -542,3 +596,9 @@ float4 PSMatCapShadingTx(PSInputPixelLightingTx pin) : SV_Target0
return float4(color, pin.Diffuse.a * texColor.a);
}
+
+[RootSignature(SkinDualTextureOneSamplerRS)]
+float4 PSMatCapShadingSkinTx(PSInputPixelLightingTx pin) : SV_Target0
+{
+ return PSMatCapShadingTx(pin);
+}
diff --git a/Src/Shaders/RootSig.fxh b/Src/Shaders/RootSig.fxh
index 416d2509..b09c63ba 100644
--- a/Src/Shaders/RootSig.fxh
+++ b/Src/Shaders/RootSig.fxh
@@ -182,14 +182,14 @@
" DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \
" DENY_HULL_SHADER_ROOT_ACCESS |" \
" DENY_MESH_SHADER_ROOT_ACCESS )," \
-"DescriptorTable ( SRV(t0) ),"\
-"DescriptorTable ( SRV(t1) ),"\
-"DescriptorTable ( SRV(t2) ),"\
-"DescriptorTable ( SRV(t3) ),"\
-"DescriptorTable ( SRV(t4) ),"\
-"DescriptorTable ( SRV(t5) ),"\
-"DescriptorTable ( Sampler(s0) ),"\
-"DescriptorTable ( Sampler(s1) ),"\
+"DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),"\
+"DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL ),"\
+"DescriptorTable ( SRV(t2), visibility = SHADER_VISIBILITY_PIXEL ),"\
+"DescriptorTable ( SRV(t3), visibility = SHADER_VISIBILITY_PIXEL ),"\
+"DescriptorTable ( SRV(t4), visibility = SHADER_VISIBILITY_PIXEL ),"\
+"DescriptorTable ( SRV(t5), visibility = SHADER_VISIBILITY_PIXEL ),"\
+"DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL ),"\
+"DescriptorTable ( Sampler(s1), visibility = SHADER_VISIBILITY_PIXEL ),"\
"CBV(b0)," \
"CBV(b1, visibility = SHADER_VISIBILITY_VERTEX )"
@@ -214,6 +214,31 @@
"DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL ),"\
"DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL )"
+#define SkinTextureSamplerRS \
+"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 ),"\
+"CBV(b1, visibility = SHADER_VISIBILITY_VERTEX )"
+
+#define SkinDualTextureOneSamplerRS \
+"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 ),"\
+"CBV(b1, visibility = SHADER_VISIBILITY_VERTEX ),"\
+"DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL )"
+
#else // !__XBOX_SCARLETT
#define NoTextureRS \
@@ -365,14 +390,14 @@
" DENY_DOMAIN_SHADER_ROOT_ACCESS |" \
" DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \
" DENY_HULL_SHADER_ROOT_ACCESS )," \
-"DescriptorTable ( SRV(t0) ),"\
-"DescriptorTable ( SRV(t1) ),"\
-"DescriptorTable ( SRV(t2) ),"\
-"DescriptorTable ( SRV(t3) ),"\
-"DescriptorTable ( SRV(t4) ),"\
-"DescriptorTable ( SRV(t5) ),"\
-"DescriptorTable ( Sampler(s0) ),"\
-"DescriptorTable ( Sampler(s1) ),"\
+"DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),"\
+"DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL ),"\
+"DescriptorTable ( SRV(t2), visibility = SHADER_VISIBILITY_PIXEL ),"\
+"DescriptorTable ( SRV(t3), visibility = SHADER_VISIBILITY_PIXEL ),"\
+"DescriptorTable ( SRV(t4), visibility = SHADER_VISIBILITY_PIXEL ),"\
+"DescriptorTable ( SRV(t5), visibility = SHADER_VISIBILITY_PIXEL ),"\
+"DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL ),"\
+"DescriptorTable ( Sampler(s1), visibility = SHADER_VISIBILITY_PIXEL ),"\
"CBV(b0)," \
"CBV(b1, visibility = SHADER_VISIBILITY_VERTEX )"
@@ -393,4 +418,25 @@
"DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL ),"\
"DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL )"
+#define SkinTextureSamplerRS \
+"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 ),"\
+"CBV(b1, visibility = SHADER_VISIBILITY_VERTEX )"
+
+#define SkinDualTextureOneSamplerRS \
+"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 ),"\
+"CBV(b1, visibility = SHADER_VISIBILITY_VERTEX ),"\
+"DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL )"
+
#endif