Refactor scene rendering to use batched culling for main view and shadow projections
This commit is contained in:
@@ -31,11 +31,11 @@
|
||||
#define STREAM_TASK_BASE MainThreadTask
|
||||
#endif
|
||||
|
||||
#define CHECK_INVALID_BUFFER(buffer) \
|
||||
if (buffer->IsValidFor(this) == false) \
|
||||
#define CHECK_INVALID_BUFFER(model, buffer) \
|
||||
if (buffer->IsValidFor(model) == false) \
|
||||
{ \
|
||||
LOG(Warning, "Invalid Model Instance Buffer size {0} for Model {1}. It should be {2}. Manual update to proper size.", buffer->Count(), ToString(), MaterialSlots.Count()); \
|
||||
buffer->Setup(this); \
|
||||
LOG(Warning, "Invalid Model Instance Buffer size {0} for Model {1}. It should be {2}. Manual update to proper size.", buffer->Count(), model->ToString(), model->MaterialSlots.Count()); \
|
||||
buffer->Setup(model); \
|
||||
}
|
||||
|
||||
REGISTER_BINARY_ASSET_ABSTRACT(ModelBase, "FlaxEngine.ModelBase");
|
||||
@@ -206,14 +206,15 @@ void Model::Draw(const RenderContext& renderContext, MaterialBase* material, con
|
||||
LODs[lodIndex].Draw(renderContext, material, world, flags, receiveDecals);
|
||||
}
|
||||
|
||||
void Model::Draw(const RenderContext& renderContext, const Mesh::DrawInfo& info)
|
||||
template<typename ContextType>
|
||||
FORCE_INLINE void ModelDraw(Model* model, const RenderContext& renderContext, const ContextType& context, const Mesh::DrawInfo& info)
|
||||
{
|
||||
ASSERT(info.Buffer);
|
||||
if (!CanBeRendered())
|
||||
if (!model->CanBeRendered())
|
||||
return;
|
||||
const auto frame = Engine::FrameCount;
|
||||
const auto modelFrame = info.DrawState->PrevFrame + 1;
|
||||
CHECK_INVALID_BUFFER(info.Buffer);
|
||||
CHECK_INVALID_BUFFER(model, info.Buffer);
|
||||
|
||||
// Select a proper LOD index (model may be culled)
|
||||
int32 lodIndex;
|
||||
@@ -223,7 +224,7 @@ void Model::Draw(const RenderContext& renderContext, const Mesh::DrawInfo& info)
|
||||
}
|
||||
else
|
||||
{
|
||||
lodIndex = RenderTools::ComputeModelLOD(this, info.Bounds.Center, (float)info.Bounds.Radius, renderContext);
|
||||
lodIndex = RenderTools::ComputeModelLOD(model, info.Bounds.Center, (float)info.Bounds.Radius, renderContext);
|
||||
if (lodIndex == -1)
|
||||
{
|
||||
// Handling model fade-out transition
|
||||
@@ -244,9 +245,9 @@ void Model::Draw(const RenderContext& renderContext, const Mesh::DrawInfo& info)
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto prevLOD = ClampLODIndex(info.DrawState->PrevLOD);
|
||||
const auto prevLOD = model->ClampLODIndex(info.DrawState->PrevLOD);
|
||||
const float normalizedProgress = static_cast<float>(info.DrawState->LODTransition) * (1.0f / 255.0f);
|
||||
LODs[prevLOD].Draw(renderContext, info, normalizedProgress);
|
||||
model->LODs.Get()[prevLOD].Draw(renderContext, info, normalizedProgress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,7 +255,7 @@ void Model::Draw(const RenderContext& renderContext, const Mesh::DrawInfo& info)
|
||||
}
|
||||
}
|
||||
lodIndex += info.LODBias + renderContext.View.ModelLODBias;
|
||||
lodIndex = ClampLODIndex(lodIndex);
|
||||
lodIndex = model->ClampLODIndex(lodIndex);
|
||||
|
||||
if (renderContext.View.IsSingleFrame)
|
||||
{
|
||||
@@ -287,22 +288,32 @@ void Model::Draw(const RenderContext& renderContext, const Mesh::DrawInfo& info)
|
||||
// Draw
|
||||
if (info.DrawState->PrevLOD == lodIndex || renderContext.View.IsSingleFrame)
|
||||
{
|
||||
LODs[lodIndex].Draw(renderContext, info, 0.0f);
|
||||
model->LODs.Get()[lodIndex].Draw(context, info, 0.0f);
|
||||
}
|
||||
else if (info.DrawState->PrevLOD == -1)
|
||||
{
|
||||
const float normalizedProgress = static_cast<float>(info.DrawState->LODTransition) * (1.0f / 255.0f);
|
||||
LODs[lodIndex].Draw(renderContext, info, 1.0f - normalizedProgress);
|
||||
model->LODs.Get()[lodIndex].Draw(context, info, 1.0f - normalizedProgress);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto prevLOD = ClampLODIndex(info.DrawState->PrevLOD);
|
||||
const auto prevLOD = model->ClampLODIndex(info.DrawState->PrevLOD);
|
||||
const float normalizedProgress = static_cast<float>(info.DrawState->LODTransition) * (1.0f / 255.0f);
|
||||
LODs[prevLOD].Draw(renderContext, info, normalizedProgress);
|
||||
LODs[lodIndex].Draw(renderContext, info, normalizedProgress - 1.0f);
|
||||
model->LODs.Get()[prevLOD].Draw(context, info, normalizedProgress);
|
||||
model->LODs.Get()[lodIndex].Draw(context, info, normalizedProgress - 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::Draw(const RenderContext& renderContext, const Mesh::DrawInfo& info)
|
||||
{
|
||||
ModelDraw(this, renderContext, renderContext, info);
|
||||
}
|
||||
|
||||
void Model::Draw(const RenderContextBatch& renderContextBatch, const Mesh::DrawInfo& info)
|
||||
{
|
||||
ModelDraw(this, renderContextBatch.GetMainContext(), renderContextBatch, info);
|
||||
}
|
||||
|
||||
bool Model::SetupLODs(const Span<int32>& meshesCountPerLod)
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
@@ -190,6 +190,13 @@ public:
|
||||
/// <param name="info">The packed drawing info data.</param>
|
||||
void Draw(const RenderContext& renderContext, const Mesh::DrawInfo& info);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the model.
|
||||
/// </summary>
|
||||
/// <param name="renderContextBatch">The rendering context batch.</param>
|
||||
/// <param name="info">The packed drawing info data.</param>
|
||||
void Draw(const RenderContextBatch& renderContextBatch, const Mesh::DrawInfo& info);
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Setups the model LODs collection including meshes creation.
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#define MODEL_LOD_TO_CHUNK_INDEX(lod) (lod + 1)
|
||||
|
||||
class MeshBase;
|
||||
struct RenderContextBatch;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for asset types that can contain a model resource.
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
#include "Engine/Debug/Exceptions/ArgumentOutOfRangeException.h"
|
||||
#include "Engine/Renderer/DrawCall.h"
|
||||
|
||||
#define CHECK_INVALID_BUFFER(buffer) \
|
||||
if (buffer->IsValidFor(this) == false) \
|
||||
#define CHECK_INVALID_BUFFER(model, buffer) \
|
||||
if (buffer->IsValidFor(model) == false) \
|
||||
{ \
|
||||
LOG(Warning, "Invalid Skinned Model Instance Buffer size {0} for Skinned Model {1}. It should be {2}. Manual update to proper size.", buffer->Count(), ToString(), MaterialSlots.Count()); \
|
||||
buffer->Setup(this); \
|
||||
LOG(Warning, "Invalid Skinned Model Instance Buffer size {0} for Skinned Model {1}. It should be {2}. Manual update to proper size.", buffer->Count(), model->ToString(), model->MaterialSlots.Count()); \
|
||||
buffer->Setup(model); \
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -172,24 +172,25 @@ BoundingBox SkinnedModel::GetBox(int32 lodIndex) const
|
||||
return LODs[lodIndex].GetBox();
|
||||
}
|
||||
|
||||
void SkinnedModel::Draw(RenderContext& renderContext, const SkinnedMesh::DrawInfo& info)
|
||||
template<typename ContextType>
|
||||
FORCE_INLINE void SkinnedModelDraw(SkinnedModel* model, const RenderContext& renderContext, const ContextType& context, const SkinnedMesh::DrawInfo& info)
|
||||
{
|
||||
ASSERT(info.Buffer);
|
||||
if (!CanBeRendered())
|
||||
if (!model->CanBeRendered())
|
||||
return;
|
||||
const auto frame = Engine::FrameCount;
|
||||
const auto modelFrame = info.DrawState->PrevFrame + 1;
|
||||
CHECK_INVALID_BUFFER(info.Buffer);
|
||||
CHECK_INVALID_BUFFER(model, info.Buffer);
|
||||
|
||||
// Select a proper LOD index (model may be culled)
|
||||
int32 lodIndex;
|
||||
if (info.ForcedLOD != -1)
|
||||
{
|
||||
lodIndex = (int32)info.ForcedLOD;
|
||||
lodIndex = info.ForcedLOD;
|
||||
}
|
||||
else
|
||||
{
|
||||
lodIndex = RenderTools::ComputeSkinnedModelLOD(this, info.Bounds.Center, (float)info.Bounds.Radius, renderContext);
|
||||
lodIndex = RenderTools::ComputeSkinnedModelLOD(model, info.Bounds.Center, (float)info.Bounds.Radius, renderContext);
|
||||
if (lodIndex == -1)
|
||||
{
|
||||
// Handling model fade-out transition
|
||||
@@ -210,9 +211,9 @@ void SkinnedModel::Draw(RenderContext& renderContext, const SkinnedMesh::DrawInf
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto prevLOD = ClampLODIndex(info.DrawState->PrevLOD);
|
||||
const auto prevLOD = model->ClampLODIndex(info.DrawState->PrevLOD);
|
||||
const float normalizedProgress = static_cast<float>(info.DrawState->LODTransition) * (1.0f / 255.0f);
|
||||
LODs[prevLOD].Draw(renderContext, info, normalizedProgress);
|
||||
model->LODs.Get()[prevLOD].Draw(renderContext, info, normalizedProgress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +221,7 @@ void SkinnedModel::Draw(RenderContext& renderContext, const SkinnedMesh::DrawInf
|
||||
}
|
||||
}
|
||||
lodIndex += info.LODBias + renderContext.View.ModelLODBias;
|
||||
lodIndex = ClampLODIndex(lodIndex);
|
||||
lodIndex = model->ClampLODIndex(lodIndex);
|
||||
|
||||
if (renderContext.View.IsSingleFrame)
|
||||
{
|
||||
@@ -253,22 +254,32 @@ void SkinnedModel::Draw(RenderContext& renderContext, const SkinnedMesh::DrawInf
|
||||
// Draw
|
||||
if (info.DrawState->PrevLOD == lodIndex || renderContext.View.IsSingleFrame)
|
||||
{
|
||||
LODs[lodIndex].Draw(renderContext, info, 0.0f);
|
||||
model->LODs.Get()[lodIndex].Draw(context, info, 0.0f);
|
||||
}
|
||||
else if (info.DrawState->PrevLOD == -1)
|
||||
{
|
||||
const float normalizedProgress = static_cast<float>(info.DrawState->LODTransition) * (1.0f / 255.0f);
|
||||
LODs[lodIndex].Draw(renderContext, info, 1.0f - normalizedProgress);
|
||||
model->LODs.Get()[lodIndex].Draw(context, info, 1.0f - normalizedProgress);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto prevLOD = ClampLODIndex(info.DrawState->PrevLOD);
|
||||
const auto prevLOD = model->ClampLODIndex(info.DrawState->PrevLOD);
|
||||
const float normalizedProgress = static_cast<float>(info.DrawState->LODTransition) * (1.0f / 255.0f);
|
||||
LODs[prevLOD].Draw(renderContext, info, normalizedProgress);
|
||||
LODs[lodIndex].Draw(renderContext, info, normalizedProgress - 1.0f);
|
||||
model->LODs.Get()[prevLOD].Draw(context, info, normalizedProgress);
|
||||
model->LODs.Get()[lodIndex].Draw(context, info, normalizedProgress - 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void SkinnedModel::Draw(const RenderContext& renderContext, const SkinnedMesh::DrawInfo& info)
|
||||
{
|
||||
SkinnedModelDraw(this, renderContext, renderContext, info);
|
||||
}
|
||||
|
||||
void SkinnedModel::Draw(const RenderContextBatch& renderContextBatch, const SkinnedMesh::DrawInfo& info)
|
||||
{
|
||||
SkinnedModelDraw(this, renderContextBatch.GetMainContext(), renderContextBatch, info);
|
||||
}
|
||||
|
||||
bool SkinnedModel::SetupLODs(const Span<int32>& meshesCountPerLod)
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
@@ -210,7 +210,14 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="info">The packed drawing info data.</param>
|
||||
void Draw(RenderContext& renderContext, const SkinnedMesh::DrawInfo& info);
|
||||
void Draw(const RenderContext& renderContext, const SkinnedMesh::DrawInfo& info);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the model.
|
||||
/// </summary>
|
||||
/// <param name="renderContextBatch">The rendering context batch.</param>
|
||||
/// <param name="info">The packed drawing info data.</param>
|
||||
void Draw(const RenderContextBatch& renderContextBatch, const SkinnedMesh::DrawInfo& info);
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
|
||||
@@ -407,6 +407,9 @@ void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, cons
|
||||
{
|
||||
if (!material || !material->IsSurface() || !IsInitialized())
|
||||
return;
|
||||
drawModes &= material->GetDrawModes();
|
||||
if (drawModes == DrawPass::None)
|
||||
return;
|
||||
|
||||
// Submit draw call
|
||||
DrawCall drawCall;
|
||||
@@ -436,18 +439,70 @@ void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, cons
|
||||
|
||||
void Mesh::Draw(const RenderContext& renderContext, const DrawInfo& info, float lodDitherFactor) const
|
||||
{
|
||||
// Cache data
|
||||
const auto& entry = info.Buffer->At(_materialSlotIndex);
|
||||
if (!entry.Visible || !IsInitialized())
|
||||
return;
|
||||
const MaterialSlot& slot = _model->MaterialSlots[_materialSlotIndex];
|
||||
|
||||
// Select material
|
||||
MaterialBase* material;
|
||||
if (entry.Material && entry.Material->IsLoaded())
|
||||
material = entry.Material;
|
||||
else if (slot.Material && slot.Material->IsLoaded())
|
||||
material = slot.Material;
|
||||
else
|
||||
material = GPUDevice::Instance->GetDefaultMaterial();
|
||||
if (!material || !material->IsSurface())
|
||||
return;
|
||||
|
||||
// Check if skip rendering
|
||||
const auto shadowsMode = static_cast<ShadowsCastingMode>(entry.ShadowsMode & slot.ShadowsMode);
|
||||
const auto drawModes = static_cast<DrawPass>(info.DrawModes & renderContext.View.GetShadowsDrawPassMask(shadowsMode));
|
||||
const auto shadowsMode = (ShadowsCastingMode)(entry.ShadowsMode & slot.ShadowsMode);
|
||||
const auto drawModes = (DrawPass)((uint32)info.DrawModes & (uint32)renderContext.View.Pass & (uint32)renderContext.View.GetShadowsDrawPassMask(shadowsMode) & (uint32)material->GetDrawModes());
|
||||
if (drawModes == DrawPass::None)
|
||||
return;
|
||||
|
||||
// Submit draw call
|
||||
DrawCall drawCall;
|
||||
drawCall.Geometry.IndexBuffer = _indexBuffer;
|
||||
drawCall.Geometry.VertexBuffers[0] = _vertexBuffers[0];
|
||||
drawCall.Geometry.VertexBuffers[1] = _vertexBuffers[1];
|
||||
drawCall.Geometry.VertexBuffers[2] = _vertexBuffers[2];
|
||||
drawCall.Geometry.VertexBuffersOffsets[0] = 0;
|
||||
drawCall.Geometry.VertexBuffersOffsets[1] = 0;
|
||||
drawCall.Geometry.VertexBuffersOffsets[2] = 0;
|
||||
if (info.VertexColors && info.VertexColors[_lodIndex])
|
||||
{
|
||||
// TODO: cache vertexOffset within the model LOD per-mesh
|
||||
uint32 vertexOffset = 0;
|
||||
for (int32 meshIndex = 0; meshIndex < _index; meshIndex++)
|
||||
vertexOffset += ((Model*)_model)->LODs[_lodIndex].Meshes[meshIndex].GetVertexCount();
|
||||
drawCall.Geometry.VertexBuffers[2] = info.VertexColors[_lodIndex];
|
||||
drawCall.Geometry.VertexBuffersOffsets[2] = vertexOffset * sizeof(VB2ElementType);
|
||||
}
|
||||
drawCall.Draw.StartIndex = 0;
|
||||
drawCall.Draw.IndicesCount = _triangles * 3;
|
||||
drawCall.InstanceCount = 1;
|
||||
drawCall.Material = material;
|
||||
drawCall.World = *info.World;
|
||||
drawCall.ObjectPosition = drawCall.World.GetTranslation();
|
||||
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;
|
||||
renderContext.List->AddDrawCall(drawModes, info.Flags, drawCall, entry.ReceiveDecals);
|
||||
}
|
||||
|
||||
void Mesh::Draw(const RenderContextBatch& renderContextBatch, const DrawInfo& info, float lodDitherFactor) const
|
||||
{
|
||||
const auto& entry = info.Buffer->At(_materialSlotIndex);
|
||||
if (!entry.Visible || !IsInitialized())
|
||||
return;
|
||||
const MaterialSlot& slot = _model->MaterialSlots[_materialSlotIndex];
|
||||
|
||||
// Select material
|
||||
MaterialBase* material;
|
||||
if (entry.Material && entry.Material->IsLoaded())
|
||||
@@ -491,7 +546,18 @@ void Mesh::Draw(const RenderContext& renderContext, const DrawInfo& info, float
|
||||
drawCall.Surface.LODDitherFactor = lodDitherFactor;
|
||||
drawCall.WorldDeterminantSign = Math::FloatSelect(drawCall.World.RotDeterminant(), 1, -1);
|
||||
drawCall.PerInstanceRandom = info.PerInstanceRandom;
|
||||
renderContext.List->AddDrawCall(drawModes, info.Flags, drawCall, entry.ReceiveDecals);
|
||||
|
||||
// Push draw call to every context
|
||||
const auto shadowsMode = (ShadowsCastingMode)(entry.ShadowsMode & slot.ShadowsMode);
|
||||
const auto materialDrawModes = material->GetDrawModes();
|
||||
for (const RenderContext& renderContext : renderContextBatch.Contexts)
|
||||
{
|
||||
const DrawPass drawModes = (DrawPass)((uint32)info.DrawModes & (uint32)renderContext.View.Pass & (uint32)renderContext.View.GetShadowsDrawPassMask(shadowsMode) & (uint32)materialDrawModes);
|
||||
if (drawModes != DrawPass::None && renderContext.View.CullingFrustum.Intersects(info.Bounds))
|
||||
{
|
||||
renderContext.List->AddDrawCall(drawModes, info.Flags, drawCall, entry.ReceiveDecals);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Mesh::DownloadDataGPU(MeshBufferType type, BytesContainer& result) const
|
||||
|
||||
@@ -367,6 +367,14 @@ public:
|
||||
/// <param name="lodDitherFactor">The LOD transition dither factor.</param>
|
||||
void Draw(const RenderContext& renderContext, const DrawInfo& info, float lodDitherFactor) const;
|
||||
|
||||
/// <summary>
|
||||
/// Draws the mesh.
|
||||
/// </summary>
|
||||
/// <param name="renderContextBatch">The rendering context batch.</param>
|
||||
/// <param name="info">The packed drawing info data.</param>
|
||||
/// <param name="lodDitherFactor">The LOD transition dither factor.</param>
|
||||
void Draw(const RenderContextBatch& renderContextBatch, const DrawInfo& info, float lodDitherFactor) const;
|
||||
|
||||
public:
|
||||
// [MeshBase]
|
||||
bool DownloadDataGPU(MeshBufferType type, BytesContainer& result) const override;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
class Task;
|
||||
class ModelBase;
|
||||
struct RenderContextBatch;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for model resources meshes.
|
||||
|
||||
@@ -116,7 +116,7 @@ public:
|
||||
{
|
||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||
{
|
||||
Meshes[i].Render(context);
|
||||
Meshes.Get()[i].Render(context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ public:
|
||||
{
|
||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||
{
|
||||
Meshes[i].Draw(renderContext, material, world, flags, receiveDecals, drawModes, perInstanceRandom);
|
||||
Meshes.Get()[i].Draw(renderContext, material, world, flags, receiveDecals, drawModes, perInstanceRandom);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +148,21 @@ public:
|
||||
{
|
||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||
{
|
||||
Meshes[i].Draw(renderContext, info, lodDitherFactor);
|
||||
Meshes.Get()[i].Draw(renderContext, info, lodDitherFactor);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws all the meshes from the model LOD.
|
||||
/// </summary>
|
||||
/// <param name="renderContextBatch">The rendering context batch.</param>
|
||||
/// <param name="info">The packed drawing info data.</param>
|
||||
/// <param name="lodDitherFactor">The LOD transition dither factor.</param>
|
||||
FORCE_INLINE void Draw(const RenderContextBatch& renderContextBatch, const Mesh::DrawInfo& info, float lodDitherFactor) const
|
||||
{
|
||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||
{
|
||||
Meshes.Get()[i].Draw(renderContextBatch, info, lodDitherFactor);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -152,18 +152,75 @@ void SkinnedMesh::Render(GPUContext* context) const
|
||||
|
||||
void SkinnedMesh::Draw(const RenderContext& renderContext, const DrawInfo& info, float lodDitherFactor) const
|
||||
{
|
||||
// Cache data
|
||||
const auto& entry = info.Buffer->At(_materialSlotIndex);
|
||||
if (!entry.Visible || !IsInitialized())
|
||||
return;
|
||||
const MaterialSlot& slot = _model->MaterialSlots[_materialSlotIndex];
|
||||
|
||||
// Select material
|
||||
MaterialBase* material;
|
||||
if (entry.Material && entry.Material->IsLoaded())
|
||||
material = entry.Material;
|
||||
else if (slot.Material && slot.Material->IsLoaded())
|
||||
material = slot.Material;
|
||||
else
|
||||
material = GPUDevice::Instance->GetDefaultMaterial();
|
||||
if (!material || !material->IsSurface())
|
||||
return;
|
||||
|
||||
// Check if skip rendering
|
||||
const auto shadowsMode = static_cast<ShadowsCastingMode>(entry.ShadowsMode & slot.ShadowsMode);
|
||||
const auto drawModes = static_cast<DrawPass>(info.DrawModes & renderContext.View.GetShadowsDrawPassMask(shadowsMode));
|
||||
const auto shadowsMode = (ShadowsCastingMode)(entry.ShadowsMode & slot.ShadowsMode);
|
||||
const auto drawModes = (DrawPass)((uint32)info.DrawModes & (uint32)renderContext.View.Pass & (uint32)renderContext.View.GetShadowsDrawPassMask(shadowsMode) & (uint32)material->GetDrawModes());
|
||||
if (drawModes == DrawPass::None)
|
||||
return;
|
||||
|
||||
// Submit draw call
|
||||
DrawCall drawCall;
|
||||
drawCall.Geometry.IndexBuffer = _indexBuffer;
|
||||
BlendShapesInstance::MeshInstance* blendShapeMeshInstance;
|
||||
if (info.BlendShapes && info.BlendShapes->Meshes.TryGet(this, blendShapeMeshInstance) && blendShapeMeshInstance->IsUsed)
|
||||
{
|
||||
// Use modified vertex buffer from the blend shapes
|
||||
if (blendShapeMeshInstance->IsDirty)
|
||||
{
|
||||
blendShapeMeshInstance->VertexBuffer.Flush();
|
||||
blendShapeMeshInstance->IsDirty = false;
|
||||
}
|
||||
drawCall.Geometry.VertexBuffers[0] = blendShapeMeshInstance->VertexBuffer.GetBuffer();
|
||||
}
|
||||
else
|
||||
{
|
||||
drawCall.Geometry.VertexBuffers[0] = _vertexBuffer;
|
||||
}
|
||||
drawCall.Geometry.VertexBuffers[1] = nullptr;
|
||||
drawCall.Geometry.VertexBuffers[2] = nullptr;
|
||||
drawCall.Geometry.VertexBuffersOffsets[0] = 0;
|
||||
drawCall.Geometry.VertexBuffersOffsets[1] = 0;
|
||||
drawCall.Geometry.VertexBuffersOffsets[2] = 0;
|
||||
drawCall.Draw.StartIndex = 0;
|
||||
drawCall.Draw.IndicesCount = _triangles * 3;
|
||||
drawCall.InstanceCount = 1;
|
||||
drawCall.Material = material;
|
||||
drawCall.World = *info.World;
|
||||
drawCall.ObjectPosition = drawCall.World.GetTranslation();
|
||||
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;
|
||||
renderContext.List->AddDrawCall(drawModes, StaticFlags::None, drawCall, entry.ReceiveDecals);
|
||||
}
|
||||
|
||||
void SkinnedMesh::Draw(const RenderContextBatch& renderContextBatch, const DrawInfo& info, float lodDitherFactor) const
|
||||
{
|
||||
const auto& entry = info.Buffer->At(_materialSlotIndex);
|
||||
if (!entry.Visible || !IsInitialized())
|
||||
return;
|
||||
const MaterialSlot& slot = _model->MaterialSlots[_materialSlotIndex];
|
||||
|
||||
// Select material
|
||||
MaterialBase* material;
|
||||
if (entry.Material && entry.Material->IsLoaded())
|
||||
@@ -212,7 +269,18 @@ void SkinnedMesh::Draw(const RenderContext& renderContext, const DrawInfo& info,
|
||||
drawCall.Surface.LODDitherFactor = lodDitherFactor;
|
||||
drawCall.WorldDeterminantSign = Math::FloatSelect(drawCall.World.RotDeterminant(), 1, -1);
|
||||
drawCall.PerInstanceRandom = info.PerInstanceRandom;
|
||||
renderContext.List->AddDrawCall(drawModes, StaticFlags::None, drawCall, entry.ReceiveDecals);
|
||||
|
||||
// Push draw call to every context
|
||||
const auto shadowsMode = (ShadowsCastingMode)(entry.ShadowsMode & slot.ShadowsMode);
|
||||
const auto materialDrawModes = material->GetDrawModes();
|
||||
for (const RenderContext& renderContext : renderContextBatch.Contexts)
|
||||
{
|
||||
const DrawPass drawModes = (DrawPass)((uint32)info.DrawModes & (uint32)renderContext.View.Pass & (uint32)renderContext.View.GetShadowsDrawPassMask(shadowsMode) & (uint32)materialDrawModes);
|
||||
if (drawModes != DrawPass::None && renderContext.View.CullingFrustum.Intersects(info.Bounds))
|
||||
{
|
||||
renderContext.List->AddDrawCall(drawModes, StaticFlags::None, drawCall, entry.ReceiveDecals);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SkinnedMesh::DownloadDataGPU(MeshBufferType type, BytesContainer& result) const
|
||||
|
||||
@@ -240,6 +240,14 @@ public:
|
||||
/// <param name="lodDitherFactor">The LOD transition dither factor.</param>
|
||||
void Draw(const RenderContext& renderContext, const DrawInfo& info, float lodDitherFactor) const;
|
||||
|
||||
/// <summary>
|
||||
/// Draws the mesh.
|
||||
/// </summary>
|
||||
/// <param name="renderContextBatch">The rendering context batch.</param>
|
||||
/// <param name="info">The packed drawing info data.</param>
|
||||
/// <param name="lodDitherFactor">The LOD transition dither factor.</param>
|
||||
void Draw(const RenderContextBatch& renderContextBatch, const DrawInfo& info, float lodDitherFactor) const;
|
||||
|
||||
public:
|
||||
// [MeshBase]
|
||||
bool DownloadDataGPU(MeshBufferType type, BytesContainer& result) const override;
|
||||
|
||||
@@ -102,7 +102,7 @@ public:
|
||||
{
|
||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||
{
|
||||
Meshes[i].Render(context);
|
||||
Meshes.Get()[i].Render(context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +116,21 @@ public:
|
||||
{
|
||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||
{
|
||||
Meshes[i].Draw(renderContext, info, lodDitherFactor);
|
||||
Meshes.Get()[i].Draw(renderContext, info, lodDitherFactor);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws all the meshes from the model LOD.
|
||||
/// </summary>
|
||||
/// <param name="renderContextBatch">The rendering context batch.</param>
|
||||
/// <param name="info">The packed drawing info data.</param>
|
||||
/// <param name="lodDitherFactor">The LOD transition dither factor.</param>
|
||||
FORCE_INLINE void Draw(const RenderContextBatch& renderContextBatch, const SkinnedMesh::DrawInfo& info, float lodDitherFactor) const
|
||||
{
|
||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||
{
|
||||
Meshes.Get()[i].Draw(renderContextBatch, info, lodDitherFactor);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -285,7 +285,7 @@ void AddActorToSceneRendering(SceneRendering* s, Actor* a)
|
||||
}
|
||||
}
|
||||
|
||||
void SceneRenderTask::OnCollectDrawCalls(RenderContext& renderContext, byte category)
|
||||
void SceneRenderTask::OnCollectDrawCalls(RenderContextBatch& renderContextBatch, byte category)
|
||||
{
|
||||
// Draw actors (collect draw calls)
|
||||
if ((ActorsSource & ActorsSources::CustomActors) != 0)
|
||||
@@ -296,15 +296,16 @@ void SceneRenderTask::OnCollectDrawCalls(RenderContext& renderContext, byte cate
|
||||
_customActorsScene->Clear();
|
||||
for (Actor* a : CustomActors)
|
||||
AddActorToSceneRendering(_customActorsScene, a);
|
||||
_customActorsScene->Draw(renderContext, (SceneRendering::DrawCategory)category);
|
||||
_customActorsScene->Draw(renderContextBatch, (SceneRendering::DrawCategory)category);
|
||||
}
|
||||
if ((ActorsSource & ActorsSources::Scenes) != 0)
|
||||
{
|
||||
Level::DrawActors(renderContext, category);
|
||||
Level::DrawActors(renderContextBatch, category);
|
||||
}
|
||||
|
||||
// External drawing event
|
||||
CollectDrawCalls(renderContext);
|
||||
for (RenderContext& renderContext : renderContextBatch.Contexts)
|
||||
CollectDrawCalls(renderContext);
|
||||
}
|
||||
|
||||
void SceneRenderTask::OnPreRender(GPUContext* context, RenderContext& renderContext)
|
||||
@@ -313,14 +314,16 @@ void SceneRenderTask::OnPreRender(GPUContext* context, RenderContext& renderCont
|
||||
|
||||
// Collect initial draw calls
|
||||
renderContext.View.Pass = DrawPass::GBuffer;
|
||||
OnCollectDrawCalls(renderContext, SceneRendering::PreRender);
|
||||
RenderContextBatch renderContextBatch(renderContext);
|
||||
OnCollectDrawCalls(renderContextBatch, SceneRendering::PreRender);
|
||||
}
|
||||
|
||||
void SceneRenderTask::OnPostRender(GPUContext* context, RenderContext& renderContext)
|
||||
{
|
||||
// Collect final draw calls
|
||||
renderContext.View.Pass = DrawPass::GBuffer;
|
||||
OnCollectDrawCalls(renderContext, SceneRendering::PostRender);
|
||||
RenderContextBatch renderContextBatch(renderContext);
|
||||
OnCollectDrawCalls(renderContextBatch, SceneRendering::PostRender);
|
||||
|
||||
PostRender(context, renderContext);
|
||||
}
|
||||
@@ -478,9 +481,22 @@ void MainRenderTask::OnBegin(GPUContext* context)
|
||||
SceneRenderTask::OnBegin(context);
|
||||
}
|
||||
|
||||
RenderContext::RenderContext(SceneRenderTask* task)
|
||||
RenderContext::RenderContext(SceneRenderTask* task) noexcept
|
||||
{
|
||||
Buffers = task->Buffers;
|
||||
Task = task;
|
||||
View = task->View;
|
||||
}
|
||||
|
||||
RenderContextBatch::RenderContextBatch(SceneRenderTask* task)
|
||||
{
|
||||
Buffers = task->Buffers;
|
||||
Task = task;
|
||||
}
|
||||
|
||||
RenderContextBatch::RenderContextBatch(const RenderContext& context)
|
||||
{
|
||||
Buffers = context.Buffers;
|
||||
Task = context.Task;
|
||||
Contexts.Add(context);
|
||||
}
|
||||
|
||||
@@ -310,9 +310,9 @@ public:
|
||||
/// <summary>
|
||||
/// Calls drawing scene objects.
|
||||
/// </summary>
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="renderContextBatch">The rendering context batch.</param>
|
||||
/// <param name="category">The actors category to draw (see SceneRendering::DrawCategory).</param>
|
||||
virtual void OnCollectDrawCalls(RenderContext& renderContext, byte category = 0);
|
||||
virtual void OnCollectDrawCalls(RenderContextBatch& renderContextBatch, byte category = 0);
|
||||
|
||||
/// <summary>
|
||||
/// The action called after scene rendering. Can be used to perform custom pre-rendering or to modify the render view.
|
||||
@@ -424,9 +424,43 @@ API_STRUCT(NoDefault) struct RenderContext
|
||||
/// </summary>
|
||||
API_FIELD() RenderView View;
|
||||
|
||||
RenderContext()
|
||||
RenderContext() = default;
|
||||
RenderContext(SceneRenderTask* task) noexcept;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The high-level renderer context batch that encapsulates multiple rendering requests within a single task (eg. optimize main view scene rendering and shadow projections at once).
|
||||
/// </summary>
|
||||
API_STRUCT(NoDefault) struct RenderContextBatch
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(RenderContextBatch);
|
||||
|
||||
/// <summary>
|
||||
/// The render buffers.
|
||||
/// </summary>
|
||||
API_FIELD() RenderBuffers* Buffers = nullptr;
|
||||
|
||||
/// <summary>
|
||||
/// The scene rendering task that is a source of renderable objects (optional).
|
||||
/// </summary>
|
||||
API_FIELD() SceneRenderTask* Task = nullptr;
|
||||
|
||||
/// <summary>
|
||||
/// The all render views collection for the current rendering (main view, shadow projections, etc.).
|
||||
/// </summary>
|
||||
API_FIELD() Array<RenderContext> Contexts;
|
||||
|
||||
RenderContextBatch() = default;
|
||||
RenderContextBatch(SceneRenderTask* task);
|
||||
RenderContextBatch(const RenderContext& context);
|
||||
|
||||
FORCE_INLINE RenderContext& GetMainContext()
|
||||
{
|
||||
return Contexts.Get()[0];
|
||||
}
|
||||
|
||||
RenderContext(SceneRenderTask* task);
|
||||
FORCE_INLINE const RenderContext& GetMainContext() const
|
||||
{
|
||||
return Contexts.Get()[0];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -60,7 +60,7 @@ void RenderView::Prepare(RenderContext& renderContext)
|
||||
PrepareCache(renderContext, width, height, taaJitter);
|
||||
}
|
||||
|
||||
void RenderView::PrepareCache(RenderContext& renderContext, float width, float height, const Float2& temporalAAJitter, RenderView* mainView)
|
||||
void RenderView::PrepareCache(const RenderContext& renderContext, float width, float height, const Float2& temporalAAJitter, const RenderView* mainView)
|
||||
{
|
||||
// The same format used by the Flax common shaders and postFx materials
|
||||
ViewInfo = Float4(1.0f / Projection.M11, 1.0f / Projection.M22, Far / (Far - Near), (-Far * Near) / (Far - Near) / Far);
|
||||
|
||||
@@ -12,7 +12,9 @@ namespace FlaxEngine
|
||||
MaxShadowsQuality = Quality.Ultra;
|
||||
ModelLODDistanceFactor = 1.0f;
|
||||
ModelLODDistanceFactorSqrt = 1.0f;
|
||||
#pragma warning disable 0612
|
||||
ShadowModelLODDistanceFactor = 1.0f;
|
||||
#pragma warning restore 0612
|
||||
Flags = ViewFlags.DefaultGame;
|
||||
Mode = ViewMode.Default;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "Enums.h"
|
||||
|
||||
struct RenderContext;
|
||||
struct RenderContextBatch;
|
||||
struct Viewport;
|
||||
class Camera;
|
||||
class RenderList;
|
||||
@@ -148,13 +149,15 @@ public:
|
||||
|
||||
/// <summary>
|
||||
/// The model LOD bias. Default is 0. Applied to all the objects in the shadow maps render views. Can be used to improve shadows rendering performance or increase quality.
|
||||
/// [Deprecated on 26.10.2022, expires on 26.10.2024]
|
||||
/// </summary>
|
||||
API_FIELD() int32 ShadowModelLODBias = 0;
|
||||
API_FIELD() DEPRECATED int32 ShadowModelLODBias = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The model LOD distance scale factor. Default is 1. Applied to all the objects in the shadow maps render views. Higher values increase LODs quality. Can be used to improve shadows rendering performance or increase quality.
|
||||
/// [Deprecated on 26.10.2022, expires on 26.10.2024]
|
||||
/// </summary>
|
||||
API_FIELD() float ShadowModelLODDistanceFactor = 1.0f;
|
||||
API_FIELD() DEPRECATED float ShadowModelLODDistanceFactor = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The Temporal Anti-Aliasing jitter frame index.
|
||||
@@ -231,7 +234,7 @@ public:
|
||||
/// <param name="height">The rendering height.</param>
|
||||
/// <param name="temporalAAJitter">The temporal jitter for this frame.</param>
|
||||
/// <param name="mainView">The main rendering viewport. Use null if it's top level view; pass pointer to main view for sub-passes like shadow depths.</param>
|
||||
void PrepareCache(RenderContext& renderContext, float width, float height, const Float2& temporalAAJitter, RenderView* mainView = nullptr);
|
||||
void PrepareCache(const RenderContext& renderContext, float width, float height, const Float2& temporalAAJitter, const RenderView* mainView = nullptr);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether view is perspective projection or orthographic.
|
||||
|
||||
@@ -1218,6 +1218,13 @@ void Actor::Draw(RenderContext& renderContext)
|
||||
{
|
||||
}
|
||||
|
||||
void Actor::Draw(RenderContextBatch& renderContextBatch)
|
||||
{
|
||||
// Default impl calls single-context
|
||||
for (RenderContext& renderContext : renderContextBatch.Contexts)
|
||||
Draw(renderContext);
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
void Actor::OnDebugDraw()
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
struct RenderView;
|
||||
struct RenderContext;
|
||||
struct RenderContextBatch;
|
||||
class GPUContext;
|
||||
class MemoryWriteStream;
|
||||
class PhysicsScene;
|
||||
@@ -675,6 +676,12 @@ public:
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
virtual void Draw(RenderContext& renderContext);
|
||||
|
||||
/// <summary>
|
||||
/// Draws this actor. Called by Scene Rendering service. This call is more optimized than generic Draw (eg. geometry is rendered during all pass types but other actors are drawn only during GBufferFill pass).
|
||||
/// </summary>
|
||||
/// <param name="renderContextBatch">The rendering context batch (eg, main view and shadow projections).</param>
|
||||
virtual void Draw(RenderContextBatch& renderContextBatch);
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -707,8 +707,7 @@ void AnimatedModel::Draw(RenderContext& renderContext)
|
||||
renderContext.View.GetWorldMatrix(_transform, world);
|
||||
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
|
||||
|
||||
const DrawPass drawModes = (DrawPass)(DrawModes & renderContext.View.Pass & (int32)renderContext.View.GetShadowsDrawPassMask(ShadowsMode));
|
||||
if (SkinnedModel && SkinnedModel->IsLoaded() && drawModes != DrawPass::None)
|
||||
if (SkinnedModel && SkinnedModel->IsLoaded())
|
||||
{
|
||||
_lastMinDstSqr = Math::Min(_lastMinDstSqr, Vector3::DistanceSquared(_transform.Translation, renderContext.View.Position + renderContext.View.Origin));
|
||||
|
||||
@@ -728,7 +727,9 @@ void AnimatedModel::Draw(RenderContext& renderContext)
|
||||
draw.BlendShapes = &_blendShapes;
|
||||
draw.World = &world;
|
||||
draw.DrawState = &_drawState;
|
||||
draw.DrawModes = drawModes;
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
draw.DrawModes = (DrawPass)(DrawModes & renderContext.View.GetShadowsDrawPassMask(ShadowsMode));
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
draw.Bounds = _sphere;
|
||||
draw.Bounds.Center -= renderContext.View.Origin;
|
||||
draw.PerInstanceRandom = GetPerInstanceRandom();
|
||||
@@ -742,6 +743,58 @@ void AnimatedModel::Draw(RenderContext& renderContext)
|
||||
GEOMETRY_DRAW_STATE_EVENT_END(_drawState, world);
|
||||
}
|
||||
|
||||
void AnimatedModel::Draw(RenderContextBatch& renderContextBatch)
|
||||
{
|
||||
if (!SkinnedModel || !SkinnedModel->IsLoaded())
|
||||
return;
|
||||
const RenderContext& renderContext = renderContextBatch.GetMainContext();
|
||||
Matrix world;
|
||||
renderContext.View.GetWorldMatrix(_transform, world);
|
||||
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
|
||||
_lastMinDstSqr = Math::Min(_lastMinDstSqr, Vector3::DistanceSquared(_transform.Translation, renderContext.View.Position + renderContext.View.Origin));
|
||||
if (_skinningData.IsReady())
|
||||
{
|
||||
#if USE_EDITOR
|
||||
// Disable motion blur effects in editor without play mode enabled to hide minor artifacts on objects moving
|
||||
if (!Editor::IsPlayMode)
|
||||
_drawState.PrevWorld = world;
|
||||
#endif
|
||||
|
||||
_skinningData.Flush(GPUDevice::Instance->GetMainContext());
|
||||
|
||||
SkinnedMesh::DrawInfo draw;
|
||||
draw.Buffer = &Entries;
|
||||
draw.Skinning = &_skinningData;
|
||||
draw.BlendShapes = &_blendShapes;
|
||||
draw.World = &world;
|
||||
draw.DrawState = &_drawState;
|
||||
draw.DrawModes = DrawModes;
|
||||
draw.Bounds = _sphere;
|
||||
draw.Bounds.Center -= renderContext.View.Origin;
|
||||
draw.PerInstanceRandom = GetPerInstanceRandom();
|
||||
draw.LODBias = LODBias;
|
||||
draw.ForcedLOD = ForcedLOD;
|
||||
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
if (ShadowsMode != ShadowsCastingMode::All)
|
||||
{
|
||||
// To handle old ShadowsMode option for all meshes we need to call per-context drawing (no batching opportunity)
|
||||
// TODO: maybe deserialize ShadowsMode into ModelInstanceBuffer entries options?
|
||||
for (auto& e : renderContextBatch.Contexts)
|
||||
{
|
||||
draw.DrawModes = (DrawPass)(DrawModes & e.View.GetShadowsDrawPassMask(ShadowsMode));
|
||||
SkinnedModel->Draw(e, draw);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SkinnedModel->Draw(renderContextBatch, draw);
|
||||
}
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
}
|
||||
GEOMETRY_DRAW_STATE_EVENT_END(_drawState, world);
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "Engine/Debug/DebugDraw.h"
|
||||
@@ -795,7 +848,9 @@ void AnimatedModel::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
SERIALIZE(LODBias);
|
||||
SERIALIZE(ForcedLOD);
|
||||
SERIALIZE(DrawModes);
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
SERIALIZE(ShadowsMode);
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
SERIALIZE(RootMotionTarget);
|
||||
|
||||
stream.JKEY("Buffer");
|
||||
@@ -819,7 +874,9 @@ void AnimatedModel::Deserialize(DeserializeStream& stream, ISerializeModifier* m
|
||||
DESERIALIZE(LODBias);
|
||||
DESERIALIZE(ForcedLOD);
|
||||
DESERIALIZE(DrawModes);
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
DESERIALIZE(ShadowsMode);
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
DESERIALIZE(RootMotionTarget);
|
||||
|
||||
Entries.DeserializeIfExists(stream, "Buffer", modifier);
|
||||
@@ -889,7 +946,7 @@ void AnimatedModel::OnDeleteObject()
|
||||
{
|
||||
// Ensure this object is no longer referenced for anim update
|
||||
Animations::RemoveFromUpdate(this);
|
||||
|
||||
|
||||
ModelInstanceActor::OnDeleteObject();
|
||||
}
|
||||
|
||||
|
||||
@@ -139,9 +139,10 @@ public:
|
||||
|
||||
/// <summary>
|
||||
/// The shadows casting mode.
|
||||
/// [Deprecated on 26.10.2022, expires on 26.10.2024]
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(110), DefaultValue(ShadowsCastingMode.All), EditorDisplay(\"Skinned Model\")")
|
||||
ShadowsCastingMode ShadowsMode = ShadowsCastingMode::All;
|
||||
DEPRECATED ShadowsCastingMode ShadowsMode = ShadowsCastingMode::All;
|
||||
|
||||
/// <summary>
|
||||
/// The animation root motion apply target. If not specified the animated model will apply it itself.
|
||||
@@ -358,6 +359,7 @@ public:
|
||||
// [ModelInstanceActor]
|
||||
bool HasContentLoaded() const override;
|
||||
void Draw(RenderContext& renderContext) override;
|
||||
void Draw(RenderContextBatch& renderContextBatch) override;
|
||||
#if USE_EDITOR
|
||||
void OnDebugDrawSelected() override;
|
||||
BoundingBox GetEditorBox() const override;
|
||||
|
||||
@@ -410,12 +410,6 @@ void SplineModel::Draw(RenderContext& renderContext)
|
||||
continue;
|
||||
const MaterialSlot& slot = model->MaterialSlots[mesh->GetMaterialSlotIndex()];
|
||||
|
||||
// Check if skip rendering
|
||||
const auto shadowsMode = static_cast<ShadowsCastingMode>(entry.ShadowsMode & slot.ShadowsMode);
|
||||
const auto drawModes = static_cast<DrawPass>(actorDrawModes & renderContext.View.GetShadowsDrawPassMask(shadowsMode));
|
||||
if (drawModes == DrawPass::None)
|
||||
continue;
|
||||
|
||||
// Select material
|
||||
MaterialBase* material = nullptr;
|
||||
if (entry.Material && entry.Material->IsLoaded())
|
||||
@@ -427,6 +421,12 @@ void SplineModel::Draw(RenderContext& renderContext)
|
||||
if (!material || !material->IsDeformable())
|
||||
continue;
|
||||
|
||||
// Check if skip rendering
|
||||
const auto shadowsMode = static_cast<ShadowsCastingMode>(entry.ShadowsMode & slot.ShadowsMode);
|
||||
const auto drawModes = static_cast<DrawPass>(actorDrawModes & renderContext.View.GetShadowsDrawPassMask(shadowsMode) & (uint32)material->GetDrawModes());
|
||||
if (drawModes == DrawPass::None)
|
||||
continue;
|
||||
|
||||
// Submit draw call
|
||||
mesh->GetDrawCallGeometry(drawCall);
|
||||
drawCall.Material = material;
|
||||
|
||||
@@ -222,6 +222,31 @@ void StaticModel::UpdateBounds()
|
||||
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
|
||||
}
|
||||
|
||||
void StaticModel::FlushVertexColors()
|
||||
{
|
||||
for (int32 lodIndex = 0; lodIndex < _vertexColorsCount; lodIndex++)
|
||||
{
|
||||
auto& vertexColorsData = _vertexColorsData[lodIndex];
|
||||
auto& vertexColorsBuffer = _vertexColorsBuffer[lodIndex];
|
||||
if (vertexColorsData.HasItems())
|
||||
{
|
||||
const uint32 size = vertexColorsData.Count() * sizeof(Color32);
|
||||
if (!vertexColorsBuffer)
|
||||
vertexColorsBuffer = GPUDevice::Instance->CreateBuffer(TEXT("VertexColors"));
|
||||
if (vertexColorsBuffer->GetSize() != size)
|
||||
{
|
||||
if (vertexColorsBuffer->Init(GPUBufferDescription::Vertex(sizeof(Color32), vertexColorsData.Count())))
|
||||
return;
|
||||
}
|
||||
GPUDevice::Instance->GetMainContext()->UpdateBuffer(vertexColorsBuffer, vertexColorsData.Get(), size);
|
||||
}
|
||||
else
|
||||
{
|
||||
SAFE_DELETE_GPU_RESOURCE(vertexColorsBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool StaticModel::HasContentLoaded() const
|
||||
{
|
||||
return (Model == nullptr || Model->IsLoaded()) && Entries.HasContentLoaded();
|
||||
@@ -229,8 +254,7 @@ bool StaticModel::HasContentLoaded() const
|
||||
|
||||
void StaticModel::Draw(RenderContext& renderContext)
|
||||
{
|
||||
const DrawPass drawModes = (DrawPass)(DrawModes & renderContext.View.Pass);
|
||||
if (!Model || !Model->IsLoaded() || !Model->CanBeRendered() || drawModes == DrawPass::None)
|
||||
if (!Model || !Model->IsLoaded() || !Model->CanBeRendered())
|
||||
return;
|
||||
if (renderContext.View.Pass == DrawPass::GlobalSDF)
|
||||
{
|
||||
@@ -246,32 +270,8 @@ void StaticModel::Draw(RenderContext& renderContext)
|
||||
renderContext.View.GetWorldMatrix(_transform, world);
|
||||
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
|
||||
|
||||
// Flush vertex colors if need to
|
||||
if (_vertexColorsDirty)
|
||||
{
|
||||
for (int32 lodIndex = 0; lodIndex < _vertexColorsCount; lodIndex++)
|
||||
{
|
||||
auto& vertexColorsData = _vertexColorsData[lodIndex];
|
||||
auto& vertexColorsBuffer = _vertexColorsBuffer[lodIndex];
|
||||
if (vertexColorsData.HasItems())
|
||||
{
|
||||
const uint32 size = vertexColorsData.Count() * sizeof(Color32);
|
||||
if (!vertexColorsBuffer)
|
||||
vertexColorsBuffer = GPUDevice::Instance->CreateBuffer(TEXT("VertexColors"));
|
||||
if (vertexColorsBuffer->GetSize() != size)
|
||||
{
|
||||
if (vertexColorsBuffer->Init(GPUBufferDescription::Vertex(sizeof(Color32), vertexColorsData.Count())))
|
||||
return;
|
||||
}
|
||||
GPUDevice::Instance->GetMainContext()->UpdateBuffer(vertexColorsBuffer, vertexColorsData.Get(), size);
|
||||
}
|
||||
else
|
||||
{
|
||||
SAFE_DELETE_GPU_RESOURCE(vertexColorsBuffer);
|
||||
}
|
||||
}
|
||||
_vertexColorsDirty = false;
|
||||
}
|
||||
FlushVertexColors();
|
||||
|
||||
#if USE_EDITOR
|
||||
// Disable motion blur effects in editor without play mode enabled to hide minor artifacts on objects moving
|
||||
@@ -286,7 +286,7 @@ void StaticModel::Draw(RenderContext& renderContext)
|
||||
draw.Lightmap = _scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex);
|
||||
draw.LightmapUVs = &Lightmap.UVsArea;
|
||||
draw.Flags = _staticFlags;
|
||||
draw.DrawModes = drawModes;
|
||||
draw.DrawModes = DrawModes;
|
||||
draw.Bounds = _sphere;
|
||||
draw.Bounds.Center -= renderContext.View.Origin;
|
||||
draw.PerInstanceRandom = GetPerInstanceRandom();
|
||||
@@ -299,6 +299,44 @@ void StaticModel::Draw(RenderContext& renderContext)
|
||||
GEOMETRY_DRAW_STATE_EVENT_END(_drawState, world);
|
||||
}
|
||||
|
||||
void StaticModel::Draw(RenderContextBatch& renderContextBatch)
|
||||
{
|
||||
if (!Model || !Model->IsLoaded())
|
||||
return;
|
||||
const RenderContext& renderContext = renderContextBatch.GetMainContext();
|
||||
Matrix world;
|
||||
renderContext.View.GetWorldMatrix(_transform, world);
|
||||
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
|
||||
|
||||
if (_vertexColorsDirty)
|
||||
FlushVertexColors();
|
||||
|
||||
#if USE_EDITOR
|
||||
// Disable motion blur effects in editor without play mode enabled to hide minor artifacts on objects moving
|
||||
if (!Editor::IsPlayMode)
|
||||
_drawState.PrevWorld = world;
|
||||
#endif
|
||||
|
||||
Mesh::DrawInfo draw;
|
||||
draw.Buffer = &Entries;
|
||||
draw.World = &world;
|
||||
draw.DrawState = &_drawState;
|
||||
draw.Lightmap = _scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex);
|
||||
draw.LightmapUVs = &Lightmap.UVsArea;
|
||||
draw.Flags = _staticFlags;
|
||||
draw.DrawModes = DrawModes;
|
||||
draw.Bounds = _sphere;
|
||||
draw.Bounds.Center -= renderContext.View.Origin;
|
||||
draw.PerInstanceRandom = GetPerInstanceRandom();
|
||||
draw.LODBias = _lodBias;
|
||||
draw.ForcedLOD = _forcedLod;
|
||||
draw.VertexColors = _vertexColorsCount ? _vertexColorsBuffer : nullptr;
|
||||
|
||||
Model->Draw(renderContextBatch, draw);
|
||||
|
||||
GEOMETRY_DRAW_STATE_EVENT_END(_drawState, world);
|
||||
}
|
||||
|
||||
bool StaticModel::IntersectsItself(const Ray& ray, Real& distance, Vector3& normal)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
@@ -171,11 +171,13 @@ private:
|
||||
void OnModelLoaded();
|
||||
void OnModelResidencyChanged();
|
||||
void UpdateBounds();
|
||||
void FlushVertexColors();
|
||||
|
||||
public:
|
||||
// [ModelInstanceActor]
|
||||
bool HasContentLoaded() const override;
|
||||
void Draw(RenderContext& renderContext) override;
|
||||
void Draw(RenderContextBatch& renderContextBatch) override;
|
||||
bool IntersectsItself(const Ray& ray, Real& distance, Vector3& normal) override;
|
||||
void Serialize(SerializeStream& stream, const void* otherObj) override;
|
||||
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
|
||||
|
||||
@@ -389,7 +389,7 @@ void Level::CallBeginPlay(Actor* obj)
|
||||
}
|
||||
}
|
||||
|
||||
void Level::DrawActors(RenderContext& renderContext, byte category)
|
||||
void Level::DrawActors(RenderContextBatch& renderContextBatch, byte category)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
|
||||
@@ -398,7 +398,7 @@ void Level::DrawActors(RenderContext& renderContext, byte category)
|
||||
for (Scene* scene : Scenes)
|
||||
{
|
||||
if (scene->IsActiveInHierarchy())
|
||||
scene->Rendering.Draw(renderContext, (SceneRendering::DrawCategory)category);
|
||||
scene->Rendering.Draw(renderContextBatch, (SceneRendering::DrawCategory)category);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ class JsonWriter;
|
||||
class Engine;
|
||||
struct RenderView;
|
||||
struct RenderContext;
|
||||
struct RenderContextBatch;
|
||||
|
||||
/// <summary>
|
||||
/// The scene manager that contains the loaded scenes collection and spawns/deleted actors.
|
||||
@@ -163,9 +164,9 @@ public:
|
||||
/// <summary>
|
||||
/// Draws all the actors.
|
||||
/// </summary>
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="renderContextBatch">The rendering context batch.</param>
|
||||
/// <param name="category">The actors category to draw (see SceneRendering::DrawCategory).</param>
|
||||
static void DrawActors(RenderContext& renderContext, byte category = 0);
|
||||
static void DrawActors(RenderContextBatch& renderContextBatch, byte category = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Collects all the post fx volumes.
|
||||
|
||||
@@ -11,6 +11,16 @@
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#endif
|
||||
|
||||
FORCE_INLINE bool FrustumsListCull(const BoundingSphere& bounds, const BoundingFrustum* frustums, int32 frustumsCount)
|
||||
{
|
||||
for (int32 i = 0; i < frustumsCount; i++)
|
||||
{
|
||||
if (frustums[i].Intersects(bounds))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ISceneRenderingListener::~ISceneRenderingListener()
|
||||
{
|
||||
for (SceneRendering* scene : _scenes)
|
||||
@@ -28,60 +38,90 @@ void ISceneRenderingListener::ListenSceneRendering(SceneRendering* scene)
|
||||
}
|
||||
}
|
||||
|
||||
void SceneRendering::Draw(RenderContext& renderContext, DrawCategory category)
|
||||
void SceneRendering::Draw(RenderContextBatch& renderContextBatch, DrawCategory category)
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
auto& view = renderContext.View;
|
||||
const BoundingFrustum frustum = view.CullingFrustum;
|
||||
auto& view = renderContextBatch.GetMainContext().View;
|
||||
const Vector3 origin = view.Origin;
|
||||
renderContext.List->Scenes.Add(this);
|
||||
for (auto& renderContext : renderContextBatch.Contexts)
|
||||
renderContext.List->Scenes.Add(this);
|
||||
auto& list = Actors[(int32)category];
|
||||
|
||||
// Setup frustum data
|
||||
Array<BoundingFrustum, RenderListAllocation> frustumsData;
|
||||
BoundingFrustum* frustums = &view.CullingFrustum;
|
||||
int32 frustumsCount = renderContextBatch.Contexts.Count();
|
||||
if (frustumsCount != 1)
|
||||
{
|
||||
frustumsData.Resize(frustumsCount);
|
||||
frustums = frustumsData.Get();
|
||||
for (int32 i = 0; i < frustumsCount; i++)
|
||||
frustums[i] = renderContextBatch.Contexts[i].View.CullingFrustum;
|
||||
}
|
||||
|
||||
#define CHECK_ACTOR ((view.RenderLayersMask.Mask & e.LayerMask) && (e.NoCulling || FrustumsListCull(e.Bounds, frustums, frustumsCount)))
|
||||
#define CHECK_ACTOR_SINGLE_FRUSTUM ((view.RenderLayersMask.Mask & e.LayerMask) && (e.NoCulling || frustums->Intersects(e.Bounds)))
|
||||
#if SCENE_RENDERING_USE_PROFILER
|
||||
#define DRAW_ACTOR(mode) PROFILE_CPU_ACTOR(e.Actor); e.Actor->Draw(mode)
|
||||
#else
|
||||
#define DRAW_ACTOR(mode) e.Actor->Draw(mode)
|
||||
#endif
|
||||
|
||||
// Draw all visual components
|
||||
if (view.IsOfflinePass)
|
||||
{
|
||||
// Offline pass with additional static flags culling
|
||||
for (int32 i = 0; i < list.Count(); i++)
|
||||
{
|
||||
auto e = list.Get()[i];
|
||||
e.Bounds.Center -= origin;
|
||||
if (view.RenderLayersMask.Mask & e.LayerMask && (e.NoCulling || frustum.Intersects(e.Bounds)) && e.Actor->GetStaticFlags() & view.StaticFlagsMask)
|
||||
if (CHECK_ACTOR && e.Actor->GetStaticFlags() & view.StaticFlagsMask)
|
||||
{
|
||||
#if SCENE_RENDERING_USE_PROFILER
|
||||
PROFILE_CPU_ACTOR(e.Actor);
|
||||
#endif
|
||||
e.Actor->Draw(renderContext);
|
||||
DRAW_ACTOR(renderContextBatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (origin.IsZero() && frustumsCount == 1)
|
||||
{
|
||||
// Fast path for no origin shifting with a single context
|
||||
auto& renderContext = renderContextBatch.Contexts[0];
|
||||
for (int32 i = 0; i < list.Count(); i++)
|
||||
{
|
||||
auto e = list.Get()[i];
|
||||
if (CHECK_ACTOR_SINGLE_FRUSTUM)
|
||||
{
|
||||
DRAW_ACTOR(renderContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (origin.IsZero())
|
||||
{
|
||||
// Fast path for no origin shifting
|
||||
for (int32 i = 0; i < list.Count(); i++)
|
||||
{
|
||||
auto e = list.Get()[i];
|
||||
if (view.RenderLayersMask.Mask & e.LayerMask && (e.NoCulling || frustum.Intersects(e.Bounds)))
|
||||
if (CHECK_ACTOR)
|
||||
{
|
||||
#if SCENE_RENDERING_USE_PROFILER
|
||||
PROFILE_CPU_ACTOR(e.Actor);
|
||||
#endif
|
||||
e.Actor->Draw(renderContext);
|
||||
DRAW_ACTOR(renderContextBatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Generic case
|
||||
for (int32 i = 0; i < list.Count(); i++)
|
||||
{
|
||||
auto e = list.Get()[i];
|
||||
e.Bounds.Center -= origin;
|
||||
if (view.RenderLayersMask.Mask & e.LayerMask && (e.NoCulling || frustum.Intersects(e.Bounds)))
|
||||
if (CHECK_ACTOR)
|
||||
{
|
||||
#if SCENE_RENDERING_USE_PROFILER
|
||||
PROFILE_CPU_ACTOR(e.Actor);
|
||||
#endif
|
||||
e.Actor->Draw(renderContext);
|
||||
DRAW_ACTOR(renderContextBatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef CHECK_ACTOR
|
||||
#undef DRAW_ACTOR
|
||||
#if USE_EDITOR
|
||||
if (view.Pass & DrawPass::GBuffer && category == SceneDraw)
|
||||
{
|
||||
|
||||
@@ -12,6 +12,7 @@ class SceneRenderTask;
|
||||
class SceneRendering;
|
||||
struct PostProcessSettings;
|
||||
struct RenderContext;
|
||||
struct RenderContextBatch;
|
||||
struct RenderView;
|
||||
|
||||
/// <summary>
|
||||
@@ -103,9 +104,9 @@ public:
|
||||
/// <summary>
|
||||
/// Draws the scene. Performs the optimized actors culling and draw calls submission for the current render pass (defined by the render view).
|
||||
/// </summary>
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="renderContextBatch">The rendering context batch.</param>
|
||||
/// <param name="category">The actors category to draw.</param>
|
||||
void Draw(RenderContext& renderContext, DrawCategory category = DrawCategory::SceneDraw);
|
||||
void Draw(RenderContextBatch& renderContextBatch, DrawCategory category = SceneDraw);
|
||||
|
||||
/// <summary>
|
||||
/// Collects the post fx volumes for the given rendering view.
|
||||
|
||||
@@ -408,12 +408,15 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
|
||||
{
|
||||
const auto material = (MaterialBase*)module->Assets[0].Get();
|
||||
const auto moduleDrawModes = module->Values.Count() > 3 ? (DrawPass)module->Values[3].AsInt : DrawPass::Default;
|
||||
auto dp = (DrawPass)(drawModes & moduleDrawModes & (uint32)material->GetDrawModes());
|
||||
if (dp == DrawPass::None)
|
||||
break;
|
||||
drawCall.Material = material;
|
||||
|
||||
// Submit draw call
|
||||
SpriteRenderer.SetupDrawCall(drawCall);
|
||||
drawCall.InstanceCount = buffer->CPU.Count;
|
||||
renderContext.List->AddDrawCall((DrawPass)(drawModes & moduleDrawModes), staticFlags, drawCall, false);
|
||||
renderContext.List->AddDrawCall(dp, staticFlags, drawCall, false);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -423,6 +426,9 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
|
||||
const auto model = (Model*)module->Assets[0].Get();
|
||||
const auto material = (MaterialBase*)module->Assets[1].Get();
|
||||
const auto moduleDrawModes = module->Values.Count() > 4 ? (DrawPass)module->Values[4].AsInt : DrawPass::Default;
|
||||
auto dp = (DrawPass)(drawModes & moduleDrawModes & (uint32)material->GetDrawModes());
|
||||
if (dp == DrawPass::None)
|
||||
break;
|
||||
drawCall.Material = material;
|
||||
|
||||
// TODO: model LOD picking for particles?
|
||||
@@ -438,7 +444,7 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
|
||||
// Submit draw call
|
||||
mesh.GetDrawCallGeometry(drawCall);
|
||||
drawCall.InstanceCount = buffer->CPU.Count;
|
||||
renderContext.List->AddDrawCall((DrawPass)(drawModes & moduleDrawModes), staticFlags, drawCall, false);
|
||||
renderContext.List->AddDrawCall(dp, staticFlags, drawCall, false);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -450,6 +456,9 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
|
||||
break;
|
||||
const auto material = (MaterialBase*)module->Assets[0].Get();
|
||||
const auto moduleDrawModes = module->Values.Count() > 6 ? (DrawPass)module->Values[6].AsInt : DrawPass::Default;
|
||||
auto dp = (DrawPass)(drawModes & moduleDrawModes & (uint32)material->GetDrawModes());
|
||||
if (dp == DrawPass::None)
|
||||
break;
|
||||
drawCall.Material = material;
|
||||
|
||||
// Node properties
|
||||
@@ -495,7 +504,7 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
|
||||
drawCall.Draw.StartIndex = ribbonModulesDrawIndicesStart[ribbonModuleIndex];
|
||||
drawCall.Draw.IndicesCount = ribbonModulesDrawIndicesCount[ribbonModuleIndex];
|
||||
drawCall.InstanceCount = 1;
|
||||
renderContext.List->AddDrawCall((DrawPass)(drawModes & moduleDrawModes), staticFlags, drawCall, false);
|
||||
renderContext.List->AddDrawCall(dp, staticFlags, drawCall, false);
|
||||
|
||||
ribbonModuleIndex++;
|
||||
|
||||
@@ -810,6 +819,7 @@ void DrawEmitterGPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
|
||||
{
|
||||
const auto material = (MaterialBase*)module->Assets[0].Get();
|
||||
const auto moduleDrawModes = module->Values.Count() > 3 ? (DrawPass)module->Values[3].AsInt : DrawPass::Default;
|
||||
auto dp = (DrawPass)(drawModes & moduleDrawModes & (uint32)material->GetDrawModes());
|
||||
drawCall.Material = material;
|
||||
|
||||
// Submit draw call
|
||||
@@ -817,7 +827,8 @@ void DrawEmitterGPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
|
||||
drawCall.InstanceCount = 0;
|
||||
drawCall.Draw.IndirectArgsBuffer = buffer->GPU.IndirectDrawArgsBuffer;
|
||||
drawCall.Draw.IndirectArgsOffset = indirectDrawCallIndex * sizeof(GPUDrawIndexedIndirectArgs);
|
||||
renderContext.List->AddDrawCall((DrawPass)(drawModes & moduleDrawModes), staticFlags, drawCall, false);
|
||||
if (dp != DrawPass::None)
|
||||
renderContext.List->AddDrawCall(dp, staticFlags, drawCall, false);
|
||||
indirectDrawCallIndex++;
|
||||
|
||||
break;
|
||||
@@ -828,6 +839,7 @@ void DrawEmitterGPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
|
||||
const auto model = (Model*)module->Assets[0].Get();
|
||||
const auto material = (MaterialBase*)module->Assets[1].Get();
|
||||
const auto moduleDrawModes = module->Values.Count() > 4 ? (DrawPass)module->Values[4].AsInt : DrawPass::Default;
|
||||
auto dp = (DrawPass)(drawModes & moduleDrawModes & (uint32)material->GetDrawModes());
|
||||
drawCall.Material = material;
|
||||
|
||||
// TODO: model LOD picking for particles?
|
||||
@@ -845,7 +857,8 @@ void DrawEmitterGPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
|
||||
drawCall.InstanceCount = 0;
|
||||
drawCall.Draw.IndirectArgsBuffer = buffer->GPU.IndirectDrawArgsBuffer;
|
||||
drawCall.Draw.IndirectArgsOffset = indirectDrawCallIndex * sizeof(GPUDrawIndexedIndirectArgs);
|
||||
renderContext.List->AddDrawCall((DrawPass)(drawModes & moduleDrawModes), staticFlags, drawCall, false);
|
||||
if (dp != DrawPass::None)
|
||||
renderContext.List->AddDrawCall(dp, staticFlags, drawCall, false);
|
||||
indirectDrawCallIndex++;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,12 +63,12 @@ void TAA::Dispose()
|
||||
_shader = nullptr;
|
||||
}
|
||||
|
||||
bool TAA::NeedMotionVectors(RenderContext& renderContext)
|
||||
bool TAA::NeedMotionVectors(const RenderContext& renderContext)
|
||||
{
|
||||
return renderContext.List->Settings.AntiAliasing.Mode == AntialiasingMode::TemporalAntialiasing;
|
||||
}
|
||||
|
||||
void TAA::Render(RenderContext& renderContext, GPUTexture* input, GPUTextureView* output)
|
||||
void TAA::Render(const RenderContext& renderContext, GPUTexture* input, GPUTextureView* output)
|
||||
{
|
||||
auto context = GPUDevice::Instance->GetMainContext();
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <returns>True if need to render motion vectors, otherwise false.</returns>
|
||||
static bool NeedMotionVectors(RenderContext& renderContext);
|
||||
static bool NeedMotionVectors(const RenderContext& renderContext);
|
||||
|
||||
/// <summary>
|
||||
/// Performs AA pass rendering for the input task.
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="input">The input render target.</param>
|
||||
/// <param name="output">The output render target.</param>
|
||||
void Render(RenderContext& renderContext, GPUTexture* input, GPUTextureView* output);
|
||||
void Render(const RenderContext& renderContext, GPUTexture* input, GPUTextureView* output);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -518,7 +518,6 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
|
||||
renderContextTiles.View.Pass = DrawPass::GBuffer | DrawPass::GlobalSurfaceAtlas;
|
||||
renderContextTiles.View.Mode = ViewMode::Default;
|
||||
renderContextTiles.View.ModelLODBias += 100000;
|
||||
renderContextTiles.View.ShadowModelLODBias += 100000;
|
||||
renderContextTiles.View.IsSingleFrame = true;
|
||||
renderContextTiles.View.IsCullingDisabled = true;
|
||||
renderContextTiles.View.Near = 0.0f;
|
||||
|
||||
@@ -150,7 +150,7 @@ void LightPass::Dispose()
|
||||
_sphereModel = nullptr;
|
||||
}
|
||||
|
||||
void LightPass::RenderLight(RenderContext& renderContext, GPUTextureView* lightBuffer)
|
||||
void LightPass::RenderLight(RenderContextBatch& renderContextBatch, GPUTextureView* lightBuffer)
|
||||
{
|
||||
const float sphereModelScale = 3.0f;
|
||||
|
||||
@@ -166,6 +166,7 @@ void LightPass::RenderLight(RenderContext& renderContext, GPUTextureView* lightB
|
||||
// Cache data
|
||||
auto device = GPUDevice::Instance;
|
||||
auto context = device->GetMainContext();
|
||||
auto& renderContext = renderContextBatch.Contexts[0];
|
||||
auto& view = renderContext.View;
|
||||
auto mainCache = renderContext.List;
|
||||
const auto lightShader = _shader->GetShader();
|
||||
@@ -219,12 +220,6 @@ void LightPass::RenderLight(RenderContext& renderContext, GPUTextureView* lightB
|
||||
auto cb1 = lightShader->GetCB(1);
|
||||
context->UpdateCB(cb1, &perFrame);
|
||||
|
||||
// Prepare shadows rendering (is will be used)
|
||||
if (useShadows)
|
||||
{
|
||||
ShadowsPass::Instance()->Prepare(renderContext, context);
|
||||
}
|
||||
|
||||
// Bind inputs
|
||||
context->BindSR(0, renderContext.Buffers->GBuffer0);
|
||||
context->BindSR(1, renderContext.Buffers->GBuffer1);
|
||||
@@ -250,7 +245,7 @@ void LightPass::RenderLight(RenderContext& renderContext, GPUTextureView* lightB
|
||||
auto& light = mainCache->PointLights[lightIndex];
|
||||
float lightRadius = light.Radius;
|
||||
Float3 lightPosition = light.Position;
|
||||
const bool renderShadow = useShadows && CanRenderShadow(view, light) && ShadowsPass::Instance()->CanRenderShadow(renderContext, light);
|
||||
const bool renderShadow = useShadows && light.ShadowDataIndex != -1;
|
||||
bool useIES = light.IESTexture != nullptr;
|
||||
|
||||
// Get distance from view center to light center less radius (check if view is inside a sphere)
|
||||
@@ -268,7 +263,7 @@ void LightPass::RenderLight(RenderContext& renderContext, GPUTextureView* lightB
|
||||
if (renderShadow)
|
||||
{
|
||||
GET_SHADOW_MASK();
|
||||
ShadowsPass::Instance()->RenderShadow(renderContext, light, shadowMaskView);
|
||||
ShadowsPass::Instance()->RenderShadow(renderContextBatch, light, shadowMaskView);
|
||||
|
||||
// Bind output
|
||||
context->SetRenderTarget(depthBufferRTV, lightBuffer);
|
||||
@@ -307,7 +302,7 @@ void LightPass::RenderLight(RenderContext& renderContext, GPUTextureView* lightB
|
||||
auto& light = mainCache->SpotLights[lightIndex];
|
||||
float lightRadius = light.Radius;
|
||||
Float3 lightPosition = light.Position;
|
||||
const bool renderShadow = useShadows && CanRenderShadow(view, light) && ShadowsPass::Instance()->CanRenderShadow(renderContext, light);
|
||||
const bool renderShadow = useShadows && light.ShadowDataIndex != -1;
|
||||
bool useIES = light.IESTexture != nullptr;
|
||||
|
||||
// Get distance from view center to light center less radius (check if view is inside a sphere)
|
||||
@@ -325,7 +320,7 @@ void LightPass::RenderLight(RenderContext& renderContext, GPUTextureView* lightB
|
||||
if (renderShadow)
|
||||
{
|
||||
GET_SHADOW_MASK();
|
||||
ShadowsPass::Instance()->RenderShadow(renderContext, light, shadowMaskView);
|
||||
ShadowsPass::Instance()->RenderShadow(renderContextBatch, light, shadowMaskView);
|
||||
|
||||
// Bind output
|
||||
context->SetRenderTarget(depthBufferRTV, lightBuffer);
|
||||
@@ -362,13 +357,13 @@ void LightPass::RenderLight(RenderContext& renderContext, GPUTextureView* lightB
|
||||
|
||||
// Cache data
|
||||
auto& light = mainCache->DirectionalLights[lightIndex];
|
||||
const bool renderShadow = useShadows && CanRenderShadow(view, light) && ShadowsPass::Instance()->CanRenderShadow(renderContext, light);
|
||||
const bool renderShadow = useShadows && light.ShadowDataIndex != -1;
|
||||
|
||||
// Check if render shadow
|
||||
if (renderShadow)
|
||||
{
|
||||
GET_SHADOW_MASK();
|
||||
ShadowsPass::Instance()->RenderShadow(renderContext, light, lightIndex, shadowMaskView);
|
||||
ShadowsPass::Instance()->RenderShadow(renderContextBatch, light, lightIndex, shadowMaskView);
|
||||
|
||||
// Bind output
|
||||
context->SetRenderTarget(depthBufferRTV, lightBuffer);
|
||||
|
||||
@@ -27,13 +27,12 @@ private:
|
||||
PixelFormat _shadowMaskFormat;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Performs the lighting rendering for the input task.
|
||||
/// </summary>
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="renderContextBatch">The rendering context batch.</param>
|
||||
/// <param name="lightBuffer">The light accumulation buffer (input and output).</param>
|
||||
void RenderLight(RenderContext& renderContext, GPUTextureView* lightBuffer);
|
||||
void RenderLight(RenderContextBatch& renderContextBatch, GPUTextureView* lightBuffer);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -416,36 +416,37 @@ void RenderList::Clear()
|
||||
|
||||
void RenderList::AddDrawCall(DrawPass drawModes, StaticFlags staticFlags, DrawCall& drawCall, bool receivesDecals)
|
||||
{
|
||||
// Mix object mask with material mask
|
||||
const auto mask = (DrawPass)(drawModes & drawCall.Material->GetDrawModes());
|
||||
if (mask == DrawPass::None)
|
||||
return;
|
||||
#if ENABLE_ASSERTION_LOW_LAYERS
|
||||
// Ensure that draw modes are non-empty and in conjunction with material draw modes
|
||||
auto materialDrawModes = drawCall.Material->GetDrawModes();
|
||||
ASSERT_LOW_LAYER(drawModes != DrawPass::None && ((uint32)drawModes & ~(uint32)materialDrawModes) == 0);
|
||||
#endif
|
||||
|
||||
// Append draw call data
|
||||
const int32 index = DrawCalls.Count();
|
||||
DrawCalls.Add(drawCall);
|
||||
|
||||
// Add draw call to proper draw lists
|
||||
if (mask & DrawPass::Depth)
|
||||
if (drawModes & DrawPass::Depth)
|
||||
{
|
||||
DrawCallsLists[(int32)DrawCallsListType::Depth].Indices.Add(index);
|
||||
}
|
||||
if (mask & (DrawPass::GBuffer | DrawPass::GlobalSurfaceAtlas))
|
||||
if (drawModes & (DrawPass::GBuffer | DrawPass::GlobalSurfaceAtlas))
|
||||
{
|
||||
if (receivesDecals)
|
||||
DrawCallsLists[(int32)DrawCallsListType::GBuffer].Indices.Add(index);
|
||||
else
|
||||
DrawCallsLists[(int32)DrawCallsListType::GBufferNoDecals].Indices.Add(index);
|
||||
}
|
||||
if (mask & DrawPass::Forward)
|
||||
if (drawModes & DrawPass::Forward)
|
||||
{
|
||||
DrawCallsLists[(int32)DrawCallsListType::Forward].Indices.Add(index);
|
||||
}
|
||||
if (mask & DrawPass::Distortion)
|
||||
if (drawModes & DrawPass::Distortion)
|
||||
{
|
||||
DrawCallsLists[(int32)DrawCallsListType::Distortion].Indices.Add(index);
|
||||
}
|
||||
if (mask & DrawPass::MotionVectors && (staticFlags & StaticFlags::Transform) == 0)
|
||||
if (drawModes & DrawPass::MotionVectors && (staticFlags & StaticFlags::Transform) == 0)
|
||||
{
|
||||
DrawCallsLists[(int32)DrawCallsListType::MotionVectors].Indices.Add(index);
|
||||
}
|
||||
@@ -477,7 +478,7 @@ void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseD
|
||||
PROFILE_CPU();
|
||||
|
||||
const int32 listSize = (int32)list.Indices.Count();
|
||||
const Float3 planeNormal = renderContext.View.Direction;
|
||||
const Float3 planeNormal = renderContext.View.Direction;
|
||||
const float planePoint = -Float3::Dot(planeNormal, renderContext.View.Position);
|
||||
|
||||
// Peek shared memory
|
||||
|
||||
@@ -36,6 +36,7 @@ struct RendererDirectionalLightData
|
||||
|
||||
StaticFlags StaticFlags;
|
||||
float IndirectLightingIntensity;
|
||||
int16 ShadowDataIndex = -1;
|
||||
int8 CastVolumetricShadow : 1;
|
||||
int8 RenderedVolumetricFog : 1;
|
||||
|
||||
@@ -80,6 +81,7 @@ struct RendererSpotLightData
|
||||
ShadowsCastingMode ShadowsMode;
|
||||
|
||||
StaticFlags StaticFlags;
|
||||
int16 ShadowDataIndex = -1;
|
||||
int8 CastVolumetricShadow : 1;
|
||||
int8 RenderedVolumetricFog : 1;
|
||||
int8 UseInverseSquaredFalloff : 1;
|
||||
@@ -117,6 +119,7 @@ struct RendererPointLightData
|
||||
ShadowsCastingMode ShadowsMode;
|
||||
|
||||
StaticFlags StaticFlags;
|
||||
int16 ShadowDataIndex = -1;
|
||||
int8 CastVolumetricShadow : 1;
|
||||
int8 RenderedVolumetricFog : 1;
|
||||
int8 UseInverseSquaredFalloff : 1;
|
||||
@@ -508,7 +511,7 @@ public:
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="postProcess">The PostFx location to check (for scripts).</param>
|
||||
/// <returns>True if render any postFx of the given type, otherwise false.</returns>
|
||||
bool HasAnyPostFx(RenderContext& renderContext, PostProcessEffectLocation postProcess) const;
|
||||
bool HasAnyPostFx(const RenderContext& renderContext, PostProcessEffectLocation postProcess) const;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether any Material PostFx specified by given type. Used to pick a faster rendering path by the frame rendering module.
|
||||
@@ -516,7 +519,7 @@ public:
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="materialPostFx">The PostFx location to check (for materials).</param>
|
||||
/// <returns>True if render any postFx of the given type, otherwise false.</returns>
|
||||
bool HasAnyPostFx(RenderContext& renderContext, MaterialPostFxLocation materialPostFx) const;
|
||||
bool HasAnyPostFx(const RenderContext& renderContext, MaterialPostFxLocation materialPostFx) const;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether any Custom PostFx or Material PostFx specified by given type. Used to pick a faster rendering path by the frame rendering module.
|
||||
@@ -525,7 +528,7 @@ public:
|
||||
/// <param name="postProcess">The PostFx location to check (for scripts).</param>
|
||||
/// <param name="materialPostFx">The PostFx location to check (for materials).</param>
|
||||
/// <returns>True if render any postFx of the given type, otherwise false.</returns>
|
||||
bool HasAnyPostFx(RenderContext& renderContext, PostProcessEffectLocation postProcess, MaterialPostFxLocation materialPostFx) const
|
||||
bool HasAnyPostFx(const RenderContext& renderContext, PostProcessEffectLocation postProcess, MaterialPostFxLocation materialPostFx) const
|
||||
{
|
||||
return HasAnyPostFx(renderContext, postProcess) || HasAnyPostFx(renderContext, materialPostFx);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
|
||||
RendererService RendererServiceInstance;
|
||||
|
||||
void RenderInner(SceneRenderTask* task, RenderContext& renderContext);
|
||||
void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderContextBatch& renderContextBatch);
|
||||
|
||||
bool RendererService::Init()
|
||||
{
|
||||
@@ -165,15 +165,18 @@ void Renderer::Render(SceneRenderTask* task)
|
||||
{
|
||||
PROFILE_GPU_CPU_NAMED("Render Frame");
|
||||
|
||||
// Prepare GPU context
|
||||
auto context = GPUDevice::Instance->GetMainContext();
|
||||
context->ClearState();
|
||||
context->FlushState();
|
||||
const Viewport viewport = task->GetViewport();
|
||||
context->SetViewportAndScissors(viewport);
|
||||
|
||||
// Prepare
|
||||
// Prepare render context
|
||||
RenderContext renderContext(task);
|
||||
renderContext.List = RenderList::GetFromPool();
|
||||
RenderContextBatch renderContextBatch(task);
|
||||
renderContextBatch.Contexts.Add(renderContext);
|
||||
|
||||
#if USE_EDITOR
|
||||
// Turn on low quality rendering during baking lightmaps (leave more GPU power for baking)
|
||||
@@ -204,7 +207,7 @@ void Renderer::Render(SceneRenderTask* task)
|
||||
|
||||
// Perform the actual rendering
|
||||
task->OnPreRender(context, renderContext);
|
||||
RenderInner(task, renderContext);
|
||||
RenderInner(task, renderContext, renderContextBatch);
|
||||
task->OnPostRender(context, renderContext);
|
||||
|
||||
#if USE_EDITOR
|
||||
@@ -216,10 +219,11 @@ void Renderer::Render(SceneRenderTask* task)
|
||||
task->View = renderContext.View;
|
||||
|
||||
// Cleanup
|
||||
RenderList::ReturnToPool(renderContext.List);
|
||||
for (const auto& e : renderContextBatch.Contexts)
|
||||
RenderList::ReturnToPool(e.List);
|
||||
}
|
||||
|
||||
bool Renderer::NeedMotionVectors(RenderContext& renderContext)
|
||||
bool Renderer::NeedMotionVectors(const RenderContext& renderContext)
|
||||
{
|
||||
const int32 screenWidth = renderContext.Buffers->GetWidth();
|
||||
const int32 screenHeight = renderContext.Buffers->GetHeight();
|
||||
@@ -255,7 +259,8 @@ void Renderer::DrawSceneDepth(GPUContext* context, SceneRenderTask* task, GPUTex
|
||||
else
|
||||
{
|
||||
// Draw scene actors
|
||||
Level::DrawActors(renderContext);
|
||||
RenderContextBatch renderContextBatch(renderContext);
|
||||
Level::DrawActors(renderContextBatch);
|
||||
}
|
||||
|
||||
// Sort draw calls
|
||||
@@ -290,7 +295,7 @@ void Renderer::DrawPostFxMaterial(GPUContext* context, const RenderContext& rend
|
||||
context->ResetRenderTarget();
|
||||
}
|
||||
|
||||
void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
|
||||
void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderContextBatch& renderContextBatch)
|
||||
{
|
||||
auto context = GPUDevice::Instance->GetMainContext();
|
||||
auto* graphicsSettings = GraphicsSettings::Get();
|
||||
@@ -316,17 +321,47 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
|
||||
renderContext.List->PostFx.Add(&postFx);
|
||||
}
|
||||
|
||||
// Collect renderable objects and construct draw call list
|
||||
view.Pass = DrawPass::GBuffer | DrawPass::Forward | DrawPass::Distortion;
|
||||
if (Renderer::NeedMotionVectors(renderContext))
|
||||
view.Pass |= DrawPass::MotionVectors;
|
||||
task->OnCollectDrawCalls(renderContext);
|
||||
// Build batch of render contexts (main view and shadow projections)
|
||||
const bool isGBufferDebug = GBufferPass::IsDebugView(renderContext.View.Mode);
|
||||
{
|
||||
PROFILE_CPU_NAMED("Collect Draw Calls");
|
||||
|
||||
view.Pass = DrawPass::GBuffer | DrawPass::Forward | DrawPass::Distortion;
|
||||
if (Renderer::NeedMotionVectors(renderContext))
|
||||
view.Pass |= DrawPass::MotionVectors;
|
||||
renderContextBatch.GetMainContext() = renderContext; // Sync render context in batch with the current value
|
||||
|
||||
bool drawShadows = !isGBufferDebug && ((view.Flags & ViewFlags::Shadows) != 0) && ShadowsPass::Instance()->IsReady();
|
||||
switch (renderContext.View.Mode)
|
||||
{
|
||||
case ViewMode::QuadOverdraw:
|
||||
case ViewMode::Emissive:
|
||||
case ViewMode::LightmapUVsDensity:
|
||||
case ViewMode::GlobalSurfaceAtlas:
|
||||
case ViewMode::GlobalSDF:
|
||||
case ViewMode::MaterialComplexity:
|
||||
drawShadows = false;
|
||||
break;
|
||||
}
|
||||
if (drawShadows)
|
||||
ShadowsPass::Instance()->SetupShadows(renderContext, renderContextBatch);
|
||||
|
||||
task->OnCollectDrawCalls(renderContextBatch);
|
||||
}
|
||||
|
||||
// Sort draw calls
|
||||
renderContext.List->SortDrawCalls(renderContext, false, DrawCallsListType::GBuffer);
|
||||
renderContext.List->SortDrawCalls(renderContext, false, DrawCallsListType::GBufferNoDecals);
|
||||
renderContext.List->SortDrawCalls(renderContext, true, DrawCallsListType::Forward);
|
||||
renderContext.List->SortDrawCalls(renderContext, false, DrawCallsListType::Distortion);
|
||||
{
|
||||
PROFILE_CPU_NAMED("Sort Draw Calls");
|
||||
renderContext.List->SortDrawCalls(renderContext, false, DrawCallsListType::GBuffer);
|
||||
renderContext.List->SortDrawCalls(renderContext, false, DrawCallsListType::GBufferNoDecals);
|
||||
renderContext.List->SortDrawCalls(renderContext, true, DrawCallsListType::Forward);
|
||||
renderContext.List->SortDrawCalls(renderContext, false, DrawCallsListType::Distortion);
|
||||
for (int32 i = 1; i < renderContextBatch.Contexts.Count(); i++)
|
||||
{
|
||||
auto& shadowContext = renderContextBatch.Contexts[i];
|
||||
shadowContext.List->SortDrawCalls(shadowContext, false, DrawCallsListType::Depth);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the light accumulation buffer
|
||||
auto outputFormat = renderContext.Buffers->GetOutputFormat();
|
||||
@@ -389,7 +424,7 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
|
||||
AmbientOcclusionPass::Instance()->Render(renderContext);
|
||||
|
||||
// Check if use custom view mode
|
||||
if (GBufferPass::IsDebugView(renderContext.View.Mode))
|
||||
if (isGBufferDebug)
|
||||
{
|
||||
context->ResetRenderTarget();
|
||||
context->SetRenderTarget(task->GetOutputView());
|
||||
@@ -400,7 +435,8 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
|
||||
}
|
||||
|
||||
// Render lighting
|
||||
LightPass::Instance()->RenderLight(renderContext, *lightBuffer);
|
||||
renderContextBatch.GetMainContext() = renderContext; // Sync render context in batch with the current value
|
||||
LightPass::Instance()->RenderLight(renderContextBatch, *lightBuffer);
|
||||
if (renderContext.View.Flags & ViewFlags::GI)
|
||||
{
|
||||
switch (renderContext.List->Settings.GlobalIllumination.Mode)
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <returns>True if need to render motion vectors, otherwise false.</returns>
|
||||
static bool NeedMotionVectors(RenderContext& renderContext);
|
||||
static bool NeedMotionVectors(const RenderContext& renderContext);
|
||||
|
||||
public:
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ PACK_STRUCT(struct Data
|
||||
GlobalSurfaceAtlasPass::ConstantsData GlobalSurfaceAtlas;
|
||||
});
|
||||
|
||||
bool ScreenSpaceReflectionsPass::NeedMotionVectors(RenderContext& renderContext)
|
||||
bool ScreenSpaceReflectionsPass::NeedMotionVectors(const RenderContext& renderContext)
|
||||
{
|
||||
auto& settings = renderContext.List->Settings.ScreenSpaceReflections;
|
||||
return settings.TemporalEffect && renderContext.View.Flags & ViewFlags::SSR;
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <returns>True if need to render motion vectors, otherwise false.</returns>
|
||||
static bool NeedMotionVectors(RenderContext& renderContext);
|
||||
static bool NeedMotionVectors(const RenderContext& renderContext);
|
||||
|
||||
/// <summary>
|
||||
/// Perform SSR rendering for the input task (blends reflections to given texture using alpha blending).
|
||||
|
||||
@@ -189,298 +189,37 @@ void ShadowsPass::updateShadowMapSize()
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowsPass::Dispose()
|
||||
void ShadowsPass::SetupRenderContext(RenderContext& renderContext, RenderContext& shadowContext)
|
||||
{
|
||||
// Base
|
||||
RendererPass::Dispose();
|
||||
|
||||
// Cleanup
|
||||
_psShadowDir.Delete();
|
||||
_psShadowPoint.Delete();
|
||||
_psShadowSpot.Delete();
|
||||
_shader = nullptr;
|
||||
_sphereModel = nullptr;
|
||||
SAFE_DELETE_GPU_RESOURCE(_shadowMapCSM);
|
||||
SAFE_DELETE_GPU_RESOURCE(_shadowMapCube);
|
||||
}
|
||||
|
||||
bool ShadowsPass::CanRenderShadow(RenderContext& renderContext, const RendererPointLightData& light)
|
||||
{
|
||||
const Float3 lightPosition = light.Position;
|
||||
const float dstLightToView = Float3::Distance(lightPosition, renderContext.View.Position);
|
||||
|
||||
// Fade shadow on distance
|
||||
const float fadeDistance = Math::Max(light.ShadowsFadeDistance, 0.1f);
|
||||
const float fade = 1 - Math::Saturate((dstLightToView - light.Radius - light.ShadowsDistance + fadeDistance) / fadeDistance);
|
||||
|
||||
return fade > ZeroTolerance && _supportsShadows;
|
||||
}
|
||||
|
||||
bool ShadowsPass::CanRenderShadow(RenderContext& renderContext, const RendererSpotLightData& light)
|
||||
{
|
||||
const Float3 lightPosition = light.Position;
|
||||
const float dstLightToView = Float3::Distance(lightPosition, renderContext.View.Position);
|
||||
|
||||
// Fade shadow on distance
|
||||
const float fadeDistance = Math::Max(light.ShadowsFadeDistance, 0.1f);
|
||||
const float fade = 1 - Math::Saturate((dstLightToView - light.Radius - light.ShadowsDistance + fadeDistance) / fadeDistance);
|
||||
|
||||
return fade > ZeroTolerance && _supportsShadows;
|
||||
}
|
||||
|
||||
bool ShadowsPass::CanRenderShadow(RenderContext& renderContext, const RendererDirectionalLightData& light)
|
||||
{
|
||||
return _supportsShadows;
|
||||
}
|
||||
|
||||
void ShadowsPass::Prepare(RenderContext& renderContext, GPUContext* context)
|
||||
{
|
||||
ASSERT(IsReady());
|
||||
auto& view = renderContext.View;
|
||||
const auto shader = _shader->GetShader();
|
||||
|
||||
const auto shadowMapsQuality = Graphics::ShadowMapsQuality;
|
||||
if (shadowMapsQuality != _currentShadowMapsQuality)
|
||||
updateShadowMapSize();
|
||||
auto shadowsQuality = Graphics::ShadowsQuality;
|
||||
maxShadowsQuality = Math::Clamp(Math::Min<int32>(static_cast<int32>(shadowsQuality), static_cast<int32>(view.MaxShadowsQuality)), 0, static_cast<int32>(Quality::MAX) - 1);
|
||||
const auto& view = renderContext.View;
|
||||
|
||||
// Use the current render view to sync model LODs with the shadow maps rendering stage
|
||||
_shadowContext.LodProxyView = &renderContext.View;
|
||||
shadowContext.LodProxyView = &renderContext.View;
|
||||
|
||||
// Prepare properties
|
||||
auto& shadowView = _shadowContext.View;
|
||||
auto& shadowView = shadowContext.View;
|
||||
shadowView.Flags = view.Flags;
|
||||
shadowView.StaticFlagsMask = view.StaticFlagsMask;
|
||||
shadowView.RenderLayersMask = view.RenderLayersMask;
|
||||
shadowView.IsOfflinePass = view.IsOfflinePass;
|
||||
shadowView.ModelLODBias = view.ModelLODBias + view.ShadowModelLODBias;
|
||||
shadowView.ModelLODDistanceFactor = view.ModelLODDistanceFactor * view.ShadowModelLODDistanceFactor;
|
||||
shadowView.ModelLODBias = view.ModelLODBias;
|
||||
shadowView.ModelLODDistanceFactor = view.ModelLODDistanceFactor;
|
||||
shadowView.Pass = DrawPass::Depth;
|
||||
shadowView.Origin = view.Origin;
|
||||
_shadowContext.List = &_shadowCache;
|
||||
shadowContext.List = RenderList::GetFromPool();
|
||||
shadowContext.Buffers = renderContext.Buffers;
|
||||
shadowContext.Task = renderContext.Task;
|
||||
}
|
||||
|
||||
void ShadowsPass::RenderShadow(RenderContext& renderContext, RendererPointLightData& light, GPUTextureView* shadowMask)
|
||||
void ShadowsPass::SetupLight(RenderContext& renderContext, RenderContextBatch& renderContextBatch, RendererDirectionalLightData& light)
|
||||
{
|
||||
const float sphereModelScale = 3.0f;
|
||||
|
||||
PROFILE_GPU_CPU("Shadow");
|
||||
|
||||
// Cache data
|
||||
auto device = GPUDevice::Instance;
|
||||
auto context = device->GetMainContext();
|
||||
auto& view = renderContext.View;
|
||||
auto shader = _shader->GetShader();
|
||||
Data sperLight;
|
||||
float lightRadius = light.Radius;
|
||||
Float3 lightPosition = light.Position;
|
||||
Float3 lightDirection = light.Direction;
|
||||
float dstLightToView = Float3::Distance(lightPosition, view.Position);
|
||||
|
||||
// TODO: here we can use lower shadows quality based on light distance to view (LOD switching) and per light setting for max quality
|
||||
int32 shadowQuality = maxShadowsQuality;
|
||||
|
||||
// Fade shadow on distance
|
||||
const float fadeDistance = Math::Max(light.ShadowsFadeDistance, 0.1f);
|
||||
const float fade = 1 - Math::Saturate((dstLightToView - light.Radius - light.ShadowsDistance + fadeDistance) / fadeDistance);
|
||||
|
||||
// Set up GPU context and render view
|
||||
const auto shadowMapsSizeCube = (float)_shadowMapsSizeCube;
|
||||
context->SetViewportAndScissors(shadowMapsSizeCube, shadowMapsSizeCube);
|
||||
_shadowContext.View.SetUpCube(PointLight_NearPlane, lightRadius, lightPosition);
|
||||
_shadowContext.View.PrepareCache(_shadowContext, shadowMapsSizeCube, shadowMapsSizeCube, Float2::Zero, &view);
|
||||
|
||||
// Render depth to all 6 faces of the cube map
|
||||
for (int32 faceIndex = 0; faceIndex < 6; faceIndex++)
|
||||
{
|
||||
// Set up view
|
||||
_shadowCache.Clear();
|
||||
_shadowContext.View.SetFace(faceIndex);
|
||||
Matrix::Transpose(_shadowContext.View.ViewProjection(), sperLight.LightShadow.ShadowVP[faceIndex]);
|
||||
|
||||
// Set render target
|
||||
auto rt = _shadowMapCube->View(faceIndex);
|
||||
context->ResetSR();
|
||||
context->SetRenderTarget(rt, static_cast<GPUTextureView*>(nullptr));
|
||||
context->ClearDepth(rt);
|
||||
|
||||
// Render actors to the shadow map
|
||||
renderContext.Task->OnCollectDrawCalls(_shadowContext);
|
||||
_shadowCache.SortDrawCalls(_shadowContext, false, DrawCallsListType::Depth);
|
||||
_shadowCache.ExecuteDrawCalls(_shadowContext, DrawCallsListType::Depth);
|
||||
}
|
||||
|
||||
// Restore GPU context
|
||||
context->ResetSR();
|
||||
context->ResetRenderTarget();
|
||||
const Viewport viewport = renderContext.Task->GetViewport();
|
||||
GPUTexture* depthBuffer = renderContext.Buffers->DepthBuffer;
|
||||
GPUTextureView* depthBufferSRV = depthBuffer->GetDescription().Flags & GPUTextureFlags::ReadOnlyDepthView ? depthBuffer->ViewReadOnlyDepth() : depthBuffer->View();
|
||||
context->SetViewportAndScissors(viewport);
|
||||
context->BindSR(0, renderContext.Buffers->GBuffer0);
|
||||
context->BindSR(1, renderContext.Buffers->GBuffer1);
|
||||
context->BindSR(2, renderContext.Buffers->GBuffer2);
|
||||
context->BindSR(3, depthBufferSRV);
|
||||
context->BindSR(4, renderContext.Buffers->GBuffer3);
|
||||
|
||||
// Setup shader data
|
||||
GBufferPass::SetInputs(view, sperLight.GBuffer);
|
||||
light.SetupLightData(&sperLight.Light, true);
|
||||
sperLight.LightShadow.ShadowMapSize = shadowMapsSizeCube;
|
||||
sperLight.LightShadow.Sharpness = light.ShadowsSharpness;
|
||||
sperLight.LightShadow.Fade = Math::Saturate(light.ShadowsStrength * fade);
|
||||
sperLight.LightShadow.NormalOffsetScale = light.ShadowsNormalOffsetScale * NormalOffsetScaleTweak * (1.0f / shadowMapsSizeCube);
|
||||
sperLight.LightShadow.Bias = light.ShadowsDepthBias;
|
||||
sperLight.LightShadow.FadeDistance = Math::Max(light.ShadowsFadeDistance, 0.1f);
|
||||
sperLight.LightShadow.NumCascades = 1;
|
||||
sperLight.LightShadow.CascadeSplits = Float4::Zero;
|
||||
Matrix::Transpose(view.ViewProjection(), sperLight.ViewProjectionMatrix);
|
||||
sperLight.ContactShadowsDistance = light.ShadowsDistance;
|
||||
sperLight.ContactShadowsLength = view.Flags & ViewFlags::ContactShadows ? light.ContactShadowsLength : 0.0f;
|
||||
|
||||
// Calculate world view projection matrix for the light sphere
|
||||
Matrix world, wvp, matrix;
|
||||
Matrix::Scaling(lightRadius * sphereModelScale, wvp);
|
||||
Matrix::Translation(lightPosition, matrix);
|
||||
Matrix::Multiply(wvp, matrix, world);
|
||||
Matrix::Multiply(world, view.ViewProjection(), wvp);
|
||||
Matrix::Transpose(wvp, sperLight.WVP);
|
||||
|
||||
// Render shadow in screen space
|
||||
context->UpdateCB(shader->GetCB(0), &sperLight);
|
||||
context->BindCB(0, shader->GetCB(0));
|
||||
context->BindCB(1, shader->GetCB(1));
|
||||
context->BindSR(5, _shadowMapCube->ViewArray());
|
||||
context->SetRenderTarget(shadowMask);
|
||||
context->SetState(_psShadowPoint.Get(shadowQuality + (sperLight.ContactShadowsLength > ZeroTolerance ? 4 : 0)));
|
||||
_sphereModel->Render(context);
|
||||
|
||||
// Cleanup
|
||||
context->ResetRenderTarget();
|
||||
context->UnBindSR(5);
|
||||
|
||||
// Render volumetric light with shadow
|
||||
VolumetricFogPass::Instance()->RenderLight(renderContext, context, light, _shadowMapCube->ViewArray(), sperLight.LightShadow);
|
||||
}
|
||||
|
||||
void ShadowsPass::RenderShadow(RenderContext& renderContext, RendererSpotLightData& light, GPUTextureView* shadowMask)
|
||||
{
|
||||
const float sphereModelScale = 3.0f;
|
||||
|
||||
PROFILE_GPU_CPU("Shadow");
|
||||
|
||||
// Cache data
|
||||
auto device = GPUDevice::Instance;
|
||||
auto context = device->GetMainContext();
|
||||
auto& view = renderContext.View;
|
||||
auto shader = _shader->GetShader();
|
||||
Data sperLight;
|
||||
float lightRadius = light.Radius;
|
||||
Float3 lightPosition = light.Position;
|
||||
Float3 lightDirection = light.Direction;
|
||||
float dstLightToView = Float3::Distance(lightPosition, view.Position);
|
||||
|
||||
// TODO: here we can use lower shadows quality based on light distance to view (LOD switching) and per light setting for max quality
|
||||
int32 shadowQuality = maxShadowsQuality;
|
||||
|
||||
// Fade shadow on distance
|
||||
const float fadeDistance = Math::Max(light.ShadowsFadeDistance, 0.1f);
|
||||
const float fade = 1 - Math::Saturate((dstLightToView - light.Radius - light.ShadowsDistance + fadeDistance) / fadeDistance);
|
||||
|
||||
// Set up GPU context and render view
|
||||
const auto shadowMapsSizeCube = (float)_shadowMapsSizeCube;
|
||||
context->SetViewportAndScissors(shadowMapsSizeCube, shadowMapsSizeCube);
|
||||
_shadowContext.View.SetProjector(SpotLight_NearPlane, lightRadius, lightPosition, lightDirection, light.UpVector, light.OuterConeAngle * 2.0f);
|
||||
_shadowContext.View.PrepareCache(_shadowContext, shadowMapsSizeCube, shadowMapsSizeCube, Float2::Zero, &view);
|
||||
|
||||
// Render depth to all 1 face of the cube map
|
||||
const int32 cubeFaceIndex = 0;
|
||||
{
|
||||
// Set up view
|
||||
_shadowCache.Clear();
|
||||
Matrix::Transpose(_shadowContext.View.ViewProjection(), sperLight.LightShadow.ShadowVP[cubeFaceIndex]);
|
||||
|
||||
// Set render target
|
||||
auto rt = _shadowMapCube->View(cubeFaceIndex);
|
||||
context->ResetSR();
|
||||
context->SetRenderTarget(rt, static_cast<GPUTextureView*>(nullptr));
|
||||
context->ClearDepth(rt);
|
||||
|
||||
// Render actors to the shadow map
|
||||
renderContext.Task->OnCollectDrawCalls(_shadowContext);
|
||||
_shadowCache.SortDrawCalls(_shadowContext, false, DrawCallsListType::Depth);
|
||||
_shadowCache.ExecuteDrawCalls(_shadowContext, DrawCallsListType::Depth);
|
||||
}
|
||||
|
||||
// Restore GPU context
|
||||
context->ResetSR();
|
||||
context->ResetRenderTarget();
|
||||
const Viewport viewport = renderContext.Task->GetViewport();
|
||||
GPUTexture* depthBuffer = renderContext.Buffers->DepthBuffer;
|
||||
GPUTextureView* depthBufferSRV = depthBuffer->GetDescription().Flags & GPUTextureFlags::ReadOnlyDepthView ? depthBuffer->ViewReadOnlyDepth() : depthBuffer->View();
|
||||
context->SetViewportAndScissors(viewport);
|
||||
context->BindSR(0, renderContext.Buffers->GBuffer0);
|
||||
context->BindSR(1, renderContext.Buffers->GBuffer1);
|
||||
context->BindSR(2, renderContext.Buffers->GBuffer2);
|
||||
context->BindSR(3, depthBufferSRV);
|
||||
context->BindSR(4, renderContext.Buffers->GBuffer3);
|
||||
|
||||
// Setup shader data
|
||||
GBufferPass::SetInputs(view, sperLight.GBuffer);
|
||||
light.SetupLightData(&sperLight.Light, true);
|
||||
sperLight.LightShadow.ShadowMapSize = shadowMapsSizeCube;
|
||||
sperLight.LightShadow.Sharpness = light.ShadowsSharpness;
|
||||
sperLight.LightShadow.Fade = Math::Saturate(light.ShadowsStrength * fade);
|
||||
sperLight.LightShadow.NormalOffsetScale = light.ShadowsNormalOffsetScale * NormalOffsetScaleTweak * (1.0f / shadowMapsSizeCube);
|
||||
sperLight.LightShadow.Bias = light.ShadowsDepthBias;
|
||||
sperLight.LightShadow.FadeDistance = Math::Max(light.ShadowsFadeDistance, 0.1f);
|
||||
sperLight.LightShadow.NumCascades = 1;
|
||||
sperLight.LightShadow.CascadeSplits = Float4::Zero;
|
||||
Matrix::Transpose(view.ViewProjection(), sperLight.ViewProjectionMatrix);
|
||||
sperLight.ContactShadowsDistance = light.ShadowsDistance;
|
||||
sperLight.ContactShadowsLength = view.Flags & ViewFlags::ContactShadows ? light.ContactShadowsLength : 0.0f;
|
||||
|
||||
// Calculate world view projection matrix for the light sphere
|
||||
Matrix world, wvp, matrix;
|
||||
Matrix::Scaling(lightRadius * sphereModelScale, wvp);
|
||||
Matrix::Translation(lightPosition, matrix);
|
||||
Matrix::Multiply(wvp, matrix, world);
|
||||
Matrix::Multiply(world, view.ViewProjection(), wvp);
|
||||
Matrix::Transpose(wvp, sperLight.WVP);
|
||||
|
||||
// Render shadow in screen space
|
||||
context->UpdateCB(shader->GetCB(0), &sperLight);
|
||||
context->BindCB(0, shader->GetCB(0));
|
||||
context->BindCB(1, shader->GetCB(1));
|
||||
context->BindSR(5, _shadowMapCube->View(cubeFaceIndex));
|
||||
context->SetRenderTarget(shadowMask);
|
||||
context->SetState(_psShadowSpot.Get(shadowQuality + (sperLight.ContactShadowsLength > ZeroTolerance ? 4 : 0)));
|
||||
_sphereModel->Render(context);
|
||||
|
||||
// Cleanup
|
||||
context->ResetRenderTarget();
|
||||
context->UnBindSR(5);
|
||||
|
||||
// Render volumetric light with shadow
|
||||
VolumetricFogPass::Instance()->RenderLight(renderContext, context, light, _shadowMapCube->View(cubeFaceIndex), sperLight.LightShadow);
|
||||
}
|
||||
|
||||
void ShadowsPass::RenderShadow(RenderContext& renderContext, RendererDirectionalLightData& light, int32 index, GPUTextureView* shadowMask)
|
||||
{
|
||||
PROFILE_GPU_CPU("Shadow");
|
||||
|
||||
// Cache data
|
||||
auto device = GPUDevice::Instance;
|
||||
auto context = device->GetMainContext();
|
||||
auto& view = renderContext.View;
|
||||
const RenderView& view = renderContext.View;
|
||||
auto mainCache = renderContext.List;
|
||||
auto shader = _shader->GetShader();
|
||||
Data sperLight;
|
||||
Float3 lightDirection = light.Direction;
|
||||
float shadowsDistance = Math::Min(view.Far, light.ShadowsDistance);
|
||||
int32 csmCount = Math::Clamp(light.CascadeCount, 0, MAX_CSM_CASCADES);
|
||||
bool blendCSM = Graphics::AllowCSMBlending;
|
||||
const auto shadowMapsSizeCSM = (float)_shadowMapsSizeCSM;
|
||||
#if USE_EDITOR
|
||||
if (IsRunningRadiancePass)
|
||||
blendCSM = false;
|
||||
@@ -561,9 +300,7 @@ void ShadowsPass::RenderShadow(RenderContext& renderContext, RendererDirectional
|
||||
|
||||
// Convert distance splits to ratios cascade in the range [0, 1]
|
||||
for (int32 i = 0; i < MAX_CSM_CASCADES; i++)
|
||||
{
|
||||
cascadeSplits[i] = (cascadeSplits[i] - cameraNear) / cameraRange;
|
||||
}
|
||||
}
|
||||
|
||||
// Select best Up vector
|
||||
@@ -585,10 +322,13 @@ void ShadowsPass::RenderShadow(RenderContext& renderContext, RendererDirectional
|
||||
Float3 frustumCorners[8];
|
||||
Matrix shadowView, shadowProjection, shadowVP;
|
||||
|
||||
// Set up GPU context and render view
|
||||
const auto shadowMapsSizeCSM = (float)_shadowMapsSizeCSM;
|
||||
context->SetViewportAndScissors(shadowMapsSizeCSM, shadowMapsSizeCSM);
|
||||
_shadowContext.View.PrepareCache(_shadowContext, shadowMapsSizeCSM, shadowMapsSizeCSM, Float2::Zero, &view);
|
||||
// Init shadow data
|
||||
light.ShadowDataIndex = _shadowData.Count();
|
||||
auto& shadowData = _shadowData.AddOne();
|
||||
shadowData.ContextIndex = renderContextBatch.Contexts.Count();
|
||||
shadowData.ContextCount = csmCount;
|
||||
shadowData.BlendCSM = blendCSM;
|
||||
renderContextBatch.Contexts.AddDefault(shadowData.ContextCount);
|
||||
|
||||
// Create the different view and projection matrices for each split
|
||||
float splitMinRatio = 0;
|
||||
@@ -684,26 +424,213 @@ void ShadowsPass::RenderShadow(RenderContext& renderContext, RendererDirectional
|
||||
0.5f, 0.5f, 0.0f, 1.0f);
|
||||
Matrix m;
|
||||
Matrix::Multiply(shadowVP, T, m);
|
||||
Matrix::Transpose(m, sperLight.LightShadow.ShadowVP[cascadeIndex]);
|
||||
Matrix::Transpose(m, shadowData.Constants.ShadowVP[cascadeIndex]);
|
||||
}
|
||||
|
||||
// Set up view and cache
|
||||
_shadowCache.Clear();
|
||||
_shadowContext.View.Position = -lightDirection * shadowsDistance + view.Position;
|
||||
_shadowContext.View.Direction = lightDirection;
|
||||
_shadowContext.View.SetUp(shadowView, shadowProjection);
|
||||
_shadowContext.View.CullingFrustum.SetMatrix(cullingVP);
|
||||
// Setup context for cascade
|
||||
auto& shadowContext = renderContextBatch.Contexts[shadowData.ContextIndex + cascadeIndex];
|
||||
SetupRenderContext(renderContext, shadowContext);
|
||||
shadowContext.List->Clear();
|
||||
shadowContext.View.Position = -lightDirection * shadowsDistance + view.Position;
|
||||
shadowContext.View.Direction = lightDirection;
|
||||
shadowContext.View.SetUp(shadowView, shadowProjection);
|
||||
shadowContext.View.CullingFrustum.SetMatrix(cullingVP);
|
||||
shadowContext.View.PrepareCache(shadowContext, shadowMapsSizeCSM, shadowMapsSizeCSM, Float2::Zero, &view);
|
||||
}
|
||||
|
||||
// Set render target
|
||||
const auto rt = _shadowMapCSM->View(cascadeIndex);
|
||||
// Setup constant buffer data
|
||||
shadowData.Constants.ShadowMapSize = shadowMapsSizeCSM;
|
||||
shadowData.Constants.Sharpness = light.ShadowsSharpness;
|
||||
shadowData.Constants.Fade = Math::Saturate(light.ShadowsStrength);
|
||||
shadowData.Constants.NormalOffsetScale = light.ShadowsNormalOffsetScale * NormalOffsetScaleTweak * (1.0f / shadowMapsSizeCSM);
|
||||
shadowData.Constants.Bias = light.ShadowsDepthBias;
|
||||
shadowData.Constants.FadeDistance = Math::Max(light.ShadowsFadeDistance, 0.1f);
|
||||
shadowData.Constants.NumCascades = csmCount;
|
||||
shadowData.Constants.CascadeSplits = view.Near + Float4(cascadeSplits) * cameraRange;
|
||||
}
|
||||
|
||||
void ShadowsPass::SetupLight(RenderContext& renderContext, RenderContextBatch& renderContextBatch, RendererPointLightData& light)
|
||||
{
|
||||
// Init shadow data
|
||||
light.ShadowDataIndex = _shadowData.Count();
|
||||
auto& shadowData = _shadowData.AddOne();
|
||||
shadowData.ContextIndex = renderContextBatch.Contexts.Count();
|
||||
shadowData.ContextCount = 6;
|
||||
renderContextBatch.Contexts.AddDefault(shadowData.ContextCount);
|
||||
|
||||
const auto& view = renderContext.View;
|
||||
const auto shadowMapsSizeCube = (float)_shadowMapsSizeCube;
|
||||
|
||||
// Fade shadow on distance
|
||||
const float fadeDistance = Math::Max(light.ShadowsFadeDistance, 0.1f);
|
||||
const float dstLightToView = Float3::Distance(light.Position, view.Position);
|
||||
const float fade = 1 - Math::Saturate((dstLightToView - light.Radius - light.ShadowsDistance + fadeDistance) / fadeDistance);
|
||||
|
||||
// Render depth to all 6 faces of the cube map
|
||||
for (int32 faceIndex = 0; faceIndex < 6; faceIndex++)
|
||||
{
|
||||
auto& shadowContext = renderContextBatch.Contexts[shadowData.ContextIndex + faceIndex];
|
||||
SetupRenderContext(renderContext, shadowContext);
|
||||
shadowContext.List->Clear();
|
||||
shadowContext.View.SetUpCube(PointLight_NearPlane, light.Radius, light.Position);
|
||||
shadowContext.View.SetFace(faceIndex);
|
||||
shadowContext.View.PrepareCache(shadowContext, shadowMapsSizeCube, shadowMapsSizeCube, Float2::Zero, &view);
|
||||
Matrix::Transpose(shadowContext.View.ViewProjection(), shadowData.Constants.ShadowVP[faceIndex]);
|
||||
}
|
||||
|
||||
// Setup constant buffer data
|
||||
shadowData.Constants.ShadowMapSize = shadowMapsSizeCube;
|
||||
shadowData.Constants.Sharpness = light.ShadowsSharpness;
|
||||
shadowData.Constants.Fade = Math::Saturate(light.ShadowsStrength * fade);
|
||||
shadowData.Constants.NormalOffsetScale = light.ShadowsNormalOffsetScale * NormalOffsetScaleTweak * (1.0f / shadowMapsSizeCube);
|
||||
shadowData.Constants.Bias = light.ShadowsDepthBias;
|
||||
shadowData.Constants.FadeDistance = Math::Max(light.ShadowsFadeDistance, 0.1f);
|
||||
shadowData.Constants.NumCascades = 1;
|
||||
shadowData.Constants.CascadeSplits = Float4::Zero;
|
||||
}
|
||||
|
||||
void ShadowsPass::SetupLight(RenderContext& renderContext, RenderContextBatch& renderContextBatch, RendererSpotLightData& light)
|
||||
{
|
||||
// Init shadow data
|
||||
light.ShadowDataIndex = _shadowData.Count();
|
||||
auto& shadowData = _shadowData.AddOne();
|
||||
shadowData.ContextIndex = renderContextBatch.Contexts.Count();
|
||||
shadowData.ContextCount = 1;
|
||||
renderContextBatch.Contexts.AddDefault(shadowData.ContextCount);
|
||||
|
||||
const auto& view = renderContext.View;
|
||||
const auto shadowMapsSizeCube = (float)_shadowMapsSizeCube;
|
||||
|
||||
// Fade shadow on distance
|
||||
const float fadeDistance = Math::Max(light.ShadowsFadeDistance, 0.1f);
|
||||
const float dstLightToView = Float3::Distance(light.Position, view.Position);
|
||||
const float fade = 1 - Math::Saturate((dstLightToView - light.Radius - light.ShadowsDistance + fadeDistance) / fadeDistance);
|
||||
|
||||
// Render depth to all 1 face of the cube map
|
||||
constexpr int32 faceIndex = 0;
|
||||
{
|
||||
auto& shadowContext = renderContextBatch.Contexts[shadowData.ContextIndex + faceIndex];
|
||||
SetupRenderContext(renderContext, shadowContext);
|
||||
shadowContext.List->Clear();
|
||||
shadowContext.View.SetProjector(SpotLight_NearPlane, light.Radius, light.Position, light.Direction, light.UpVector, light.OuterConeAngle * 2.0f);
|
||||
shadowContext.View.PrepareCache(shadowContext, shadowMapsSizeCube, shadowMapsSizeCube, Float2::Zero, &view);
|
||||
Matrix::Transpose(shadowContext.View.ViewProjection(), shadowData.Constants.ShadowVP[faceIndex]);
|
||||
}
|
||||
|
||||
// Setup constant buffer data
|
||||
shadowData.Constants.ShadowMapSize = shadowMapsSizeCube;
|
||||
shadowData.Constants.Sharpness = light.ShadowsSharpness;
|
||||
shadowData.Constants.Fade = Math::Saturate(light.ShadowsStrength * fade);
|
||||
shadowData.Constants.NormalOffsetScale = light.ShadowsNormalOffsetScale * NormalOffsetScaleTweak * (1.0f / shadowMapsSizeCube);
|
||||
shadowData.Constants.Bias = light.ShadowsDepthBias;
|
||||
shadowData.Constants.FadeDistance = Math::Max(light.ShadowsFadeDistance, 0.1f);
|
||||
shadowData.Constants.NumCascades = 1;
|
||||
shadowData.Constants.CascadeSplits = Float4::Zero;
|
||||
}
|
||||
|
||||
void ShadowsPass::Dispose()
|
||||
{
|
||||
// Base
|
||||
RendererPass::Dispose();
|
||||
|
||||
// Cleanup
|
||||
_psShadowDir.Delete();
|
||||
_psShadowPoint.Delete();
|
||||
_psShadowSpot.Delete();
|
||||
_shader = nullptr;
|
||||
_sphereModel = nullptr;
|
||||
SAFE_DELETE_GPU_RESOURCE(_shadowMapCSM);
|
||||
SAFE_DELETE_GPU_RESOURCE(_shadowMapCube);
|
||||
}
|
||||
|
||||
void ShadowsPass::SetupShadows(RenderContext& renderContext, RenderContextBatch& renderContextBatch)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
_shadowData.Clear();
|
||||
auto& view = renderContext.View;
|
||||
|
||||
// Update shadow map
|
||||
const auto shadowMapsQuality = Graphics::ShadowMapsQuality;
|
||||
if (shadowMapsQuality != _currentShadowMapsQuality)
|
||||
updateShadowMapSize();
|
||||
auto shadowsQuality = Graphics::ShadowsQuality;
|
||||
maxShadowsQuality = Math::Clamp(Math::Min<int32>(static_cast<int32>(shadowsQuality), static_cast<int32>(view.MaxShadowsQuality)), 0, static_cast<int32>(Quality::MAX) - 1);
|
||||
|
||||
// Create shadow projections for lights
|
||||
for (auto& light : renderContext.List->DirectionalLights)
|
||||
{
|
||||
if (::CanRenderShadow(view, light) && CanRenderShadow(renderContext, light))
|
||||
SetupLight(renderContext, renderContextBatch, light);
|
||||
}
|
||||
for (auto& light : renderContext.List->PointLights)
|
||||
{
|
||||
if (::CanRenderShadow(view, light) && CanRenderShadow(renderContext, light))
|
||||
SetupLight(renderContext, renderContextBatch, light);
|
||||
}
|
||||
for (auto& light : renderContext.List->SpotLights)
|
||||
{
|
||||
if (::CanRenderShadow(view, light) && CanRenderShadow(renderContext, light))
|
||||
SetupLight(renderContext, renderContextBatch, light);
|
||||
}
|
||||
}
|
||||
|
||||
bool ShadowsPass::CanRenderShadow(const RenderContext& renderContext, const RendererPointLightData& light)
|
||||
{
|
||||
const Float3 lightPosition = light.Position;
|
||||
const float dstLightToView = Float3::Distance(lightPosition, renderContext.View.Position);
|
||||
|
||||
// Fade shadow on distance
|
||||
const float fadeDistance = Math::Max(light.ShadowsFadeDistance, 0.1f);
|
||||
const float fade = 1 - Math::Saturate((dstLightToView - light.Radius - light.ShadowsDistance + fadeDistance) / fadeDistance);
|
||||
|
||||
return fade > ZeroTolerance && _supportsShadows;
|
||||
}
|
||||
|
||||
bool ShadowsPass::CanRenderShadow(const RenderContext& renderContext, const RendererSpotLightData& light)
|
||||
{
|
||||
const Float3 lightPosition = light.Position;
|
||||
const float dstLightToView = Float3::Distance(lightPosition, renderContext.View.Position);
|
||||
|
||||
// Fade shadow on distance
|
||||
const float fadeDistance = Math::Max(light.ShadowsFadeDistance, 0.1f);
|
||||
const float fade = 1 - Math::Saturate((dstLightToView - light.Radius - light.ShadowsDistance + fadeDistance) / fadeDistance);
|
||||
|
||||
return fade > ZeroTolerance && _supportsShadows;
|
||||
}
|
||||
|
||||
bool ShadowsPass::CanRenderShadow(const RenderContext& renderContext, const RendererDirectionalLightData& light)
|
||||
{
|
||||
return _supportsShadows;
|
||||
}
|
||||
|
||||
void ShadowsPass::RenderShadow(RenderContextBatch& renderContextBatch, RendererPointLightData& light, GPUTextureView* shadowMask)
|
||||
{
|
||||
if (light.ShadowDataIndex == -1)
|
||||
return;
|
||||
PROFILE_GPU_CPU("Shadow");
|
||||
GPUContext* context = GPUDevice::Instance->GetMainContext();
|
||||
RenderContext& renderContext = renderContextBatch.Contexts[0];
|
||||
ShadowData& shadowData = _shadowData[light.ShadowDataIndex];
|
||||
const float sphereModelScale = 3.0f;
|
||||
auto& view = renderContext.View;
|
||||
auto shader = _shader->GetShader();
|
||||
|
||||
// TODO: here we can use lower shadows quality based on light distance to view (LOD switching) and per light setting for max quality
|
||||
int32 shadowQuality = maxShadowsQuality;
|
||||
|
||||
// Set up GPU context and render view
|
||||
const auto shadowMapsSizeCube = (float)_shadowMapsSizeCube;
|
||||
context->SetViewportAndScissors(shadowMapsSizeCube, shadowMapsSizeCube);
|
||||
|
||||
// Render depth to all 6 faces of the cube map
|
||||
for (int32 faceIndex = 0; faceIndex < 6; faceIndex++)
|
||||
{
|
||||
auto rt = _shadowMapCube->View(faceIndex);
|
||||
context->ResetSR();
|
||||
context->SetRenderTarget(rt, static_cast<GPUTextureView*>(nullptr));
|
||||
context->ClearDepth(rt);
|
||||
|
||||
// Render actors to the shadow map
|
||||
renderContext.Task->OnCollectDrawCalls(_shadowContext);
|
||||
_shadowCache.SortDrawCalls(_shadowContext, false, DrawCallsListType::Depth);
|
||||
_shadowCache.ExecuteDrawCalls(_shadowContext, DrawCallsListType::Depth);
|
||||
auto& shadowContext = renderContextBatch.Contexts[shadowData.ContextIndex + faceIndex];
|
||||
shadowContext.List->ExecuteDrawCalls(shadowContext, DrawCallsListType::Depth);
|
||||
}
|
||||
|
||||
// Restore GPU context
|
||||
@@ -720,27 +647,168 @@ void ShadowsPass::RenderShadow(RenderContext& renderContext, RendererDirectional
|
||||
context->BindSR(4, renderContext.Buffers->GBuffer3);
|
||||
|
||||
// Setup shader data
|
||||
Data sperLight;
|
||||
GBufferPass::SetInputs(view, sperLight.GBuffer);
|
||||
light.SetupLightData(&sperLight.Light, true);
|
||||
sperLight.LightShadow.ShadowMapSize = shadowMapsSizeCSM;
|
||||
sperLight.LightShadow.Sharpness = light.ShadowsSharpness;
|
||||
sperLight.LightShadow.Fade = Math::Saturate(light.ShadowsStrength);
|
||||
sperLight.LightShadow.NormalOffsetScale = light.ShadowsNormalOffsetScale * NormalOffsetScaleTweak * (1.0f / shadowMapsSizeCSM);
|
||||
sperLight.LightShadow.Bias = light.ShadowsDepthBias;
|
||||
sperLight.LightShadow.FadeDistance = Math::Max(light.ShadowsFadeDistance, 0.1f);
|
||||
sperLight.LightShadow.NumCascades = csmCount;
|
||||
sperLight.LightShadow.CascadeSplits = view.Near + Float4(cascadeSplits) * cameraRange;
|
||||
sperLight.LightShadow = shadowData.Constants;
|
||||
Matrix::Transpose(view.ViewProjection(), sperLight.ViewProjectionMatrix);
|
||||
sperLight.ContactShadowsDistance = light.ShadowsDistance;
|
||||
sperLight.ContactShadowsLength = view.Flags & ViewFlags::ContactShadows ? light.ContactShadowsLength : 0.0f;
|
||||
|
||||
// Calculate world view projection matrix for the light sphere
|
||||
Matrix world, wvp, matrix;
|
||||
Matrix::Scaling(light.Radius * sphereModelScale, wvp);
|
||||
Matrix::Translation(light.Position, matrix);
|
||||
Matrix::Multiply(wvp, matrix, world);
|
||||
Matrix::Multiply(world, view.ViewProjection(), wvp);
|
||||
Matrix::Transpose(wvp, sperLight.WVP);
|
||||
|
||||
// Render shadow in screen space
|
||||
context->UpdateCB(shader->GetCB(0), &sperLight);
|
||||
context->BindCB(0, shader->GetCB(0));
|
||||
context->BindCB(1, shader->GetCB(1));
|
||||
context->BindSR(5, _shadowMapCube->ViewArray());
|
||||
context->SetRenderTarget(shadowMask);
|
||||
context->SetState(_psShadowPoint.Get(shadowQuality + (sperLight.ContactShadowsLength > ZeroTolerance ? 4 : 0)));
|
||||
_sphereModel->Render(context);
|
||||
|
||||
// Cleanup
|
||||
context->ResetRenderTarget();
|
||||
context->UnBindSR(5);
|
||||
|
||||
// Render volumetric light with shadow
|
||||
VolumetricFogPass::Instance()->RenderLight(renderContext, context, light, _shadowMapCube->ViewArray(), sperLight.LightShadow);
|
||||
}
|
||||
|
||||
void ShadowsPass::RenderShadow(RenderContextBatch& renderContextBatch, RendererSpotLightData& light, GPUTextureView* shadowMask)
|
||||
{
|
||||
if (light.ShadowDataIndex == -1)
|
||||
return;
|
||||
PROFILE_GPU_CPU("Shadow");
|
||||
GPUContext* context = GPUDevice::Instance->GetMainContext();
|
||||
RenderContext& renderContext = renderContextBatch.Contexts[0];
|
||||
ShadowData& shadowData = _shadowData[light.ShadowDataIndex];
|
||||
const float sphereModelScale = 3.0f;
|
||||
auto& view = renderContext.View;
|
||||
auto shader = _shader->GetShader();
|
||||
|
||||
// TODO: here we can use lower shadows quality based on light distance to view (LOD switching) and per light setting for max quality
|
||||
int32 shadowQuality = maxShadowsQuality;
|
||||
|
||||
// Set up GPU context and render view
|
||||
const auto shadowMapsSizeCube = (float)_shadowMapsSizeCube;
|
||||
context->SetViewportAndScissors(shadowMapsSizeCube, shadowMapsSizeCube);
|
||||
|
||||
// Render depth to all 1 face of the cube map
|
||||
constexpr int32 faceIndex = 0;
|
||||
{
|
||||
auto rt = _shadowMapCube->View(faceIndex);
|
||||
context->ResetSR();
|
||||
context->SetRenderTarget(rt, static_cast<GPUTextureView*>(nullptr));
|
||||
context->ClearDepth(rt);
|
||||
auto& shadowContext = renderContextBatch.Contexts[shadowData.ContextIndex + faceIndex];
|
||||
shadowContext.List->ExecuteDrawCalls(shadowContext, DrawCallsListType::Depth);
|
||||
}
|
||||
|
||||
// Restore GPU context
|
||||
context->ResetSR();
|
||||
context->ResetRenderTarget();
|
||||
const Viewport viewport = renderContext.Task->GetViewport();
|
||||
GPUTexture* depthBuffer = renderContext.Buffers->DepthBuffer;
|
||||
GPUTextureView* depthBufferSRV = depthBuffer->GetDescription().Flags & GPUTextureFlags::ReadOnlyDepthView ? depthBuffer->ViewReadOnlyDepth() : depthBuffer->View();
|
||||
context->SetViewportAndScissors(viewport);
|
||||
context->BindSR(0, renderContext.Buffers->GBuffer0);
|
||||
context->BindSR(1, renderContext.Buffers->GBuffer1);
|
||||
context->BindSR(2, renderContext.Buffers->GBuffer2);
|
||||
context->BindSR(3, depthBufferSRV);
|
||||
context->BindSR(4, renderContext.Buffers->GBuffer3);
|
||||
|
||||
// Setup shader data
|
||||
Data sperLight;
|
||||
GBufferPass::SetInputs(view, sperLight.GBuffer);
|
||||
light.SetupLightData(&sperLight.Light, true);
|
||||
sperLight.LightShadow = shadowData.Constants;
|
||||
Matrix::Transpose(view.ViewProjection(), sperLight.ViewProjectionMatrix);
|
||||
sperLight.ContactShadowsDistance = light.ShadowsDistance;
|
||||
sperLight.ContactShadowsLength = view.Flags & ViewFlags::ContactShadows ? light.ContactShadowsLength : 0.0f;
|
||||
|
||||
// Calculate world view projection matrix for the light sphere
|
||||
Matrix world, wvp, matrix;
|
||||
Matrix::Scaling(light.Radius * sphereModelScale, wvp);
|
||||
Matrix::Translation(light.Position, matrix);
|
||||
Matrix::Multiply(wvp, matrix, world);
|
||||
Matrix::Multiply(world, view.ViewProjection(), wvp);
|
||||
Matrix::Transpose(wvp, sperLight.WVP);
|
||||
|
||||
// Render shadow in screen space
|
||||
context->UpdateCB(shader->GetCB(0), &sperLight);
|
||||
context->BindCB(0, shader->GetCB(0));
|
||||
context->BindCB(1, shader->GetCB(1));
|
||||
context->BindSR(5, _shadowMapCube->View(faceIndex));
|
||||
context->SetRenderTarget(shadowMask);
|
||||
context->SetState(_psShadowSpot.Get(shadowQuality + (sperLight.ContactShadowsLength > ZeroTolerance ? 4 : 0)));
|
||||
_sphereModel->Render(context);
|
||||
|
||||
// Cleanup
|
||||
context->ResetRenderTarget();
|
||||
context->UnBindSR(5);
|
||||
|
||||
// Render volumetric light with shadow
|
||||
VolumetricFogPass::Instance()->RenderLight(renderContext, context, light, _shadowMapCube->View(faceIndex), sperLight.LightShadow);
|
||||
}
|
||||
|
||||
void ShadowsPass::RenderShadow(RenderContextBatch& renderContextBatch, RendererDirectionalLightData& light, int32 index, GPUTextureView* shadowMask)
|
||||
{
|
||||
if (light.ShadowDataIndex == -1)
|
||||
return;
|
||||
PROFILE_GPU_CPU("Shadow");
|
||||
GPUContext* context = GPUDevice::Instance->GetMainContext();
|
||||
RenderContext& renderContext = renderContextBatch.Contexts[0];
|
||||
ShadowData& shadowData = _shadowData[light.ShadowDataIndex];
|
||||
const float shadowMapsSizeCSM = (float)_shadowMapsSizeCSM;
|
||||
context->SetViewportAndScissors(shadowMapsSizeCSM, shadowMapsSizeCSM);
|
||||
|
||||
// Render shadow map for each projection
|
||||
for (int32 cascadeIndex = 0; cascadeIndex < shadowData.ContextCount; cascadeIndex++)
|
||||
{
|
||||
const auto rt = _shadowMapCSM->View(cascadeIndex);
|
||||
context->ResetSR();
|
||||
context->SetRenderTarget(rt, static_cast<GPUTextureView*>(nullptr));
|
||||
context->ClearDepth(rt);
|
||||
auto& shadowContext = renderContextBatch.Contexts[shadowData.ContextIndex + cascadeIndex];
|
||||
shadowContext.List->ExecuteDrawCalls(shadowContext, DrawCallsListType::Depth);
|
||||
}
|
||||
|
||||
// Restore GPU context
|
||||
context->ResetSR();
|
||||
context->ResetRenderTarget();
|
||||
GPUTexture* depthBuffer = renderContext.Buffers->DepthBuffer;
|
||||
GPUTextureView* depthBufferSRV = depthBuffer->GetDescription().Flags & GPUTextureFlags::ReadOnlyDepthView ? depthBuffer->ViewReadOnlyDepth() : depthBuffer->View();
|
||||
context->SetViewportAndScissors(renderContext.Task->GetViewport());
|
||||
context->BindSR(0, renderContext.Buffers->GBuffer0);
|
||||
context->BindSR(1, renderContext.Buffers->GBuffer1);
|
||||
context->BindSR(2, renderContext.Buffers->GBuffer2);
|
||||
context->BindSR(3, depthBufferSRV);
|
||||
context->BindSR(4, renderContext.Buffers->GBuffer3);
|
||||
|
||||
// Setup shader data
|
||||
Data sperLight;
|
||||
auto& view = renderContext.View;
|
||||
GBufferPass::SetInputs(view, sperLight.GBuffer);
|
||||
light.SetupLightData(&sperLight.Light, true);
|
||||
sperLight.LightShadow = shadowData.Constants;
|
||||
Matrix::Transpose(view.ViewProjection(), sperLight.ViewProjectionMatrix);
|
||||
sperLight.ContactShadowsDistance = light.ShadowsDistance;
|
||||
sperLight.ContactShadowsLength = view.Flags & ViewFlags::ContactShadows ? light.ContactShadowsLength : 0.0f;
|
||||
|
||||
// Render shadow in screen space
|
||||
auto shader = _shader->GetShader();
|
||||
context->UpdateCB(shader->GetCB(0), &sperLight);
|
||||
context->BindCB(0, shader->GetCB(0));
|
||||
context->BindCB(1, shader->GetCB(1));
|
||||
context->BindSR(5, _shadowMapCSM->ViewArray());
|
||||
context->SetRenderTarget(shadowMask);
|
||||
context->SetState(_psShadowDir.Get(maxShadowsQuality + static_cast<int32>(Quality::MAX) * blendCSM + (sperLight.ContactShadowsLength > ZeroTolerance ? 8 : 0)));
|
||||
context->SetState(_psShadowDir.Get(maxShadowsQuality + static_cast<int32>(Quality::MAX) * shadowData.BlendCSM + (sperLight.ContactShadowsLength > ZeroTolerance ? 8 : 0)));
|
||||
context->DrawFullscreenTriangle();
|
||||
|
||||
// Cleanup
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#define SHADOWS_PASS_SS_RR_FORMAT PixelFormat::R11G11B10_Float
|
||||
|
||||
template<typename T>
|
||||
bool CanRenderShadow(RenderView& view, const T& light)
|
||||
bool CanRenderShadow(const RenderView& view, const T& light)
|
||||
{
|
||||
bool result = false;
|
||||
switch ((ShadowsCastingMode)light.ShadowsMode)
|
||||
@@ -42,6 +42,14 @@ class ShadowsPass : public RendererPass<ShadowsPass>
|
||||
{
|
||||
private:
|
||||
|
||||
struct ShadowData
|
||||
{
|
||||
int32 ContextIndex;
|
||||
int32 ContextCount;
|
||||
bool BlendCSM;
|
||||
LightShadowData Constants;
|
||||
};
|
||||
|
||||
// Shader stuff
|
||||
AssetReference<Shader> _shader;
|
||||
GPUPipelineStatePermutationsPs<static_cast<int32>(Quality::MAX) * 2 * 2> _psShadowDir;
|
||||
@@ -57,9 +65,8 @@ private:
|
||||
Quality _currentShadowMapsQuality;
|
||||
|
||||
// Shadow map rendering stuff
|
||||
RenderContext _shadowContext;
|
||||
RenderList _shadowCache;
|
||||
AssetReference<Model> _sphereModel;
|
||||
Array<ShadowData> _shadowData;
|
||||
|
||||
// Cached state for the current frame rendering (setup via Prepare)
|
||||
int32 maxShadowsQuality;
|
||||
@@ -87,6 +94,10 @@ public:
|
||||
LightShadowData LastDirLight;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Setups the shadows rendering for batched scene drawing. Checks which lights will cast a shadow.
|
||||
/// </summary>
|
||||
void SetupShadows(RenderContext& renderContext, RenderContextBatch& renderContextBatch);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether can render shadow for the specified light.
|
||||
@@ -94,7 +105,7 @@ public:
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="light">The light.</param>
|
||||
/// <returns><c>true</c> if can render shadow for the specified light; otherwise, <c>false</c>.</returns>
|
||||
bool CanRenderShadow(RenderContext& renderContext, const RendererPointLightData& light);
|
||||
bool CanRenderShadow(const RenderContext& renderContext, const RendererPointLightData& light);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether can render shadow for the specified light.
|
||||
@@ -102,7 +113,7 @@ public:
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="light">The light.</param>
|
||||
/// <returns><c>true</c> if can render shadow for the specified light; otherwise, <c>false</c>.</returns>
|
||||
bool CanRenderShadow(RenderContext& renderContext, const RendererSpotLightData& light);
|
||||
bool CanRenderShadow(const RenderContext& renderContext, const RendererSpotLightData& light);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether can render shadow for the specified light.
|
||||
@@ -110,43 +121,40 @@ public:
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="light">The light.</param>
|
||||
/// <returns><c>true</c> if can render shadow for the specified light; otherwise, <c>false</c>.</returns>
|
||||
bool CanRenderShadow(RenderContext& renderContext, const RendererDirectionalLightData& light);
|
||||
|
||||
/// <summary>
|
||||
/// Prepares the shadows rendering. Called by the light pass once per frame.
|
||||
/// </summary>
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="context">The GPU command context.</param>
|
||||
void Prepare(RenderContext& renderContext, GPUContext* context);
|
||||
bool CanRenderShadow(const RenderContext& renderContext, const RendererDirectionalLightData& light);
|
||||
|
||||
/// <summary>
|
||||
/// Renders the shadow mask for the given light.
|
||||
/// </summary>
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="renderContextBatch">The rendering context batch.</param>
|
||||
/// <param name="light">The light.</param>
|
||||
/// <param name="shadowMask">The shadow mask (output).</param>
|
||||
void RenderShadow(RenderContext& renderContext, RendererPointLightData& light, GPUTextureView* shadowMask);
|
||||
void RenderShadow(RenderContextBatch& renderContextBatch, RendererPointLightData& light, GPUTextureView* shadowMask);
|
||||
|
||||
/// <summary>
|
||||
/// Renders the shadow mask for the given light.
|
||||
/// </summary>
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="renderContextBatch">The rendering context batch.</param>
|
||||
/// <param name="light">The light.</param>
|
||||
/// <param name="shadowMask">The shadow mask (output).</param>
|
||||
void RenderShadow(RenderContext& renderContext, RendererSpotLightData& light, GPUTextureView* shadowMask);
|
||||
void RenderShadow(RenderContextBatch& renderContextBatch, RendererSpotLightData& light, GPUTextureView* shadowMask);
|
||||
|
||||
/// <summary>
|
||||
/// Renders the shadow mask for the given light.
|
||||
/// </summary>
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="renderContextBatch">The rendering context batch.</param>
|
||||
/// <param name="light">The light.</param>
|
||||
/// <param name="index">The light index.</param>
|
||||
/// <param name="shadowMask">The shadow mask (output).</param>
|
||||
void RenderShadow(RenderContext& renderContext, RendererDirectionalLightData& light, int32 index, GPUTextureView* shadowMask);
|
||||
void RenderShadow(RenderContextBatch& renderContextBatch, RendererDirectionalLightData& light, int32 index, GPUTextureView* shadowMask);
|
||||
|
||||
private:
|
||||
|
||||
void updateShadowMapSize();
|
||||
void SetupRenderContext(RenderContext& renderContext, RenderContext& shadowContext);
|
||||
void SetupLight(RenderContext& renderContext, RenderContextBatch& renderContextBatch, RendererDirectionalLightData& light);
|
||||
void SetupLight(RenderContext& renderContext, RenderContextBatch& renderContextBatch, RendererPointLightData& light);
|
||||
void SetupLight(RenderContext& renderContext, RenderContextBatch& renderContextBatch, RendererSpotLightData& light);
|
||||
|
||||
#if COMPILE_WITH_DEV_ENV
|
||||
void OnShaderReloading(Asset* obj)
|
||||
|
||||
@@ -121,8 +121,9 @@ void TerrainChunk::Draw(const RenderContext& renderContext) const
|
||||
//drawCall.TerrainData.HeightmapUVScaleBias.W += halfTexelOffset;
|
||||
|
||||
// Submit draw call
|
||||
auto drawModes = (DrawPass)(_patch->_terrain->DrawModes & renderContext.View.Pass);
|
||||
renderContext.List->AddDrawCall(drawModes, flags, drawCall, true);
|
||||
auto drawModes = (DrawPass)(_patch->_terrain->DrawModes & renderContext.View.Pass & (uint32)drawCall.Material->GetDrawModes());
|
||||
if (drawModes != DrawPass::None)
|
||||
renderContext.List->AddDrawCall(drawModes, flags, drawCall, true);
|
||||
}
|
||||
|
||||
void TerrainChunk::Draw(const RenderContext& renderContext, MaterialBase* material, int32 lodIndex) const
|
||||
@@ -176,8 +177,9 @@ void TerrainChunk::Draw(const RenderContext& renderContext, MaterialBase* materi
|
||||
//drawCall.TerrainData.HeightmapUVScaleBias.W += halfTexelOffset;
|
||||
|
||||
// Submit draw call
|
||||
auto drawModes = (DrawPass)(_patch->_terrain->DrawModes & renderContext.View.Pass);
|
||||
renderContext.List->AddDrawCall(drawModes, flags, drawCall, true);
|
||||
auto drawModes = (DrawPass)(_patch->_terrain->DrawModes & renderContext.View.Pass & (uint32)drawCall.Material->GetDrawModes());
|
||||
if (drawModes != DrawPass::None)
|
||||
renderContext.List->AddDrawCall(drawModes, flags, drawCall, true);
|
||||
}
|
||||
|
||||
bool TerrainChunk::Intersects(const Ray& ray, Real& distance)
|
||||
|
||||
@@ -344,14 +344,12 @@ void TextRender::Draw(RenderContext& renderContext)
|
||||
if (renderContext.View.Pass == DrawPass::GlobalSurfaceAtlas)
|
||||
return; // TODO: Text rendering to Global Surface Atlas
|
||||
if (_isDirty)
|
||||
{
|
||||
UpdateLayout();
|
||||
}
|
||||
Matrix world;
|
||||
renderContext.View.GetWorldMatrix(_transform, world);
|
||||
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
|
||||
|
||||
const DrawPass drawModes = (DrawPass)(DrawModes & renderContext.View.Pass & (int32)renderContext.View.GetShadowsDrawPassMask(ShadowsMode));
|
||||
const DrawPass drawModes = (DrawPass)(DrawModes & renderContext.View.Pass & (uint32)renderContext.View.GetShadowsDrawPassMask(ShadowsMode));
|
||||
if (_vb0.Data.Count() > 0 && drawModes != DrawPass::None)
|
||||
{
|
||||
#if USE_EDITOR
|
||||
@@ -394,6 +392,8 @@ void TextRender::Draw(RenderContext& renderContext)
|
||||
// Submit draw calls
|
||||
for (const auto& e : _drawChunks)
|
||||
{
|
||||
if ((drawModes & e.Material->GetDrawModes()) == 0)
|
||||
continue;
|
||||
drawCall.Draw.IndicesCount = e.IndicesCount;
|
||||
drawCall.Draw.StartIndex = e.StartIndex;
|
||||
drawCall.Material = e.Material;
|
||||
|
||||
Reference in New Issue
Block a user