Refactor draw calls and instancing logic to be more modular
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if material needs vertex color vertex buffer data for rendering.
|
||||
/// </summary>
|
||||
/// <returns>True if mesh renderer have to provide vertex color buffer to render that material</returns>
|
||||
FORCE_INLINE bool RequireVertexColor() const
|
||||
{
|
||||
return (GetInfo().UsageFlags & MaterialUsageFlags::UseVertexColor) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if material supports dithered LOD transitions.
|
||||
/// </summary>
|
||||
/// <returns>True if material supports dithered LOD transitions, otherwise false.</returns>
|
||||
FORCE_INLINE bool IsDitheredLODTransition() const
|
||||
{
|
||||
return (GetInfo().FeaturesFlags & MaterialFeaturesFlags::DitheredLODTransition) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if material is ready for rendering.
|
||||
/// </summary>
|
||||
@@ -123,11 +104,22 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The instancing handling used to hash, batch and write draw calls.
|
||||
/// </summary>
|
||||
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);
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if material can use draw calls instancing.
|
||||
/// </summary>
|
||||
/// <param name="handler">The output data for the instancing handling used to hash, batch and write draw calls. Valid only when function returns true.</param>
|
||||
/// <returns>True if can use instancing, otherwise false.</returns>
|
||||
virtual bool CanUseInstancing() const
|
||||
virtual bool CanUseInstancing(InstancingHandler& handler) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -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<ParticleMaterialShaderData*>(_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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -113,6 +113,11 @@ public:
|
||||
/// </summary>
|
||||
struct DrawCall
|
||||
{
|
||||
/// <summary>
|
||||
/// The material to use for rendering.
|
||||
/// </summary>
|
||||
IMaterial* Material;
|
||||
|
||||
struct
|
||||
{
|
||||
/// <summary>
|
||||
@@ -156,53 +161,18 @@ struct DrawCall
|
||||
/// </summary>
|
||||
GPUBuffer* IndirectArgsBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// The target material to use.
|
||||
/// </summary>
|
||||
IMaterial* Material;
|
||||
|
||||
// Particles don't use skinning nor lightmaps so pack those stuff together
|
||||
// Per-material shader data packed into union
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/// <summary>
|
||||
/// Pointer to lightmap for static object with prebaked lighting.
|
||||
/// </summary>
|
||||
const Lightmap* Lightmap;
|
||||
|
||||
/// <summary>
|
||||
/// The skinning data. If set then material should use GPU skinning during rendering.
|
||||
/// </summary>
|
||||
SkinnedMeshDrawData* Skinning;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
/// <summary>
|
||||
/// The particles data. Used only by the particles shaders.
|
||||
/// </summary>
|
||||
class ParticleBuffer* Particles;
|
||||
|
||||
/// <summary>
|
||||
/// The particle module to draw.
|
||||
/// </summary>
|
||||
class ParticleEmitterGraphCPUNode* Module;
|
||||
};
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Object world transformation matrix.
|
||||
/// </summary>
|
||||
Matrix World;
|
||||
|
||||
// Terrain and particles don't use previous world matrix so pack those stuff together
|
||||
union
|
||||
{
|
||||
/// <summary>
|
||||
/// Object world transformation matrix using during previous frame.
|
||||
/// </summary>
|
||||
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;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Lightmap UVs area that entry occupies.
|
||||
/// Object world transformation matrix.
|
||||
/// </summary>
|
||||
Rectangle LightmapUVsArea;
|
||||
Matrix World;
|
||||
|
||||
/// <summary>
|
||||
/// Object location in the world used for draw calls sorting.
|
||||
@@ -243,36 +226,17 @@ struct DrawCall
|
||||
/// </summary>
|
||||
float WorldDeterminantSign;
|
||||
|
||||
/// <summary>
|
||||
/// Object geometry size in the world (unscaled).
|
||||
/// </summary>
|
||||
Vector3 GeometrySize;
|
||||
|
||||
/// <summary>
|
||||
/// The random per-instance value (normalized to range 0-1).
|
||||
/// </summary>
|
||||
float PerInstanceRandom;
|
||||
|
||||
/// <summary>
|
||||
/// The model LOD transition dither factor.
|
||||
/// </summary>
|
||||
float LODDitherFactor;
|
||||
|
||||
/// <summary>
|
||||
/// Does nothing.
|
||||
/// </summary>
|
||||
DrawCall()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether world transform matrix is performing negative scale (then model culling should be inverted).
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if world matrix contains negative scale; otherwise, <c>false</c>.</returns>
|
||||
FORCE_INLINE bool IsNegativeScale() const
|
||||
{
|
||||
return WorldDeterminantSign < 0;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if this draw call be batched together with the other one.
|
||||
/// </summary>
|
||||
/// <param name="a">The first draw call.</param>
|
||||
/// <param name="b">The second draw call.</param>
|
||||
/// <returns>True if can merge them, otherwise false.</returns>
|
||||
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();
|
||||
/// <summary>
|
||||
/// Checks if this draw call be batched together with the other one.
|
||||
/// </summary>
|
||||
/// <param name="a">The first draw call.</param>
|
||||
/// <param name="b">The second draw call.</param>
|
||||
/// <returns>True if can merge them, otherwise false.</returns>
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -357,18 +357,6 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
/// <summary>
|
||||
/// Represents data per instance element used for instanced rendering.
|
||||
/// </summary>
|
||||
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:
|
||||
/// <param name="list">The collected draw calls list.</param>
|
||||
void ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsList& list);
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Represents data per instance element used for instanced rendering.
|
||||
/// </summary>
|
||||
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);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<int32>(_neighbors[0]->_cachedDrawLOD, lod, minLod);
|
||||
drawCall.TerrainData.NeighborLOD.Y = (float)Math::Clamp<int32>(_neighbors[1]->_cachedDrawLOD, lod, minLod);
|
||||
drawCall.TerrainData.NeighborLOD.Z = (float)Math::Clamp<int32>(_neighbors[2]->_cachedDrawLOD, lod, minLod);
|
||||
drawCall.TerrainData.NeighborLOD.W = (float)Math::Clamp<int32>(_neighbors[3]->_cachedDrawLOD, lod, minLod);
|
||||
drawCall.Terrain.NeighborLOD.X = (float)Math::Clamp<int32>(_neighbors[0]->_cachedDrawLOD, lod, minLod);
|
||||
drawCall.Terrain.NeighborLOD.Y = (float)Math::Clamp<int32>(_neighbors[1]->_cachedDrawLOD, lod, minLod);
|
||||
drawCall.Terrain.NeighborLOD.Z = (float)Math::Clamp<int32>(_neighbors[2]->_cachedDrawLOD, lod, minLod);
|
||||
drawCall.Terrain.NeighborLOD.W = (float)Math::Clamp<int32>(_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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user