From d8304a217875a2308b5771c1355560250de216a2 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 5 Feb 2021 14:54:29 +0100 Subject: [PATCH] Refactor material shaders generator to use modular features as extensions --- .../Features/MotionVectors.hlsl | 44 +++++ .../Features/Tessellation.hlsl | 11 +- .../Editor/MaterialTemplates/Particle.shader | 13 +- .../Editor/MaterialTemplates/Surface.shader | 173 ++++-------------- .../Materials/DecalMaterialShader.cpp | 17 +- .../Materials/DeferredMaterialShader.cpp | 13 +- .../Materials/ForwardMaterialShader.cpp | 12 +- .../Graphics/Materials/GUIMaterialShader.cpp | 18 +- .../Graphics/Materials/MaterialShader.cpp | 32 ++-- .../Graphics/Materials/MaterialShader.h | 21 ++- .../Materials/MaterialShaderFeatures.cpp | 15 +- .../Materials/MaterialShaderFeatures.h | 10 +- .../Materials/ParticleMaterialShader.cpp | 34 ++-- .../Materials/PostFxMaterialShader.cpp | 17 +- .../Materials/TerrainMaterialShader.cpp | 12 +- .../MaterialGenerator/MaterialGenerator.cpp | 2 + 16 files changed, 185 insertions(+), 259 deletions(-) create mode 100644 Content/Editor/MaterialTemplates/Features/MotionVectors.hlsl diff --git a/Content/Editor/MaterialTemplates/Features/MotionVectors.hlsl b/Content/Editor/MaterialTemplates/Features/MotionVectors.hlsl new file mode 100644 index 000000000..992eb6805 --- /dev/null +++ b/Content/Editor/MaterialTemplates/Features/MotionVectors.hlsl @@ -0,0 +1,44 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +@0// Motion Vectors: Defines +@1// Motion Vectors: Includes +@2// Motion Vectors: Constants +@3// Motion Vectors: Resources +@4// Motion Vectors: Utilities +@5// Motion Vectors: Shaders + +// Pixel Shader function for Motion Vectors Pass +META_PS(true, FEATURE_LEVEL_ES2) +float4 PS_MotionVectors(PixelInput input) : SV_Target0 +{ +#if USE_DITHERED_LOD_TRANSITION + // LOD masking + ClipLODTransition(input); +#endif + +#if MATERIAL_MASKED + // Perform per pixel clipping if material requries it + MaterialInput materialInput = GetMaterialInput(input); + Material material = GetMaterialPS(materialInput); + clip(material.Mask - MATERIAL_MASK_THRESHOLD); +#endif + + // Calculate this and previosu frame pixel locations in clip space + float4 prevClipPos = mul(float4(input.Geometry.PrevWorldPosition, 1), PrevViewProjectionMatrix); + float4 curClipPos = mul(float4(input.Geometry.WorldPosition, 1), ViewProjectionMatrix); + float2 prevHPos = prevClipPos.xy / prevClipPos.w; + float2 curHPos = curClipPos.xy / curClipPos.w; + + // Revert temporal jitter offset + prevHPos -= TemporalAAJitter.zw; + curHPos -= TemporalAAJitter.xy; + + // Clip Space -> UV Space + float2 vPosPrev = prevHPos.xy * 0.5f + 0.5f; + float2 vPosCur = curHPos.xy * 0.5f + 0.5f; + vPosPrev.y = 1.0 - vPosPrev.y; + vPosCur.y = 1.0 - vPosCur.y; + + // Calculate per-pixel motion vector + return float4(vPosCur - vPosPrev, 0, 1); +} diff --git a/Content/Editor/MaterialTemplates/Features/Tessellation.hlsl b/Content/Editor/MaterialTemplates/Features/Tessellation.hlsl index f2fc714ee..e2e0b54ea 100644 --- a/Content/Editor/MaterialTemplates/Features/Tessellation.hlsl +++ b/Content/Editor/MaterialTemplates/Features/Tessellation.hlsl @@ -32,14 +32,13 @@ struct TessalationDSToPS MaterialInput GetMaterialInput(TessalationDSToPS input) { - MaterialInput result = (MaterialInput)0; - result.SvPosition = input.Position; - GetGeometryMaterialInput(result, input.Geometry); - result.TwoSidedSign = WorldDeterminantSign; + MaterialInput output = GetGeometryMaterialInput(input.Geometry); + output.SvPosition = input.Position; + output.TwoSidedSign = WorldDeterminantSign; #if USE_CUSTOM_VERTEX_INTERPOLATORS - result.CustomVSToPS = input.CustomVSToPS; + output.CustomVSToPS = input.CustomVSToPS; #endif - return result; + return output; } struct TessalationPatch diff --git a/Content/Editor/MaterialTemplates/Particle.shader b/Content/Editor/MaterialTemplates/Particle.shader index a3befc24f..109fe668b 100644 --- a/Content/Editor/MaterialTemplates/Particle.shader +++ b/Content/Editor/MaterialTemplates/Particle.shader @@ -141,14 +141,11 @@ MaterialInput GetMaterialInput(PixelInput input) } // Gets the local to world transform matrix (supports instancing) -float4x4 GetInstanceTransform(ModelInput input) -{ - return WorldMatrix; -} -float4x4 GetInstanceTransform(MaterialInput input) -{ - return WorldMatrix; -} +#if USE_INSTANCING +#define GetInstanceTransform(input) float4x4(float4(input.InstanceTransform1.xyz, 0.0f), float4(input.InstanceTransform2.xyz, 0.0f), float4(input.InstanceTransform3.xyz, 0.0f), float4(input.InstanceOrigin.xyz, 1.0f)) +#else +#define GetInstanceTransform(input) WorldMatrix; +#endif // Removes the scale vector from the local to world transformation matrix (supports instancing) float3x3 RemoveScaleFromLocalToWorld(float3x3 localToWorld) diff --git a/Content/Editor/MaterialTemplates/Surface.shader b/Content/Editor/MaterialTemplates/Surface.shader index 8c09e7611..f3cc8499e 100644 --- a/Content/Editor/MaterialTemplates/Surface.shader +++ b/Content/Editor/MaterialTemplates/Surface.shader @@ -101,19 +101,21 @@ struct MaterialInput }; // Extracts geometry data to the material input -void GetGeometryMaterialInput(inout MaterialInput result, in GeometryData geometry) +MaterialInput GetGeometryMaterialInput(GeometryData geometry) { - result.WorldPosition = geometry.WorldPosition; - result.TexCoord = geometry.TexCoord; + MaterialInput output = (MaterialInput)0; + output.WorldPosition = geometry.WorldPosition; + output.TexCoord = geometry.TexCoord; #if USE_LIGHTMAP - result.LightmapUV = geometry.LightmapUV; + output.LightmapUV = geometry.LightmapUV; #endif #if USE_VERTEX_COLOR - result.VertexColor = geometry.VertexColor; + output.VertexColor = geometry.VertexColor; #endif - result.TBN = CalcTangentBasis(geometry.WorldNormal, geometry.WorldTangent); - result.InstanceOrigin = geometry.InstanceOrigin; - result.InstanceParams = geometry.InstanceParams; + output.TBN = CalcTangentBasis(geometry.WorldNormal, geometry.WorldTangent); + output.InstanceOrigin = geometry.InstanceOrigin; + output.InstanceParams = geometry.InstanceParams; + return output; } #if USE_TESSELLATION @@ -157,111 +159,23 @@ GeometryData InterpolateGeometry(GeometryData p0, float w0, GeometryData p1, flo #endif -MaterialInput GetMaterialInput(ModelInput input, VertexOutput output, float3 localNormal) -{ - MaterialInput result = (MaterialInput)0; - result.WorldPosition = output.Geometry.WorldPosition; - result.TexCoord = output.Geometry.TexCoord; -#if USE_LIGHTMAP - result.LightmapUV = output.Geometry.LightmapUV; -#endif -#if USE_VERTEX_COLOR - result.VertexColor = output.Geometry.VertexColor; -#endif - result.TBN = CalcTangentBasis(output.Geometry.WorldNormal, output.Geometry.WorldTangent); - result.TwoSidedSign = WorldDeterminantSign; - result.SvPosition = output.Position; - result.PreSkinnedPosition = input.Position.xyz; - result.PreSkinnedNormal = localNormal; -#if USE_INSTANCING - result.InstanceOrigin = input.InstanceOrigin.xyz; - result.InstanceParams = float2(input.InstanceOrigin.w, input.InstanceTransform1.w); - result.InstanceTransform1 = input.InstanceTransform1.xyz; - result.InstanceTransform2 = input.InstanceTransform2.xyz; - result.InstanceTransform3 = input.InstanceTransform3.xyz; -#else - result.InstanceOrigin = WorldMatrix[3].xyz; - result.InstanceParams = float2(PerInstanceRandom, LODDitherFactor); -#endif - return result; -} - -MaterialInput GetMaterialInput(VertexOutput output, float3 localPosition, float3 localNormal) -{ - MaterialInput result = (MaterialInput)0; - result.WorldPosition = output.Geometry.WorldPosition; - result.TexCoord = output.Geometry.TexCoord; -#if USE_LIGHTMAP - result.LightmapUV = output.Geometry.LightmapUV; -#endif -#if USE_VERTEX_COLOR - result.VertexColor = output.Geometry.VertexColor; -#endif - result.TBN = CalcTangentBasis(output.Geometry.WorldNormal, output.Geometry.WorldTangent); - result.TwoSidedSign = WorldDeterminantSign; - result.InstanceOrigin = WorldMatrix[3].xyz; - result.InstanceParams = float2(PerInstanceRandom, LODDitherFactor); - result.SvPosition = output.Position; - result.PreSkinnedPosition = localPosition; - result.PreSkinnedNormal = localNormal; - return result; -} - MaterialInput GetMaterialInput(PixelInput input) { - MaterialInput result = (MaterialInput)0; - result.WorldPosition = input.Geometry.WorldPosition; - result.TexCoord = input.Geometry.TexCoord; -#if USE_LIGHTMAP - result.LightmapUV = input.Geometry.LightmapUV; -#endif -#if USE_VERTEX_COLOR - result.VertexColor = input.Geometry.VertexColor; -#endif - result.TBN = CalcTangentBasis(input.Geometry.WorldNormal, input.Geometry.WorldTangent); - result.TwoSidedSign = WorldDeterminantSign * (input.IsFrontFace ? 1.0 : -1.0); - result.InstanceOrigin = input.Geometry.InstanceOrigin; - result.InstanceParams = input.Geometry.InstanceParams; - result.SvPosition = input.Position; + MaterialInput output = GetGeometryMaterialInput(input.Geometry); + output.TwoSidedSign = WorldDeterminantSign * (input.IsFrontFace ? 1.0 : -1.0); + output.SvPosition = input.Position; #if USE_CUSTOM_VERTEX_INTERPOLATORS - result.CustomVSToPS = input.CustomVSToPS; + output.CustomVSToPS = input.CustomVSToPS; #endif - return result; + return output; } // Gets the local to world transform matrix (supports instancing) -float4x4 GetInstanceTransform(ModelInput input) -{ #if USE_INSTANCING - return float4x4(float4(input.InstanceTransform1.xyz, 0.0f), float4(input.InstanceTransform2.xyz, 0.0f), float4(input.InstanceTransform3.xyz, 0.0f), float4(input.InstanceOrigin.xyz, 1.0f)); +#define GetInstanceTransform(input) float4x4(float4(input.InstanceTransform1.xyz, 0.0f), float4(input.InstanceTransform2.xyz, 0.0f), float4(input.InstanceTransform3.xyz, 0.0f), float4(input.InstanceOrigin.xyz, 1.0f)) #else - return WorldMatrix; +#define GetInstanceTransform(input) WorldMatrix; #endif -} -float4x4 GetInstanceTransform(ModelInput_Skinned input) -{ -#if USE_INSTANCING - return float4x4(float4(input.InstanceTransform1.xyz, 0.0f), float4(input.InstanceTransform2.xyz, 0.0f), float4(input.InstanceTransform3.xyz, 0.0f), float4(input.InstanceOrigin.xyz, 1.0f)); -#else - return WorldMatrix; -#endif -} -float4x4 GetInstanceTransform(ModelInput_PosOnly input) -{ -#if USE_INSTANCING - return float4x4(float4(input.InstanceTransform1.xyz, 0.0f), float4(input.InstanceTransform2.xyz, 0.0f), float4(input.InstanceTransform3.xyz, 0.0f), float4(input.InstanceOrigin.xyz, 1.0f)); -#else - return WorldMatrix; -#endif -} -float4x4 GetInstanceTransform(MaterialInput input) -{ -#if USE_INSTANCING - return float4x4(float4(input.InstanceTransform1.xyz, 0.0f), float4(input.InstanceTransform2.xyz, 0.0f), float4(input.InstanceTransform3.xyz, 0.0f), float4(input.InstanceOrigin.xyz, 1.0f)); -#else - return WorldMatrix; -#endif -} // Removes the scale vector from the local to world transformation matrix (supports instancing) float3x3 RemoveScaleFromLocalToWorld(float3x3 localToWorld) @@ -453,7 +367,16 @@ VertexOutput VS(ModelInput input) // Get material input params if need to evaluate any material property #if USE_POSITION_OFFSET || USE_TESSELLATION || USE_CUSTOM_VERTEX_INTERPOLATORS - MaterialInput materialInput = GetMaterialInput(input, output, tangentToLocal[2].xyz); + MaterialInput materialInput = GetGeometryMaterialInput(output.Geometry); + materialInput.TwoSidedSign = WorldDeterminantSign; + materialInput.SvPosition = output.Position; + materialInput.PreSkinnedPosition = input.Position.xyz; + materialInput.PreSkinnedNormal = tangentToLocal[2].xyz; +#if USE_INSTANCING + materialInput.InstanceTransform1 = input.InstanceTransform1.xyz; + materialInput.InstanceTransform2 = input.InstanceTransform2.xyz; + materialInput.InstanceTransform3 = input.InstanceTransform3.xyz; +#endif Material material = GetMaterialVS(materialInput); #endif @@ -626,7 +549,11 @@ VertexOutput VS_Skinned(ModelInput_Skinned input) // Get material input params if need to evaluate any material property #if USE_POSITION_OFFSET || USE_TESSELLATION || USE_CUSTOM_VERTEX_INTERPOLATORS - MaterialInput materialInput = GetMaterialInput(output, input.Position.xyz, tangentToLocal[2].xyz); + MaterialInput materialInput = GetGeometryMaterialInput(output.Geometry); + materialInput.TwoSidedSign = WorldDeterminantSign; + materialInput.SvPosition = output.Position; + materialInput.PreSkinnedPosition = input.Position.xyz; + materialInput.PreSkinnedNormal = tangentToLocal[2].xyz; Material material = GetMaterialVS(materialInput); #endif @@ -699,40 +626,4 @@ void PS_Depth(PixelInput input #endif } -// Pixel Shader function for Motion Vectors Pass -META_PS(USE_DEFERRED, FEATURE_LEVEL_ES2) -float4 PS_MotionVectors(PixelInput input) : SV_Target0 -{ -#if USE_DITHERED_LOD_TRANSITION - // LOD masking - ClipLODTransition(input); -#endif - -#if MATERIAL_MASKED - // Perform per pixel clipping if material requries it - MaterialInput materialInput = GetMaterialInput(input); - Material material = GetMaterialPS(materialInput); - clip(material.Mask - MATERIAL_MASK_THRESHOLD); -#endif - - // Calculate this and previosu frame pixel locations in clip space - float4 prevClipPos = mul(float4(input.Geometry.PrevWorldPosition, 1), PrevViewProjectionMatrix); - float4 curClipPos = mul(float4(input.Geometry.WorldPosition, 1), ViewProjectionMatrix); - float2 prevHPos = prevClipPos.xy / prevClipPos.w; - float2 curHPos = curClipPos.xy / curClipPos.w; - - // Revert temporal jitter offset - prevHPos -= TemporalAAJitter.zw; - curHPos -= TemporalAAJitter.xy; - - // Clip Space -> UV Space - float2 vPosPrev = prevHPos.xy * 0.5f + 0.5f; - float2 vPosCur = curHPos.xy * 0.5f + 0.5f; - vPosPrev.y = 1.0 - vPosPrev.y; - vPosCur.y = 1.0 - vPosCur.y; - - // Calculate per-pixel motion vector - return float4(vPosCur - vPosPrev, 0, 1); -} - @9 diff --git a/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp b/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp index 27e9c7b38..e141996dc 100644 --- a/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp @@ -37,14 +37,16 @@ void DecalMaterialShader::Bind(BindParameters& params) auto context = params.GPUContext; auto& view = params.RenderContext.View; auto& drawCall = *params.FirstDrawCall; - const auto cb0 = _shader->GetCB(0); - const bool hasCb0 = cb0->GetSize() != 0; + byte* cb = _cbData.Get(); + auto materialData = reinterpret_cast(cb); + cb += sizeof(DecalMaterialShaderData); + int32 srv = 0; const bool isCameraInside = OrientedBoundingBox(Vector3::Half, params.FirstDrawCall->World).Contains(view.Position) == ContainmentType::Contains; // Setup parameters MaterialParameter::BindMeta bindMeta; bindMeta.Context = context; - bindMeta.Constants = hasCb0 ? _cb0Data.Get() + sizeof(DecalMaterialShaderData) : nullptr; + bindMeta.Constants = cb; bindMeta.Input = nullptr; bindMeta.Buffers = nullptr; bindMeta.CanSampleDepth = true; @@ -55,10 +57,7 @@ void DecalMaterialShader::Bind(BindParameters& params) context->BindSR(0, GET_TEXTURE_VIEW_SAFE(params.RenderContext.Buffers->DepthBuffer)); // Setup material constants data - if (hasCb0) { - const auto materialData = reinterpret_cast(_cb0Data.Get()); - Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix); Matrix::Transpose(drawCall.World, materialData->WorldMatrix); Matrix::Transpose(view.View, materialData->ViewMatrix); @@ -85,10 +84,10 @@ void DecalMaterialShader::Bind(BindParameters& params) } // Bind constants - if (hasCb0) + if (_cb) { - context->UpdateCB(cb0, _cb0Data.Get()); - context->BindCB(0, cb0); + context->UpdateCB(_cb, _cbData.Get()); + context->BindCB(0, _cb); } // Bind pipeline diff --git a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp index 4afbdd60d..d8b40c3a6 100644 --- a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp @@ -61,10 +61,7 @@ void DeferredMaterialShader::Bind(BindParameters& params) auto context = params.GPUContext; auto& view = params.RenderContext.View; auto& drawCall = *params.FirstDrawCall; - const auto cb0 = _shader->GetCB(0); - const bool hasCb0 = cb0 && cb0->GetSize() != 0; - ASSERT(hasCb0 && "TODO: fix it"); // TODO: always make cb pointer valid even if cb is missing - byte* cb = _cb0Data.Get(); + byte* cb = _cbData.Get(); auto materialData = reinterpret_cast(cb); cb += sizeof(DeferredMaterialShaderData); int32 srv = 2; @@ -82,8 +79,6 @@ void DeferredMaterialShader::Bind(BindParameters& params) bindMeta.CanSampleGBuffer = false; MaterialParams::Bind(params.ParamsLink, bindMeta); - // Setup material constants data - if (hasCb0) { Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix); Matrix::Transpose(drawCall.World, materialData->WorldMatrix); @@ -131,10 +126,10 @@ void DeferredMaterialShader::Bind(BindParameters& params) } // Bind constants - if (hasCb0) + if (_cb) { - context->UpdateCB(cb0, _cb0Data.Get()); - context->BindCB(0, cb0); + context->UpdateCB(_cb, _cbData.Get()); + context->BindCB(0, _cb); } // Select pipeline state based on current pass and render mode diff --git a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp index bf9f566ef..addd7e96a 100644 --- a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp @@ -58,10 +58,7 @@ void ForwardMaterialShader::Bind(BindParameters& params) auto context = params.GPUContext; auto& view = params.RenderContext.View; auto& drawCall = *params.FirstDrawCall; - const auto cb0 = _shader->GetCB(0); - const bool hasCb0 = cb0 && cb0->GetSize() != 0; - ASSERT(hasCb0 && "TODO: fix it"); // TODO: always make cb pointer valid even if cb is missing - byte* cb = _cb0Data.Get(); + byte* cb = _cbData.Get(); auto materialData = reinterpret_cast(cb); cb += sizeof(ForwardMaterialShaderData); int32 srv = 2; @@ -89,7 +86,6 @@ void ForwardMaterialShader::Bind(BindParameters& params) } // Setup material constants data - if (hasCb0) { Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix); Matrix::Transpose(drawCall.World, materialData->WorldMatrix); @@ -121,10 +117,10 @@ void ForwardMaterialShader::Bind(BindParameters& params) } // Bind constants - if (hasCb0) + if (_cb) { - context->UpdateCB(cb0, _cb0Data.Get()); - context->BindCB(0, cb0); + context->UpdateCB(_cb, _cbData.Get()); + context->BindCB(0, _cb); } // Select pipeline state based on current pass and render mode diff --git a/Source/Engine/Graphics/Materials/GUIMaterialShader.cpp b/Source/Engine/Graphics/Materials/GUIMaterialShader.cpp index 23b327a1b..9e1d9ea21 100644 --- a/Source/Engine/Graphics/Materials/GUIMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/GUIMaterialShader.cpp @@ -28,15 +28,16 @@ void GUIMaterialShader::Bind(BindParameters& params) { // Prepare auto context = params.GPUContext; - auto& view = params.RenderContext.View; - const auto cb0 = _shader->GetCB(0); - const bool hasCb0 = cb0->GetSize() != 0; + byte* cb = _cbData.Get(); + auto materialData = reinterpret_cast(cb); + cb += sizeof(GUIMaterialShaderData); + int32 srv = 0; const auto ps = context->IsDepthBufferBinded() ? _cache.Depth : _cache.NoDepth; // Setup parameters MaterialParameter::BindMeta bindMeta; bindMeta.Context = context; - bindMeta.Constants = hasCb0 ? _cb0Data.Get() + sizeof(GUIMaterialShaderData) : nullptr; + bindMeta.Constants = cb; bindMeta.Input = nullptr; bindMeta.Buffers = nullptr; bindMeta.CanSampleDepth = false; @@ -44,10 +45,7 @@ void GUIMaterialShader::Bind(BindParameters& params) MaterialParams::Bind(params.ParamsLink, bindMeta); // Setup material constants data - if (hasCb0) { - auto materialData = reinterpret_cast(_cb0Data.Get()); - const auto viewProjectionMatrix = (Matrix*)params.CustomData; Matrix::Transpose(*viewProjectionMatrix, materialData->ViewProjectionMatrix); Matrix::Transpose(Matrix::Identity, materialData->WorldMatrix); @@ -62,10 +60,10 @@ void GUIMaterialShader::Bind(BindParameters& params) } // Bind constants - if (hasCb0) + if (_cb) { - context->UpdateCB(cb0, _cb0Data.Get()); - context->BindCB(0, cb0); + context->UpdateCB(_cb, _cbData.Get()); + context->BindCB(0, _cb); } // Bind pipeline diff --git a/Source/Engine/Graphics/Materials/MaterialShader.cpp b/Source/Engine/Graphics/Materials/MaterialShader.cpp index ee1cf22c4..2d7998b8a 100644 --- a/Source/Engine/Graphics/Materials/MaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/MaterialShader.cpp @@ -14,18 +14,15 @@ #include "GUIMaterialShader.h" #include "TerrainMaterialShader.h" #include "ParticleMaterialShader.h" +//#include "DeformableMaterialShader.h" -GPUPipelineState* MaterialShader::PipelineStateCache::GetPS(CullMode mode, bool wireframe) +GPUPipelineState* MaterialShader::PipelineStateCache::InitPS(CullMode mode, bool wireframe) { - const int32 index = static_cast(mode) + (wireframe ? 3 : 0); - if (PS[index]) - return PS[index]; - Desc.CullMode = mode; Desc.Wireframe = wireframe; - PS[index] = GPUDevice::Instance->CreatePipelineState(); - PS[index]->Init(Desc); - return PS[index]; + auto ps = GPUDevice::Instance->CreatePipelineState(); + ps->Init(Desc); + return ps; } MaterialShader::MaterialShader(const String& name) @@ -65,6 +62,9 @@ MaterialShader* MaterialShader::Create(const String& name, MemoryReadStream& sha case MaterialDomain::Particle: material = New(name); break; + /*case MaterialDomain::Deformable: + material = New(name); + break;*/ default: LOG(Fatal, "Unknown material type."); return nullptr; @@ -138,10 +138,17 @@ bool MaterialShader::Load(MemoryReadStream& shaderCacheStream, const MaterialInf } // Init memory for a constant buffer - const auto cb0 = _shader->GetCB(0); - if (cb0) + _cb = _shader->GetCB(0); + if (_cb) { - _cb0Data.Resize(cb0->GetSize(), false); + int32 cbSize = _cb->GetSize(); + if (cbSize == 0) + { + // Handle unused constant buffer (eg. postFx returning solid color) + cbSize = 1024; + _cb = nullptr; + } + _cbData.Resize(cbSize, false); } // Initialize the material based on type (create pipeline states and setup) @@ -157,6 +164,7 @@ bool MaterialShader::Load(MemoryReadStream& shaderCacheStream, const MaterialInf void MaterialShader::Unload() { _isLoaded = false; - _cb0Data.Resize(0, false); + _cb = nullptr; + _cbData.Resize(0, false); _shader->ReleaseGPU(); } diff --git a/Source/Engine/Graphics/Materials/MaterialShader.h b/Source/Engine/Graphics/Materials/MaterialShader.h index baa463d3f..102ac4d41 100644 --- a/Source/Engine/Graphics/Materials/MaterialShader.h +++ b/Source/Engine/Graphics/Materials/MaterialShader.h @@ -9,10 +9,11 @@ /// /// Current materials shader version. /// -#define MATERIAL_GRAPH_VERSION 146 +#define MATERIAL_GRAPH_VERSION 147 class Material; class GPUShader; +class GPUConstantBuffer; class MemoryReadStream; /// @@ -37,7 +38,16 @@ protected: Desc = desc; } - GPUPipelineState* GetPS(CullMode mode, bool wireframe); + GPUPipelineState* GetPS(CullMode mode, bool wireframe) + { + const int32 index = static_cast(mode) + (wireframe ? 3 : 0); + auto ps = PS[index]; + if (!ps) + PS[index] = ps = InitPS(mode, wireframe); + return ps; + } + + GPUPipelineState* InitPS(CullMode mode, bool wireframe); void Release() { @@ -52,7 +62,8 @@ protected: bool _isLoaded; GPUShader* _shader; - Array _cb0Data; + GPUConstantBuffer* _cb; + Array _cbData; MaterialInfo _info; protected: @@ -89,10 +100,8 @@ public: /// The created and loaded material or null if failed. static MaterialShader* CreateDummy(MemoryReadStream& shaderCacheStream, const MaterialInfo& info); -public: - /// - /// Clear loaded data + /// Clears the loaded data. /// virtual void Unload(); diff --git a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp index 2a6a97ffa..abc28a0de 100644 --- a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp +++ b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp @@ -158,36 +158,31 @@ bool LightmapFeature::Bind(MaterialShader::BindParameters& params, byte*& cb, in void ForwardShadingFeature::Generate(GeneratorData& data) { data.Template = TEXT("Features/ForwardShading.hlsl"); - data.ConstantsSize = sizeof(Data); - data.ResourcesCount = SRVs; } void DeferredShadingFeature::Generate(GeneratorData& data) { data.Template = TEXT("Features/DeferredShading.hlsl"); - data.ConstantsSize = 0; - data.ResourcesCount = 0; } void TessellationFeature::Generate(GeneratorData& data) { data.Template = TEXT("Features/Tessellation.hlsl"); - data.ConstantsSize = 0; - data.ResourcesCount = 0; } void LightmapFeature::Generate(GeneratorData& data) { data.Template = TEXT("Features/Lightmap.hlsl"); - data.ConstantsSize = sizeof(Data); - data.ResourcesCount = SRVs; } void DistortionFeature::Generate(GeneratorData& data) { data.Template = TEXT("Features/Distortion.hlsl"); - data.ConstantsSize = 0; - data.ResourcesCount = 0; +} + +void MotionVectorsFeature::Generate(GeneratorData& data) +{ + data.Template = TEXT("Features/MotionVectors.hlsl"); } #endif diff --git a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.h b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.h index 3128a688d..a70d9ada8 100644 --- a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.h +++ b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.h @@ -12,8 +12,6 @@ struct MaterialShaderFeature struct GeneratorData { const Char* Template; - int32 ConstantsSize; - int32 ResourcesCount; }; #endif; }; @@ -82,3 +80,11 @@ struct DistortionFeature : MaterialShaderFeature static void Generate(GeneratorData& data); #endif }; + +// Material shader feature that adds motion vectors rendering pass. +struct MotionVectorsFeature : MaterialShaderFeature +{ +#if USE_EDITOR + static void Generate(GeneratorData& data); +#endif +}; diff --git a/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp b/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp index 8ee49ae78..eda7fff22 100644 --- a/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp @@ -60,10 +60,7 @@ void ParticleMaterialShader::Bind(BindParameters& params) auto& view = params.RenderContext.View; auto& drawCall = *params.FirstDrawCall; const uint32 sortedIndicesOffset = drawCall.Particle.Module->SortedIndicesOffset; - const auto cb0 = _shader->GetCB(0); - const bool hasCb0 = cb0->GetSize() != 0; - ASSERT(hasCb0 && "TODO: fix it"); // TODO: always make cb pointer valid even if cb is missing - byte* cb = _cb0Data.Get(); + byte* cb = _cbData.Get(); auto materialData = reinterpret_cast(cb); cb += sizeof(ParticleMaterialShaderData); int32 srv = 2; @@ -86,7 +83,6 @@ void ParticleMaterialShader::Bind(BindParameters& params) context->BindSR(1, drawCall.Particle.Particles->GPU.SortedIndices ? drawCall.Particle.Particles->GPU.SortedIndices->View() : nullptr); // Setup particles attributes binding info - if (hasCb0) { const auto& p = *params.ParamsLink->This; for (int32 i = 0; i < p.Count(); i++) @@ -129,19 +125,16 @@ void ParticleMaterialShader::Bind(BindParameters& params) static StringView ParticleRibbonTwist(TEXT("RibbonTwist")); static StringView ParticleRibbonFacingVector(TEXT("RibbonFacingVector")); - if (hasCb0) - { - materialData->RibbonWidthOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRibbonWidth, ParticleAttribute::ValueTypes::Float, -1); - materialData->RibbonTwistOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRibbonTwist, ParticleAttribute::ValueTypes::Float, -1); - materialData->RibbonFacingVectorOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRibbonFacingVector, ParticleAttribute::ValueTypes::Vector3, -1); + materialData->RibbonWidthOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRibbonWidth, ParticleAttribute::ValueTypes::Float, -1); + materialData->RibbonTwistOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRibbonTwist, ParticleAttribute::ValueTypes::Float, -1); + materialData->RibbonFacingVectorOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRibbonFacingVector, ParticleAttribute::ValueTypes::Vector3, -1); - materialData->RibbonUVTilingDistance = drawCall.Particle.Ribbon.UVTilingDistance; - materialData->RibbonUVScale.X = drawCall.Particle.Ribbon.UVScaleX; - materialData->RibbonUVScale.Y = drawCall.Particle.Ribbon.UVScaleY; - materialData->RibbonUVOffset.X = drawCall.Particle.Ribbon.UVOffsetX; - materialData->RibbonUVOffset.Y = drawCall.Particle.Ribbon.UVOffsetY; - materialData->RibbonSegmentCount = drawCall.Particle.Ribbon.SegmentCount; - } + materialData->RibbonUVTilingDistance = drawCall.Particle.Ribbon.UVTilingDistance; + materialData->RibbonUVScale.X = drawCall.Particle.Ribbon.UVScaleX; + materialData->RibbonUVScale.Y = drawCall.Particle.Ribbon.UVScaleY; + materialData->RibbonUVOffset.X = drawCall.Particle.Ribbon.UVOffsetX; + materialData->RibbonUVOffset.Y = drawCall.Particle.Ribbon.UVOffsetY; + materialData->RibbonSegmentCount = drawCall.Particle.Ribbon.SegmentCount; if (drawCall.Particle.Ribbon.SegmentDistances) context->BindSR(1, drawCall.Particle.Ribbon.SegmentDistances->View()); @@ -153,7 +146,6 @@ void ParticleMaterialShader::Bind(BindParameters& params) GPUPipelineState* state = psCache->GetPS(cullMode, wireframe); // Setup material constants data - if (hasCb0) { static StringView ParticlePosition(TEXT("Position")); static StringView ParticleSpriteSize(TEXT("SpriteSize")); @@ -188,10 +180,10 @@ void ParticleMaterialShader::Bind(BindParameters& params) } // Bind constants - if (hasCb0) + if (_cb) { - context->UpdateCB(cb0, _cb0Data.Get()); - context->BindCB(0, cb0); + context->UpdateCB(_cb, _cbData.Get()); + context->BindCB(0, _cb); } // Bind pipeline diff --git a/Source/Engine/Graphics/Materials/PostFxMaterialShader.cpp b/Source/Engine/Graphics/Materials/PostFxMaterialShader.cpp index 8be86a4ac..890275f68 100644 --- a/Source/Engine/Graphics/Materials/PostFxMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/PostFxMaterialShader.cpp @@ -26,13 +26,15 @@ void PostFxMaterialShader::Bind(BindParameters& params) // Prepare auto context = params.GPUContext; auto& view = params.RenderContext.View; - const auto cb0 = _shader->GetCB(0); - const bool hasCb0 = cb0->GetSize() != 0; + byte* cb = _cbData.Get(); + auto materialData = reinterpret_cast(cb); + cb += sizeof(PostFxMaterialShaderData); + int32 srv = 0; // Setup parameters MaterialParameter::BindMeta bindMeta; bindMeta.Context = context; - bindMeta.Constants = hasCb0 ? _cb0Data.Get() + sizeof(PostFxMaterialShaderData) : nullptr; + bindMeta.Constants = cb; bindMeta.Input = params.Input; bindMeta.Buffers = params.RenderContext.Buffers; bindMeta.CanSampleDepth = true; @@ -40,10 +42,7 @@ void PostFxMaterialShader::Bind(BindParameters& params) MaterialParams::Bind(params.ParamsLink, bindMeta); // Setup material constants data - if (hasCb0) { - const auto materialData = reinterpret_cast(_cb0Data.Get()); - Matrix::Transpose(view.View, materialData->ViewMatrix); materialData->ViewPos = view.Position; materialData->ViewFar = view.Far; @@ -55,10 +54,10 @@ void PostFxMaterialShader::Bind(BindParameters& params) } // Bind constants - if (hasCb0) + if (_cb) { - context->UpdateCB(cb0, _cb0Data.Get()); - context->BindCB(0, cb0); + context->UpdateCB(_cb, _cbData.Get()); + context->BindCB(0, _cb); } // Bind pipeline diff --git a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp index 89a96d902..80988e405 100644 --- a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp @@ -54,10 +54,7 @@ void TerrainMaterialShader::Bind(BindParameters& params) auto context = params.GPUContext; auto& view = params.RenderContext.View; auto& drawCall = *params.FirstDrawCall; - const auto cb0 = _shader->GetCB(0); - const bool hasCb0 = cb0->GetSize() != 0; - ASSERT(hasCb0 && "TODO: fix it"); // TODO: always make cb pointer valid even if cb is missing - byte* cb = _cb0Data.Get(); + byte* cb = _cbData.Get(); auto materialData = reinterpret_cast(cb); cb += sizeof(TerrainMaterialShaderData); int32 srv = 3; @@ -76,7 +73,6 @@ void TerrainMaterialShader::Bind(BindParameters& params) MaterialParams::Bind(params.ParamsLink, bindMeta); // Setup material constants data - if (hasCb0) { Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix); Matrix::Transpose(drawCall.World, materialData->WorldMatrix); @@ -114,10 +110,10 @@ void TerrainMaterialShader::Bind(BindParameters& params) context->BindSR(2, splatmap1); // Bind constants - if (hasCb0) + if (_cb) { - context->UpdateCB(cb0, _cb0Data.Get()); - context->BindCB(0, cb0); + context->UpdateCB(_cb, _cbData.Get()); + context->BindCB(0, _cb); } // Select pipeline state based on current pass and render mode diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp index fb0585f83..2f54efe82 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp @@ -185,6 +185,8 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo if (materialInfo.TessellationMode != TessellationMethod::None) ADD_FEATURE(TessellationFeature); if (materialInfo.BlendMode == MaterialBlendMode::Opaque) + ADD_FEATURE(MotionVectorsFeature); + if (materialInfo.BlendMode == MaterialBlendMode::Opaque) ADD_FEATURE(LightmapFeature); if (materialInfo.BlendMode == MaterialBlendMode::Opaque) ADD_FEATURE(DeferredShadingFeature);