diff --git a/Source/Engine/Content/Assets/Material.cpp b/Source/Engine/Content/Assets/Material.cpp
index b40e1e9c0..571e46243 100644
--- a/Source/Engine/Content/Assets/Material.cpp
+++ b/Source/Engine/Content/Assets/Material.cpp
@@ -61,9 +61,9 @@ bool Material::CanUseLightmap() const
return _materialShader && _materialShader->CanUseLightmap();
}
-bool Material::CanUseInstancing() const
+bool Material::CanUseInstancing(InstancingHandler& handler) const
{
- return _materialShader && _materialShader->CanUseInstancing();
+ return _materialShader && _materialShader->CanUseInstancing(handler);
}
void Material::Bind(BindParameters& params)
diff --git a/Source/Engine/Content/Assets/Material.h b/Source/Engine/Content/Assets/Material.h
index bdaba7abb..0a9ad1dbc 100644
--- a/Source/Engine/Content/Assets/Material.h
+++ b/Source/Engine/Content/Assets/Material.h
@@ -48,7 +48,7 @@ public:
bool IsReady() const override;
DrawPass GetDrawModes() const override;
bool CanUseLightmap() const override;
- bool CanUseInstancing() const override;
+ bool CanUseInstancing(InstancingHandler& handler) const override;
void Bind(BindParameters& params) override;
// [ShaderAssetBase]
diff --git a/Source/Engine/Content/Assets/MaterialInstance.cpp b/Source/Engine/Content/Assets/MaterialInstance.cpp
index ace2fcee9..0678f9992 100644
--- a/Source/Engine/Content/Assets/MaterialInstance.cpp
+++ b/Source/Engine/Content/Assets/MaterialInstance.cpp
@@ -167,9 +167,9 @@ bool MaterialInstance::CanUseLightmap() const
return _baseMaterial && _baseMaterial->CanUseLightmap();
}
-bool MaterialInstance::CanUseInstancing() const
+bool MaterialInstance::CanUseInstancing(InstancingHandler& handler) const
{
- return _baseMaterial && _baseMaterial->CanUseInstancing();
+ return _baseMaterial && _baseMaterial->CanUseInstancing(handler);
}
void MaterialInstance::Bind(BindParameters& params)
diff --git a/Source/Engine/Content/Assets/MaterialInstance.h b/Source/Engine/Content/Assets/MaterialInstance.h
index 9fe92e39c..3cf74db03 100644
--- a/Source/Engine/Content/Assets/MaterialInstance.h
+++ b/Source/Engine/Content/Assets/MaterialInstance.h
@@ -64,7 +64,7 @@ public:
bool IsReady() const override;
DrawPass GetDrawModes() const override;
bool CanUseLightmap() const override;
- bool CanUseInstancing() const override;
+ bool CanUseInstancing(InstancingHandler& handler) const override;
void Bind(BindParameters& params) override;
protected:
diff --git a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp
index 049484459..5a460079d 100644
--- a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp
+++ b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp
@@ -5,6 +5,7 @@
#include "Engine/Graphics/RenderBuffers.h"
#include "Engine/Graphics/RenderView.h"
#include "Engine/Renderer/DrawCall.h"
+#include "Engine/Renderer/RenderList.h"
#include "Engine/Level/Scene/Lightmap.h"
#include "Engine/Graphics/GPUContext.h"
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
@@ -48,8 +49,9 @@ bool DeferredMaterialShader::CanUseLightmap() const
return true;
}
-bool DeferredMaterialShader::CanUseInstancing() const
+bool DeferredMaterialShader::CanUseInstancing(InstancingHandler& handler) const
{
+ handler = { SurfaceDrawCallHandler::GetHash, SurfaceDrawCallHandler::CanBatch, SurfaceDrawCallHandler::WriteDrawCall, };
return true;
}
@@ -79,7 +81,7 @@ void DeferredMaterialShader::Bind(BindParameters& params)
Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix);
Matrix::Transpose(drawCall.World, materialData->WorldMatrix);
Matrix::Transpose(view.View, materialData->ViewMatrix);
- Matrix::Transpose(drawCall.PrevWorld, materialData->PrevWorldMatrix);
+ Matrix::Transpose(drawCall.Surface.PrevWorld, materialData->PrevWorldMatrix);
Matrix::Transpose(view.PrevViewProjection, materialData->PrevViewProjectionMatrix);
materialData->ViewPos = view.Position;
@@ -100,40 +102,40 @@ void DeferredMaterialShader::Bind(BindParameters& params)
materialData->WorldInvScale = worldInvScale;
materialData->WorldDeterminantSign = drawCall.WorldDeterminantSign;
- materialData->LODDitherFactor = drawCall.LODDitherFactor;
+ materialData->LODDitherFactor = drawCall.Surface.LODDitherFactor;
materialData->PerInstanceRandom = drawCall.PerInstanceRandom;
materialData->TemporalAAJitter = view.TemporalAAJitter;
- materialData->GeometrySize = drawCall.GeometrySize;
+ materialData->GeometrySize = drawCall.Surface.GeometrySize;
}
const bool useLightmap = view.Flags & ViewFlags::GI
#if USE_EDITOR
&& EnableLightmapsUsage
#endif
- && drawCall.Lightmap != nullptr;
+ && drawCall.Surface.Lightmap != nullptr;
if (useLightmap)
{
// Bind lightmap textures
GPUTexture *lightmap0, *lightmap1, *lightmap2;
- drawCall.Lightmap->GetTextures(&lightmap0, &lightmap1, &lightmap2);
+ drawCall.Surface.Lightmap->GetTextures(&lightmap0, &lightmap1, &lightmap2);
context->BindSR(0, lightmap0);
context->BindSR(1, lightmap1);
context->BindSR(2, lightmap2);
// Set lightmap data
- materialData->LightmapArea = drawCall.LightmapUVsArea;
+ materialData->LightmapArea = drawCall.Surface.LightmapUVsArea;
}
// Check if is using mesh skinning
- const bool useSkinning = drawCall.Skinning != nullptr;
+ const bool useSkinning = drawCall.Surface.Skinning != nullptr;
bool perBoneMotionBlur = false;
if (useSkinning)
{
// Bind skinning buffer
- ASSERT(drawCall.Skinning->IsReady());
- context->BindSR(0, drawCall.Skinning->BoneMatrices->View());
- if (drawCall.Skinning->PrevBoneMatrices && drawCall.Skinning->PrevBoneMatrices->IsAllocated())
+ ASSERT(drawCall.Surface.Skinning->IsReady());
+ context->BindSR(0, drawCall.Surface.Skinning->BoneMatrices->View());
+ if (drawCall.Surface.Skinning->PrevBoneMatrices && drawCall.Surface.Skinning->PrevBoneMatrices->IsAllocated())
{
- context->BindSR(1, drawCall.Skinning->PrevBoneMatrices->View());
+ context->BindSR(1, drawCall.Surface.Skinning->PrevBoneMatrices->View());
perBoneMotionBlur = true;
}
}
@@ -152,7 +154,7 @@ void DeferredMaterialShader::Bind(BindParameters& params)
if (IsRunningRadiancePass)
cullMode = CullMode::TwoSided;
#endif
- if (cullMode != CullMode::TwoSided && drawCall.IsNegativeScale())
+ if (cullMode != CullMode::TwoSided && drawCall.WorldDeterminantSign < 0)
{
// Invert culling when scale is negative
if (cullMode == CullMode::Normal)
diff --git a/Source/Engine/Graphics/Materials/DeferredMaterialShader.h b/Source/Engine/Graphics/Materials/DeferredMaterialShader.h
index f8df968c9..537547c6a 100644
--- a/Source/Engine/Graphics/Materials/DeferredMaterialShader.h
+++ b/Source/Engine/Graphics/Materials/DeferredMaterialShader.h
@@ -66,7 +66,7 @@ public:
// [MaterialShader]
DrawPass GetDrawModes() const override;
bool CanUseLightmap() const override;
- bool CanUseInstancing() const override;
+ bool CanUseInstancing(InstancingHandler& handler) const override;
void Bind(BindParameters& params) override;
void Unload() override;
diff --git a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp
index 863af34e1..39e39a7d4 100644
--- a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp
+++ b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp
@@ -10,6 +10,7 @@
#include "Engine/Renderer/DepthOfFieldPass.h"
#include "Engine/Renderer/DrawCall.h"
#include "Engine/Renderer/ShadowsPass.h"
+#include "Engine/Renderer/RenderList.h"
#if USE_EDITOR
#include "Engine/Renderer/Lightmaps.h"
#endif
@@ -54,8 +55,9 @@ DrawPass ForwardMaterialShader::GetDrawModes() const
return _drawModes;
}
-bool ForwardMaterialShader::CanUseInstancing() const
+bool ForwardMaterialShader::CanUseInstancing(InstancingHandler& handler) const
{
+ handler = { SurfaceDrawCallHandler::GetHash, SurfaceDrawCallHandler::CanBatch, SurfaceDrawCallHandler::WriteDrawCall, };
return true;
}
@@ -82,12 +84,12 @@ void ForwardMaterialShader::Bind(BindParameters& params)
MaterialParams::Bind(params.ParamsLink, bindMeta);
// Check if is using mesh skinning
- const bool useSkinning = drawCall.Skinning != nullptr;
+ const bool useSkinning = drawCall.Surface.Skinning != nullptr;
if (useSkinning)
{
// Bind skinning buffer
- ASSERT(drawCall.Skinning->IsReady());
- context->BindSR(0, drawCall.Skinning->BoneMatrices->View());
+ ASSERT(drawCall.Surface.Skinning->IsReady());
+ context->BindSR(0, drawCall.Surface.Skinning->BoneMatrices->View());
}
// Setup material constants data
@@ -97,7 +99,7 @@ void ForwardMaterialShader::Bind(BindParameters& params)
Matrix::Transpose(view.Frustum.GetMatrix(), materialData->ViewProjectionMatrix);
Matrix::Transpose(drawCall.World, materialData->WorldMatrix);
Matrix::Transpose(view.View, materialData->ViewMatrix);
- Matrix::Transpose(drawCall.PrevWorld, materialData->PrevWorldMatrix);
+ Matrix::Transpose(drawCall.Surface.PrevWorld, materialData->PrevWorldMatrix);
Matrix::Transpose(view.PrevViewProjection, materialData->PrevViewProjectionMatrix);
materialData->ViewPos = view.Position;
@@ -118,9 +120,9 @@ void ForwardMaterialShader::Bind(BindParameters& params)
materialData->WorldInvScale = worldInvScale;
materialData->WorldDeterminantSign = drawCall.WorldDeterminantSign;
- materialData->LODDitherFactor = drawCall.LODDitherFactor;
+ materialData->LODDitherFactor = drawCall.Surface.LODDitherFactor;
materialData->PerInstanceRandom = drawCall.PerInstanceRandom;
- materialData->GeometrySize = drawCall.GeometrySize;
+ materialData->GeometrySize = drawCall.Surface.GeometrySize;
}
// Setup lighting constants data
@@ -249,7 +251,7 @@ void ForwardMaterialShader::Bind(BindParameters& params)
if (IsRunningRadiancePass)
cullMode = CullMode::TwoSided;
#endif
- if (cullMode != CullMode::TwoSided && drawCall.IsNegativeScale())
+ if (cullMode != CullMode::TwoSided && drawCall.WorldDeterminantSign < 0)
{
// Invert culling when scale is negative
if (cullMode == CullMode::Normal)
diff --git a/Source/Engine/Graphics/Materials/ForwardMaterialShader.h b/Source/Engine/Graphics/Materials/ForwardMaterialShader.h
index d39fcea54..bcba48259 100644
--- a/Source/Engine/Graphics/Materials/ForwardMaterialShader.h
+++ b/Source/Engine/Graphics/Materials/ForwardMaterialShader.h
@@ -67,7 +67,7 @@ public:
// [MaterialShader]
DrawPass GetDrawModes() const override;
- bool CanUseInstancing() const override;
+ bool CanUseInstancing(InstancingHandler& handler) const override;
void Bind(BindParameters& params) override;
void Unload() override;
diff --git a/Source/Engine/Graphics/Materials/IMaterial.h b/Source/Engine/Graphics/Materials/IMaterial.h
index 09796c04b..f1e7856af 100644
--- a/Source/Engine/Graphics/Materials/IMaterial.h
+++ b/Source/Engine/Graphics/Materials/IMaterial.h
@@ -2,7 +2,6 @@
#pragma once
-#include "Engine/Threading/Task.h"
#include "MaterialInfo.h"
struct MaterialParamsLink;
@@ -81,24 +80,6 @@ public:
return GetInfo().Domain == MaterialDomain::Particle;
}
- ///
- /// Checks if material needs vertex color vertex buffer data for rendering.
- ///
- /// True if mesh renderer have to provide vertex color buffer to render that material
- FORCE_INLINE bool RequireVertexColor() const
- {
- return (GetInfo().UsageFlags & MaterialUsageFlags::UseVertexColor) != 0;
- }
-
- ///
- /// Checks if material supports dithered LOD transitions.
- ///
- /// True if material supports dithered LOD transitions, otherwise false.
- FORCE_INLINE bool IsDitheredLODTransition() const
- {
- return (GetInfo().FeaturesFlags & MaterialFeaturesFlags::DitheredLODTransition) != 0;
- }
-
///
/// Returns true if material is ready for rendering.
///
@@ -123,11 +104,22 @@ public:
return false;
}
+ ///
+ /// The instancing handling used to hash, batch and write draw calls.
+ ///
+ struct InstancingHandler
+ {
+ void (*GetHash)(const DrawCall& drawCall, int32& batchKey);
+ bool (*CanBatch)(const DrawCall& a, const DrawCall& b);
+ void (*WriteDrawCall)(struct InstanceData* instanceData, const DrawCall& drawCall);
+ };
+
///
/// Returns true if material can use draw calls instancing.
///
+ /// The output data for the instancing handling used to hash, batch and write draw calls. Valid only when function returns true.
/// True if can use instancing, otherwise false.
- virtual bool CanUseInstancing() const
+ virtual bool CanUseInstancing(InstancingHandler& handler) const
{
return false;
}
diff --git a/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp b/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp
index 8c1c065ab..210c81e7d 100644
--- a/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp
+++ b/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp
@@ -76,7 +76,7 @@ void ParticleMaterialShader::Bind(BindParameters& params)
const bool hasCb0 = cb0->GetSize() != 0;
const auto cb1 = _shader->GetCB(1);
const bool hasCb1 = cb1->GetSize() != 0;
- const uint32 sortedIndicesOffset = drawCall.Module->SortedIndicesOffset;
+ const uint32 sortedIndicesOffset = drawCall.Particle.Module->SortedIndicesOffset;
// Setup parameters
MaterialParameter::BindMeta bindMeta;
@@ -90,9 +90,9 @@ void ParticleMaterialShader::Bind(BindParameters& params)
// Setup particles data and attributes binding info
{
- context->BindSR(0, drawCall.Particles->GPU.Buffer->View());
- if (drawCall.Particles->GPU.SortedIndices)
- context->BindSR(1, drawCall.Particles->GPU.SortedIndices->View());
+ context->BindSR(0, drawCall.Particle.Particles->GPU.Buffer->View());
+ if (drawCall.Particle.Particles->GPU.SortedIndices)
+ context->BindSR(1, drawCall.Particle.Particles->GPU.SortedIndices->View());
if (hasCb0)
{
@@ -104,7 +104,7 @@ void ParticleMaterialShader::Bind(BindParameters& params)
{
auto name = StringView(param.GetName().Get() + 9);
- const int32 offset = drawCall.Particles->Layout->FindAttributeOffset(name);
+ const int32 offset = drawCall.Particle.Particles->Layout->FindAttributeOffset(name);
*((int32*)(bindMeta.Buffer0 + param.GetBindOffset())) = offset;
}
}
@@ -115,7 +115,7 @@ void ParticleMaterialShader::Bind(BindParameters& params)
const bool wireframe = (_info.FeaturesFlags & MaterialFeaturesFlags::Wireframe) != 0 || view.Mode == ViewMode::Wireframe;
CullMode cullMode = view.Pass == DrawPass::Depth ? CullMode::TwoSided : _info.CullMode;
PipelineStateCache* psCache = nullptr;
- switch (drawCall.Module->TypeID)
+ switch (drawCall.Particle.Module->TypeID)
{
// Sprite Rendering
case 400:
@@ -142,20 +142,20 @@ void ParticleMaterialShader::Bind(BindParameters& params)
{
const auto materialData = reinterpret_cast(_cb0Data.Get());
- materialData->RibbonWidthOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleRibbonWidth, ParticleAttribute::ValueTypes::Float, -1);
- materialData->RibbonTwistOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleRibbonTwist, ParticleAttribute::ValueTypes::Float, -1);
- materialData->RibbonFacingVectorOffset = drawCall.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.Ribbon.UVTilingDistance;
- materialData->RibbonUVScale.X = drawCall.Ribbon.UVScaleX;
- materialData->RibbonUVScale.Y = drawCall.Ribbon.UVScaleY;
- materialData->RibbonUVOffset.X = drawCall.Ribbon.UVOffsetX;
- materialData->RibbonUVOffset.Y = drawCall.Ribbon.UVOffsetY;
- materialData->RibbonSegmentCount = drawCall.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.Ribbon.SegmentDistances)
- context->BindSR(1, drawCall.Ribbon.SegmentDistances->View());
+ if (drawCall.Particle.Ribbon.SegmentDistances)
+ context->BindSR(1, drawCall.Particle.Ribbon.SegmentDistances->View());
break;
}
@@ -186,17 +186,17 @@ void ParticleMaterialShader::Bind(BindParameters& params)
materialData->TimeParam = Time::Draw.UnscaledTime.GetTotalSeconds();
materialData->ViewInfo = view.ViewInfo;
materialData->ScreenSize = view.ScreenSize;
- materialData->SortedIndicesOffset = drawCall.Particles->GPU.SortedIndices && params.RenderContext.View.Pass != DrawPass::Depth ? sortedIndicesOffset : 0xFFFFFFFF;
+ materialData->SortedIndicesOffset = drawCall.Particle.Particles->GPU.SortedIndices && params.RenderContext.View.Pass != DrawPass::Depth ? sortedIndicesOffset : 0xFFFFFFFF;
materialData->PerInstanceRandom = drawCall.PerInstanceRandom;
- materialData->ParticleStride = drawCall.Particles->Stride;
- materialData->PositionOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticlePosition, ParticleAttribute::ValueTypes::Vector3);
- materialData->SpriteSizeOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleSpriteSize, ParticleAttribute::ValueTypes::Vector2);
- materialData->SpriteFacingModeOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleSpriteFacingMode, ParticleAttribute::ValueTypes::Int, -1);
- materialData->SpriteFacingVectorOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleSpriteFacingVector, ParticleAttribute::ValueTypes::Vector3);
- materialData->VelocityOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleVelocityOffset, ParticleAttribute::ValueTypes::Vector3);
- materialData->RotationOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleRotationOffset, ParticleAttribute::ValueTypes::Vector3, -1);
- materialData->ScaleOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleScaleOffset, ParticleAttribute::ValueTypes::Vector3, -1);
- materialData->ModelFacingModeOffset = drawCall.Particles->Layout->FindAttributeOffset(ParticleModelFacingModeOffset, ParticleAttribute::ValueTypes::Int, -1);
+ materialData->ParticleStride = drawCall.Particle.Particles->Stride;
+ materialData->PositionOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticlePosition, ParticleAttribute::ValueTypes::Vector3);
+ materialData->SpriteSizeOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleSpriteSize, ParticleAttribute::ValueTypes::Vector2);
+ materialData->SpriteFacingModeOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleSpriteFacingMode, ParticleAttribute::ValueTypes::Int, -1);
+ materialData->SpriteFacingVectorOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleSpriteFacingVector, ParticleAttribute::ValueTypes::Vector3);
+ materialData->VelocityOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleVelocityOffset, ParticleAttribute::ValueTypes::Vector3);
+ materialData->RotationOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleRotationOffset, ParticleAttribute::ValueTypes::Vector3, -1);
+ materialData->ScaleOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleScaleOffset, ParticleAttribute::ValueTypes::Vector3, -1);
+ materialData->ModelFacingModeOffset = drawCall.Particle.Particles->Layout->FindAttributeOffset(ParticleModelFacingModeOffset, ParticleAttribute::ValueTypes::Int, -1);
Matrix::Invert(drawCall.World, materialData->WorldMatrixInverseTransposed);
}
diff --git a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp
index 212e27d87..37f932a5a 100644
--- a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp
+++ b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp
@@ -93,36 +93,36 @@ void TerrainMaterialShader::Bind(BindParameters& params)
data->WorldDeterminantSign = drawCall.WorldDeterminantSign;
data->PerInstanceRandom = drawCall.PerInstanceRandom;
- data->CurrentLOD = drawCall.TerrainData.CurrentLOD;
- data->ChunkSizeNextLOD = drawCall.TerrainData.ChunkSizeNextLOD;
- data->TerrainChunkSizeLOD0 = drawCall.TerrainData.TerrainChunkSizeLOD0;
- data->HeightmapUVScaleBias = drawCall.TerrainData.HeightmapUVScaleBias;
- data->NeighborLOD = drawCall.TerrainData.NeighborLOD;
- data->OffsetUV = drawCall.TerrainData.OffsetUV;
+ data->CurrentLOD = drawCall.Terrain.CurrentLOD;
+ data->ChunkSizeNextLOD = drawCall.Terrain.ChunkSizeNextLOD;
+ data->TerrainChunkSizeLOD0 = drawCall.Terrain.TerrainChunkSizeLOD0;
+ data->HeightmapUVScaleBias = drawCall.Terrain.HeightmapUVScaleBias;
+ data->NeighborLOD = drawCall.Terrain.NeighborLOD;
+ data->OffsetUV = drawCall.Terrain.OffsetUV;
}
const bool useLightmap = view.Flags & ViewFlags::GI
#if USE_EDITOR
&& EnableLightmapsUsage
#endif
&& view.Pass == DrawPass::GBuffer
- && drawCall.Lightmap != nullptr;
+ && drawCall.Terrain.Lightmap != nullptr;
if (useLightmap)
{
// Bind lightmap textures
GPUTexture *lightmap0, *lightmap1, *lightmap2;
- drawCall.Lightmap->GetTextures(&lightmap0, &lightmap1, &lightmap2);
+ drawCall.Terrain.Lightmap->GetTextures(&lightmap0, &lightmap1, &lightmap2);
context->BindSR(0, lightmap0);
context->BindSR(1, lightmap1);
context->BindSR(2, lightmap2);
// Set lightmap data
- data->LightmapArea = drawCall.LightmapUVsArea;
+ data->LightmapArea = drawCall.Terrain.LightmapUVsArea;
}
// Bind terrain textures
- const auto heightmap = drawCall.TerrainData.Patch->Heightmap.Get()->GetTexture();
- const auto splatmap0 = drawCall.TerrainData.Patch->Splatmap[0] ? drawCall.TerrainData.Patch->Splatmap[0]->GetTexture() : nullptr;
- const auto splatmap1 = drawCall.TerrainData.Patch->Splatmap[1] ? drawCall.TerrainData.Patch->Splatmap[1]->GetTexture() : nullptr;
+ const auto heightmap = drawCall.Terrain.Patch->Heightmap.Get()->GetTexture();
+ const auto splatmap0 = drawCall.Terrain.Patch->Splatmap[0] ? drawCall.Terrain.Patch->Splatmap[0]->GetTexture() : nullptr;
+ const auto splatmap1 = drawCall.Terrain.Patch->Splatmap[1] ? drawCall.Terrain.Patch->Splatmap[1]->GetTexture() : nullptr;
context->BindSR(3, heightmap);
context->BindSR(4, splatmap0);
context->BindSR(5, splatmap1);
@@ -141,7 +141,7 @@ void TerrainMaterialShader::Bind(BindParameters& params)
if (IsRunningRadiancePass)
cullMode = CullMode::TwoSided;
#endif
- if (cullMode != CullMode::TwoSided && drawCall.IsNegativeScale())
+ if (cullMode != CullMode::TwoSided && drawCall.WorldDeterminantSign < 0)
{
// Invert culling when scale is negative
if (cullMode == CullMode::Normal)
diff --git a/Source/Engine/Graphics/Models/Mesh.cpp b/Source/Engine/Graphics/Models/Mesh.cpp
index 444d60540..99262cd51 100644
--- a/Source/Engine/Graphics/Models/Mesh.cpp
+++ b/Source/Engine/Graphics/Models/Mesh.cpp
@@ -393,15 +393,15 @@ void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, cons
drawCall.IndirectArgsOffset = 0;
drawCall.Material = material;
drawCall.World = world;
- drawCall.PrevWorld = world;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
- drawCall.GeometrySize = _box.GetSize();
- drawCall.Lightmap = nullptr;
- drawCall.LightmapUVsArea = Rectangle::Empty;
- drawCall.Skinning = nullptr;
+ drawCall.Surface.GeometrySize = _box.GetSize();
+ drawCall.Surface.PrevWorld = world;
+ drawCall.Surface.Lightmap = nullptr;
+ drawCall.Surface.LightmapUVsArea = Rectangle::Empty;
+ drawCall.Surface.Skinning = nullptr;
+ drawCall.Surface.LODDitherFactor = 0.0f;
drawCall.WorldDeterminantSign = Math::FloatSelect(world.RotDeterminant(), 1, -1);
drawCall.PerInstanceRandom = 0.0f;
- drawCall.LODDitherFactor = 0.0f;
renderContext.List->AddDrawCall(DrawPass::Default, flags, drawCall, receiveDecals);
}
@@ -456,15 +456,15 @@ void Mesh::Draw(const RenderContext& renderContext, const DrawInfo& info, float
drawCall.IndirectArgsOffset = 0;
drawCall.Material = material;
drawCall.World = *info.World;
- drawCall.PrevWorld = info.DrawState->PrevWorld;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
- drawCall.GeometrySize = _box.GetSize();
- drawCall.Lightmap = info.Flags & StaticFlags::Lightmap ? info.Lightmap : nullptr;
- drawCall.LightmapUVsArea = info.LightmapUVs ? *info.LightmapUVs : Rectangle::Empty;
- drawCall.Skinning = nullptr;
+ drawCall.Surface.GeometrySize = _box.GetSize();
+ drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
+ drawCall.Surface.Lightmap = info.Flags & StaticFlags::Lightmap ? info.Lightmap : nullptr;
+ drawCall.Surface.LightmapUVsArea = info.LightmapUVs ? *info.LightmapUVs : Rectangle::Empty;
+ drawCall.Surface.Skinning = nullptr;
+ drawCall.Surface.LODDitherFactor = lodDitherFactor;
drawCall.WorldDeterminantSign = Math::FloatSelect(drawCall.World.RotDeterminant(), 1, -1);
drawCall.PerInstanceRandom = info.PerInstanceRandom;
- drawCall.LODDitherFactor = lodDitherFactor;
renderContext.List->AddDrawCall(drawModes, info.Flags, drawCall, entry.ReceiveDecals);
}
diff --git a/Source/Engine/Graphics/Models/SkinnedMesh.cpp b/Source/Engine/Graphics/Models/SkinnedMesh.cpp
index 90aa03d86..e9e7f8438 100644
--- a/Source/Engine/Graphics/Models/SkinnedMesh.cpp
+++ b/Source/Engine/Graphics/Models/SkinnedMesh.cpp
@@ -193,15 +193,15 @@ void SkinnedMesh::Draw(const RenderContext& renderContext, const DrawInfo& info,
drawCall.IndirectArgsOffset = 0;
drawCall.Material = material;
drawCall.World = *info.World;
- drawCall.PrevWorld = info.DrawState->PrevWorld;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
- drawCall.GeometrySize = _box.GetSize();
- drawCall.Lightmap = nullptr;
- drawCall.LightmapUVsArea = Rectangle::Empty;
- drawCall.Skinning = info.Skinning;
+ drawCall.Surface.GeometrySize = _box.GetSize();
+ drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
+ drawCall.Surface.Lightmap = nullptr;
+ drawCall.Surface.LightmapUVsArea = Rectangle::Empty;
+ drawCall.Surface.Skinning = info.Skinning;
+ drawCall.Surface.LODDitherFactor = lodDitherFactor;
drawCall.WorldDeterminantSign = Math::FloatSelect(drawCall.World.RotDeterminant(), 1, -1);
drawCall.PerInstanceRandom = info.PerInstanceRandom;
- drawCall.LODDitherFactor = lodDitherFactor;
renderContext.List->AddDrawCall(drawModes, StaticFlags::None, drawCall, entry.ReceiveDecals);
}
diff --git a/Source/Engine/Level/Actors/Skybox.cpp b/Source/Engine/Level/Actors/Skybox.cpp
index 48c19191f..e8ea08c89 100644
--- a/Source/Engine/Level/Actors/Skybox.cpp
+++ b/Source/Engine/Level/Actors/Skybox.cpp
@@ -93,7 +93,7 @@ void Skybox::ApplySky(GPUContext* context, RenderContext& renderContext, const M
Platform::MemoryClear(&drawCall, sizeof(DrawCall));
drawCall.World = world;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
- drawCall.GeometrySize = _box.GetSize();
+ drawCall.Surface.GeometrySize = _box.GetSize();
drawCall.WorldDeterminantSign = Math::FloatSelect(world.RotDeterminant(), 1, -1);
drawCall.PerInstanceRandom = GetPerInstanceRandom();
MaterialBase::BindParameters bindParams(context, renderContext, drawCall);
diff --git a/Source/Engine/Particles/ParticleManager.cpp b/Source/Engine/Particles/ParticleManager.cpp
index 40cebd892..c83aacbbf 100644
--- a/Source/Engine/Particles/ParticleManager.cpp
+++ b/Source/Engine/Particles/ParticleManager.cpp
@@ -423,7 +423,7 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
{
const int32 moduleIndex = renderModulesIndices[index];
auto module = emitter->Graph.RenderModules[moduleIndex];
- drawCall.Module = module;
+ drawCall.Particle.Module = module;
switch (module->TypeID)
{
@@ -486,7 +486,7 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
int32 count = buffer->CPU.Count;
// Setup ribbon data
- auto& ribbon = drawCall.Ribbon;
+ auto& ribbon = drawCall.Particle.Ribbon;
ribbon.UVTilingDistance = uvTilingDistance;
ribbon.SegmentCount = ribbonModulesSegmentCount[ribbonModuleIndex];
ribbon.UVScaleX = uvScale.X;
@@ -788,7 +788,7 @@ void DrawEmitterGPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
{
int32 moduleIndex = renderModulesIndices[index];
auto module = emitter->Graph.RenderModules[moduleIndex];
- drawCall.Module = module;
+ drawCall.Particle.Module = module;
switch (module->TypeID)
{
@@ -875,9 +875,7 @@ void ParticleManager::DrawParticles(RenderContext& renderContext, ParticleEffect
// Setup a draw call common data
DrawCall drawCall;
- drawCall.LightmapUVsArea = Rectangle::Empty;
drawCall.PerInstanceRandom = effect->GetPerInstanceRandom();
- drawCall.LODDitherFactor = 1.0f;
drawCall.ObjectPosition = world.GetTranslation();
// Draw all emitters
@@ -890,9 +888,8 @@ void ParticleManager::DrawParticles(RenderContext& renderContext, ParticleEffect
auto emitter = buffer->Emitter;
drawCall.World = emitter->SimulationSpace == ParticlesSimulationSpace::World ? Matrix::Identity : world;
- drawCall.PrevWorld = drawCall.World;
drawCall.WorldDeterminantSign = Math::FloatSelect(drawCall.World.RotDeterminant(), 1, -1);
- drawCall.Particles = buffer;
+ drawCall.Particle.Particles = buffer;
// Check if need to render any module
RenderModulesIndices renderModulesIndices;
diff --git a/Source/Engine/Renderer/DrawCall.h b/Source/Engine/Renderer/DrawCall.h
index cc35b2627..31656145b 100644
--- a/Source/Engine/Renderer/DrawCall.h
+++ b/Source/Engine/Renderer/DrawCall.h
@@ -113,6 +113,11 @@ public:
///
struct DrawCall
{
+ ///
+ /// The material to use for rendering.
+ ///
+ IMaterial* Material;
+
struct
{
///
@@ -156,53 +161,18 @@ struct DrawCall
///
GPUBuffer* IndirectArgsBuffer;
- ///
- /// The target material to use.
- ///
- IMaterial* Material;
-
- // Particles don't use skinning nor lightmaps so pack those stuff together
+ // Per-material shader data packed into union
union
{
struct
{
- ///
- /// Pointer to lightmap for static object with prebaked lighting.
- ///
const Lightmap* Lightmap;
-
- ///
- /// The skinning data. If set then material should use GPU skinning during rendering.
- ///
SkinnedMeshDrawData* Skinning;
- };
-
- struct
- {
- ///
- /// The particles data. Used only by the particles shaders.
- ///
- class ParticleBuffer* Particles;
-
- ///
- /// The particle module to draw.
- ///
- class ParticleEmitterGraphCPUNode* Module;
- };
- };
-
- ///
- /// Object world transformation matrix.
- ///
- Matrix World;
-
- // Terrain and particles don't use previous world matrix so pack those stuff together
- union
- {
- ///
- /// Object world transformation matrix using during previous frame.
- ///
- Matrix PrevWorld;
+ Rectangle LightmapUVsArea;
+ Vector3 GeometrySize; // Object geometry size in the world (unscaled).
+ float LODDitherFactor; // The model LOD transition dither progress.
+ Matrix PrevWorld;
+ } Surface;
struct
{
@@ -212,26 +182,39 @@ struct DrawCall
float CurrentLOD;
float ChunkSizeNextLOD;
float TerrainChunkSizeLOD0;
+ Rectangle LightmapUVsArea;
const class TerrainPatch* Patch;
- } TerrainData;
+ const Lightmap* Lightmap;
+ } Terrain;
struct
{
- int32 RibbonOrderOffset;
- float UVTilingDistance;
- float UVScaleX;
- float UVScaleY;
- float UVOffsetX;
- float UVOffsetY;
- uint32 SegmentCount;
- GPUBuffer* SegmentDistances;
- } Ribbon;
+ class ParticleBuffer* Particles;
+ class ParticleEmitterGraphCPUNode* Module;
+
+ struct
+ {
+ int32 OrderOffset;
+ float UVTilingDistance;
+ float UVScaleX;
+ float UVScaleY;
+ float UVOffsetX;
+ float UVOffsetY;
+ uint32 SegmentCount;
+ GPUBuffer* SegmentDistances;
+ } Ribbon;
+ } Particle;
+
+ struct
+ {
+ byte Raw[96];
+ } Custom;
};
///
- /// Lightmap UVs area that entry occupies.
+ /// Object world transformation matrix.
///
- Rectangle LightmapUVsArea;
+ Matrix World;
///
/// Object location in the world used for draw calls sorting.
@@ -243,36 +226,17 @@ struct DrawCall
///
float WorldDeterminantSign;
- ///
- /// Object geometry size in the world (unscaled).
- ///
- Vector3 GeometrySize;
-
///
/// The random per-instance value (normalized to range 0-1).
///
float PerInstanceRandom;
- ///
- /// The model LOD transition dither factor.
- ///
- float LODDitherFactor;
-
///
/// Does nothing.
///
DrawCall()
{
}
-
- ///
- /// Determines whether world transform matrix is performing negative scale (then model culling should be inverted).
- ///
- /// true if world matrix contains negative scale; otherwise, false.
- FORCE_INLINE bool IsNegativeScale() const
- {
- return WorldDeterminantSign < 0;
- }
};
template<>
diff --git a/Source/Engine/Renderer/Editor/LightmapUVsDensity.cpp b/Source/Engine/Renderer/Editor/LightmapUVsDensity.cpp
index 152b43d50..9ba9f1a0d 100644
--- a/Source/Engine/Renderer/Editor/LightmapUVsDensity.cpp
+++ b/Source/Engine/Renderer/Editor/LightmapUVsDensity.cpp
@@ -178,7 +178,7 @@ void LightmapUVsDensityMaterialShader::Bind(BindParameters& params)
scaleZ > 0.00001f ? 1.0f / scaleZ : 0.0f);
data.LightmapTexelsPerWorldUnit = ShadowsOfMordor::LightmapTexelsPerWorldUnit;
data.LightmapSize = 1024.0f;
- data.LightmapArea = drawCall.LightmapUVsArea;
+ data.LightmapArea = drawCall.Surface.LightmapUVsArea;
if (drawCallModel)
{
// Calculate current lightmap slot size for the object (matches the ShadowsOfMordor calculations when baking the lighting)
diff --git a/Source/Engine/Renderer/GBufferPass.cpp b/Source/Engine/Renderer/GBufferPass.cpp
index 5c6f76905..b9e91ee01 100644
--- a/Source/Engine/Renderer/GBufferPass.cpp
+++ b/Source/Engine/Renderer/GBufferPass.cpp
@@ -145,7 +145,8 @@ void GBufferPass::Fill(RenderContext& renderContext, GPUTextureView* lightBuffer
drawCall.Material = _lightmapUVsDensityMaterialShader;
}
}
- if (!_lightmapUVsDensityMaterialShader->CanUseInstancing())
+ IMaterial::InstancingHandler handler;
+ if (!_lightmapUVsDensityMaterialShader->CanUseInstancing(handler))
{
drawCallsList.CanUseInstancing = false;
}
@@ -166,7 +167,8 @@ void GBufferPass::Fill(RenderContext& renderContext, GPUTextureView* lightBuffer
drawCall.Material = _vertexColorsMaterialShader;
}
}
- if (!_vertexColorsMaterialShader->CanUseInstancing())
+ IMaterial::InstancingHandler handler;
+ if (!_vertexColorsMaterialShader->CanUseInstancing(handler))
{
drawCallsList.CanUseInstancing = false;
}
@@ -311,8 +313,6 @@ void GBufferPass::DrawDecals(RenderContext& renderContext, GPUTextureView* light
DrawCall drawCall;
MaterialBase::BindParameters bindParams(gpuContext, renderContext, drawCall);
drawCall.Material = nullptr;
- drawCall.Lightmap = nullptr;
- drawCall.Skinning = nullptr;
drawCall.WorldDeterminantSign = 1.0f;
// Draw all decals
diff --git a/Source/Engine/Renderer/RenderList.cpp b/Source/Engine/Renderer/RenderList.cpp
index c78931416..dd711a5e0 100644
--- a/Source/Engine/Renderer/RenderList.cpp
+++ b/Source/Engine/Renderer/RenderList.cpp
@@ -19,6 +19,11 @@
#define BATCH_KEY_BITS 32
#define BATCH_KEY_MASK ((1 << BATCH_KEY_BITS) - 1)
+static_assert(sizeof(DrawCall) <= 280, "Too big draw call data size.");
+static_assert(sizeof(DrawCall::Surface) >= sizeof(DrawCall::Terrain), "Wrong draw call data size.");
+static_assert(sizeof(DrawCall::Surface) >= sizeof(DrawCall::Particle), "Wrong draw call data size.");
+static_assert(sizeof(DrawCall::Surface) >= sizeof(DrawCall::Custom), "Wrong draw call data size.");
+
namespace
{
// Cached data for the draw calls sorting
@@ -495,24 +500,24 @@ end:
}
}
-///
-/// Checks if this draw call be batched together with the other one.
-///
-/// The first draw call.
-/// The second draw call.
-/// True if can merge them, otherwise false.
-FORCE_INLINE bool CanBatchWith(const DrawCall& a, const DrawCall& b)
+namespace
{
- return Platform::MemoryCompare(&a.Geometry, &b.Geometry, sizeof(a.Geometry)) == 0 &&
- a.Material == b.Material &&
- a.Lightmap == b.Lightmap &&
- // TODO: add batch.CanBatch flag computed in AddDrawCall to remove those checks here for Skinning and IndirectDrawArgs
- a.Skinning == nullptr &&
- b.Skinning == nullptr &&
- a.IndirectArgsBuffer == nullptr &&
- b.IndirectArgsBuffer == nullptr &&
- a.WorldDeterminantSign == b.WorldDeterminantSign &&
- a.Material->CanUseInstancing();
+ ///
+ /// Checks if this draw call be batched together with the other one.
+ ///
+ /// The first draw call.
+ /// The second draw call.
+ /// True if can merge them, otherwise false.
+ FORCE_INLINE bool CanBatchWith(const DrawCall& a, const DrawCall& b)
+ {
+ IMaterial::InstancingHandler handler;
+ return a.Material == b.Material &&
+ a.Material->CanUseInstancing(handler) &&
+ Platform::MemoryCompare(&a.Geometry, &b.Geometry, sizeof(a.Geometry)) == 0 &&
+ a.IndirectArgsBuffer == nullptr &&
+ b.IndirectArgsBuffer == nullptr &&
+ a.WorldDeterminantSign == b.WorldDeterminantSign;
+ }
}
void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseDistance, DrawCallsList& list)
@@ -540,7 +545,9 @@ void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseD
batchKey = (batchKey * 397) ^ GetHash(drawCall.Geometry.VertexBuffers[1]);
batchKey = (batchKey * 397) ^ GetHash(drawCall.Geometry.VertexBuffers[2]);
batchKey = (batchKey * 397) ^ GetHash(drawCall.Material);
- batchKey = (batchKey * 397) ^ GetHash(drawCall.Lightmap);
+ IMaterial::InstancingHandler handler;
+ if (drawCall.Material->CanUseInstancing(handler))
+ handler.GetHash(drawCall, batchKey);
batchKey += (int32)(471 * drawCall.WorldDeterminantSign);
#if USE_BATCH_KEY_MASK
const uint32 batchHashKey = (uint32)batchKey & BATCH_KEY_MASK;
@@ -635,14 +642,12 @@ void RenderList::ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsL
auto& batch = list.Batches[i];
if (batch.BatchSize > 1)
{
+ IMaterial::InstancingHandler handler;
+ DrawCalls[list.Indices[batch.StartIndex]].Material->CanUseInstancing(handler);
for (int32 j = 0; j < batch.BatchSize; j++)
{
auto& drawCall = DrawCalls[list.Indices[batch.StartIndex + j]];
- instanceData->InstanceOrigin = Vector4(drawCall.World.M41, drawCall.World.M42, drawCall.World.M43, drawCall.PerInstanceRandom);
- instanceData->InstanceTransform1 = Vector4(drawCall.World.M11, drawCall.World.M12, drawCall.World.M13, drawCall.LODDitherFactor);
- instanceData->InstanceTransform2 = Vector3(drawCall.World.M21, drawCall.World.M22, drawCall.World.M23);
- instanceData->InstanceTransform3 = Vector3(drawCall.World.M31, drawCall.World.M32, drawCall.World.M33);
- instanceData->InstanceLightmapArea = Half4(drawCall.LightmapUVsArea);
+ handler.WriteDrawCall(instanceData, drawCall);
instanceData++;
}
}
@@ -742,3 +747,26 @@ DRAW:
}
}
}
+
+void SurfaceDrawCallHandler::GetHash(const DrawCall& drawCall, int32& batchKey)
+{
+ batchKey = (batchKey * 397) ^ ::GetHash(drawCall.Surface.Lightmap);
+}
+
+bool SurfaceDrawCallHandler::CanBatch(const DrawCall& a, const DrawCall& b)
+{
+ return a.Surface.Lightmap == b.Surface.Lightmap &&
+ a.Surface.Skinning == nullptr &&
+ b.Surface.Skinning == nullptr;
+}
+
+void SurfaceDrawCallHandler::WriteDrawCall(InstanceData* instanceData, const DrawCall& drawCall)
+{
+ instanceData->InstanceOrigin = Vector3(drawCall.World.M41, drawCall.World.M42, drawCall.World.M43);
+ instanceData->PerInstanceRandom = drawCall.PerInstanceRandom;
+ instanceData->InstanceTransform1 = Vector3(drawCall.World.M11, drawCall.World.M12, drawCall.World.M13);
+ instanceData->LODDitherFactor = drawCall.Surface.LODDitherFactor;
+ instanceData->InstanceTransform2 = Vector3(drawCall.World.M21, drawCall.World.M22, drawCall.World.M23);
+ instanceData->InstanceTransform3 = Vector3(drawCall.World.M31, drawCall.World.M32, drawCall.World.M33);
+ instanceData->InstanceLightmapArea = Half4(drawCall.Surface.LightmapUVsArea);
+}
diff --git a/Source/Engine/Renderer/RenderList.h b/Source/Engine/Renderer/RenderList.h
index dffbbd2d1..69ef0c33d 100644
--- a/Source/Engine/Renderer/RenderList.h
+++ b/Source/Engine/Renderer/RenderList.h
@@ -357,18 +357,6 @@ public:
private:
- ///
- /// Represents data per instance element used for instanced rendering.
- ///
- struct InstanceData
- {
- Vector4 InstanceOrigin; // .w contains PerInstanceRandom
- Vector4 InstanceTransform1; // .w contains LODDitherFactor
- Vector3 InstanceTransform2;
- Vector3 InstanceTransform3;
- Half4 InstanceLightmapArea;
- };
-
DynamicVertexBuffer _instanceBuffer;
public:
@@ -475,3 +463,24 @@ public:
/// The collected draw calls list.
void ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsList& list);
};
+
+///
+/// Represents data per instance element used for instanced rendering.
+///
+struct FLAXENGINE_API InstanceData
+{
+ Vector3 InstanceOrigin;
+ float PerInstanceRandom;
+ Vector3 InstanceTransform1;
+ float LODDitherFactor;
+ Vector3 InstanceTransform2;
+ Vector3 InstanceTransform3;
+ Half4 InstanceLightmapArea;
+};
+
+struct SurfaceDrawCallHandler
+{
+ static void GetHash(const DrawCall& drawCall, int32& batchKey);
+ static bool CanBatch(const DrawCall& a, const DrawCall& b);
+ static void WriteDrawCall(InstanceData* instanceData, const DrawCall& drawCall);
+};
diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp
index 4d3241375..89efef74c 100644
--- a/Source/Engine/Renderer/Renderer.cpp
+++ b/Source/Engine/Renderer/Renderer.cpp
@@ -31,9 +31,6 @@
#include "Editor/Editor.h"
#endif
-// It must use less or the same amount of memory
-static_assert(sizeof(DrawCall::TerrainData) <= sizeof(DrawCall::PrevWorld), "Invalid size of the terrain data in the draw call.");
-
#if USE_EDITOR
// Additional options used in editor for lightmaps baking
bool IsRunningRadiancePass = false;
diff --git a/Source/Engine/Terrain/TerrainChunk.cpp b/Source/Engine/Terrain/TerrainChunk.cpp
index 1241935e5..6cff541f3 100644
--- a/Source/Engine/Terrain/TerrainChunk.cpp
+++ b/Source/Engine/Terrain/TerrainChunk.cpp
@@ -88,33 +88,31 @@ void TerrainChunk::Draw(const RenderContext& renderContext) const
drawCall.Material = _cachedDrawMaterial;
drawCall.World = _world;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
- drawCall.TerrainData.Patch = _patch;
- drawCall.TerrainData.HeightmapUVScaleBias = _heightmapUVScaleBias;
- drawCall.TerrainData.OffsetUV = Vector2((float)(_patch->_x * TerrainPatch::CHUNKS_COUNT_EDGE + _x), (float)(_patch->_z * TerrainPatch::CHUNKS_COUNT_EDGE + _z));
- drawCall.TerrainData.CurrentLOD = (float)lod;
- drawCall.TerrainData.ChunkSizeNextLOD = (float)(((chunkSize + 1) >> (lod + 1)) - 1);
- drawCall.TerrainData.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize;
+ drawCall.Terrain.Patch = _patch;
+ drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias;
+ drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * TerrainPatch::CHUNKS_COUNT_EDGE + _x), (float)(_patch->_z * TerrainPatch::CHUNKS_COUNT_EDGE + _z));
+ drawCall.Terrain.CurrentLOD = (float)lod;
+ drawCall.Terrain.ChunkSizeNextLOD = (float)(((chunkSize + 1) >> (lod + 1)) - 1);
+ drawCall.Terrain.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize;
// TODO: try using SIMD clamping for 4 chunks at once
- drawCall.TerrainData.NeighborLOD.X = (float)Math::Clamp(_neighbors[0]->_cachedDrawLOD, lod, minLod);
- drawCall.TerrainData.NeighborLOD.Y = (float)Math::Clamp(_neighbors[1]->_cachedDrawLOD, lod, minLod);
- drawCall.TerrainData.NeighborLOD.Z = (float)Math::Clamp(_neighbors[2]->_cachedDrawLOD, lod, minLod);
- drawCall.TerrainData.NeighborLOD.W = (float)Math::Clamp(_neighbors[3]->_cachedDrawLOD, lod, minLod);
+ drawCall.Terrain.NeighborLOD.X = (float)Math::Clamp(_neighbors[0]->_cachedDrawLOD, lod, minLod);
+ drawCall.Terrain.NeighborLOD.Y = (float)Math::Clamp(_neighbors[1]->_cachedDrawLOD, lod, minLod);
+ drawCall.Terrain.NeighborLOD.Z = (float)Math::Clamp(_neighbors[2]->_cachedDrawLOD, lod, minLod);
+ drawCall.Terrain.NeighborLOD.W = (float)Math::Clamp(_neighbors[3]->_cachedDrawLOD, lod, minLod);
const auto scene = _patch->_terrain->GetScene();
const auto flags = _patch->_terrain->_staticFlags;
if (flags & StaticFlags::Lightmap && scene)
{
- drawCall.Lightmap = scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex);
- drawCall.LightmapUVsArea = Lightmap.UVsArea;
+ drawCall.Terrain.Lightmap = scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex);
+ drawCall.Terrain.LightmapUVsArea = Lightmap.UVsArea;
}
else
{
- drawCall.Lightmap = nullptr;
- drawCall.LightmapUVsArea = Rectangle::Empty;
+ drawCall.Terrain.Lightmap = nullptr;
+ drawCall.Terrain.LightmapUVsArea = Rectangle::Empty;
}
- drawCall.Skinning = nullptr;
drawCall.WorldDeterminantSign = Math::FloatSelect(drawCall.World.RotDeterminant(), 1, -1);
drawCall.PerInstanceRandom = _perInstanceRandom;
- drawCall.LODDitherFactor = 0.0f;
// Add half-texel offset for heightmap sampling in vertex shader
//const float lodHeightmapSize = Math::Max(1, drawCall.TerrainData.Heightmap->Width() >> lod);
@@ -147,32 +145,30 @@ void TerrainChunk::Draw(const RenderContext& renderContext, MaterialBase* materi
drawCall.Material = material;
drawCall.World = _world;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
- drawCall.TerrainData.Patch = _patch;
- drawCall.TerrainData.HeightmapUVScaleBias = _heightmapUVScaleBias;
- drawCall.TerrainData.OffsetUV = Vector2((float)(_patch->_x * TerrainPatch::CHUNKS_COUNT_EDGE + _x), (float)(_patch->_z * TerrainPatch::CHUNKS_COUNT_EDGE + _z));
- drawCall.TerrainData.CurrentLOD = (float)lod;
- drawCall.TerrainData.ChunkSizeNextLOD = (float)(((chunkSize + 1) >> (lod + 1)) - 1);
- drawCall.TerrainData.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize;
- drawCall.TerrainData.NeighborLOD.X = (float)lod;
- drawCall.TerrainData.NeighborLOD.Y = (float)lod;
- drawCall.TerrainData.NeighborLOD.Z = (float)lod;
- drawCall.TerrainData.NeighborLOD.W = (float)lod;
+ drawCall.Terrain.Patch = _patch;
+ drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias;
+ drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * TerrainPatch::CHUNKS_COUNT_EDGE + _x), (float)(_patch->_z * TerrainPatch::CHUNKS_COUNT_EDGE + _z));
+ drawCall.Terrain.CurrentLOD = (float)lod;
+ drawCall.Terrain.ChunkSizeNextLOD = (float)(((chunkSize + 1) >> (lod + 1)) - 1);
+ drawCall.Terrain.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize;
+ drawCall.Terrain.NeighborLOD.X = (float)lod;
+ drawCall.Terrain.NeighborLOD.Y = (float)lod;
+ drawCall.Terrain.NeighborLOD.Z = (float)lod;
+ drawCall.Terrain.NeighborLOD.W = (float)lod;
const auto scene = _patch->_terrain->GetScene();
const auto flags = _patch->_terrain->_staticFlags;
if (flags & StaticFlags::Lightmap && scene)
{
- drawCall.Lightmap = scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex);
- drawCall.LightmapUVsArea = Lightmap.UVsArea;
+ drawCall.Terrain.Lightmap = scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex);
+ drawCall.Terrain.LightmapUVsArea = Lightmap.UVsArea;
}
else
{
- drawCall.Lightmap = nullptr;
- drawCall.LightmapUVsArea = Rectangle::Empty;
+ drawCall.Terrain.Lightmap = nullptr;
+ drawCall.Terrain.LightmapUVsArea = Rectangle::Empty;
}
- drawCall.Skinning = nullptr;
drawCall.WorldDeterminantSign = Math::FloatSelect(drawCall.World.RotDeterminant(), 1, -1);
drawCall.PerInstanceRandom = _perInstanceRandom;
- drawCall.LODDitherFactor = 0.0f;
// Add half-texel offset for heightmap sampling in vertex shader
//const float lodHeightmapSize = Math::Max(1, drawCall.TerrainData.Heightmap->Width() >> lod);
diff --git a/Source/Engine/UI/TextRender.cpp b/Source/Engine/UI/TextRender.cpp
index 958aced8b..5707b4461 100644
--- a/Source/Engine/UI/TextRender.cpp
+++ b/Source/Engine/UI/TextRender.cpp
@@ -319,15 +319,15 @@ void TextRender::Draw(RenderContext& renderContext)
// Setup draw call
DrawCall drawCall;
drawCall.World = _world;
- drawCall.PrevWorld = _drawState.PrevWorld;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
- drawCall.GeometrySize = _localBox.GetSize();
- drawCall.Lightmap = nullptr;
- drawCall.LightmapUVsArea = Rectangle::Empty;
- drawCall.Skinning = nullptr;
+ drawCall.Surface.GeometrySize = _localBox.GetSize();
+ drawCall.Surface.PrevWorld = _drawState.PrevWorld;
+ drawCall.Surface.Lightmap = nullptr;
+ drawCall.Surface.LightmapUVsArea = Rectangle::Empty;
+ drawCall.Surface.Skinning = nullptr;
+ drawCall.Surface.LODDitherFactor = 0.0f;
drawCall.WorldDeterminantSign = Math::FloatSelect(_world.RotDeterminant(), 1, -1);
drawCall.PerInstanceRandom = GetPerInstanceRandom();
- drawCall.LODDitherFactor = 0.0f;
drawCall.Geometry.IndexBuffer = _ib.GetBuffer();
drawCall.Geometry.VertexBuffers[0] = _vb0.GetBuffer();
drawCall.Geometry.VertexBuffers[1] = _vb1.GetBuffer();