Refactor GeometryDrawStateData storage into RenderBufers for correct split-screen rendering

Refactor `ISceneRenderingListener` events to contain more data
This commit is contained in:
2026-08-03 07:08:27 +02:00
parent e8c63066e3
commit d845eb54ce
26 changed files with 188 additions and 89 deletions
@@ -130,8 +130,6 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Scene
const BoundingFrustum frustum = view.Frustum;
const auto& icons = scene->GetSceneRendering()->ViewportIcons;
Matrix m1, m2, world;
GeometryDrawStateData drawState;
draw.DrawState = &drawState;
draw.World = &world;
AssetReference<Texture> texture;
for (Actor* icon : icons)
@@ -211,10 +209,6 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Actor
Matrix::Billboard(sphere.Center, view.Position, Vector3::Up, view.Direction, m2);
Matrix::Multiply(m1, m2, world);
// Draw icon
GeometryDrawStateData drawState;
draw.DrawState = &drawState;
// Support custom icons through types, but not ones that were added through actors, since they cant register while in prefab view anyway
if (ActorTypeToTexture.TryGet(actor->GetTypeHandle(), texture))
{
@@ -227,9 +221,7 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Actor
draw.Buffer->At(0).ReceiveDecals = false;
draw.Buffer->At(0).ShadowsMode = ShadowsCastingMode::None;
}
AssetReference<MaterialBase> material;
if (!TextureToMaterial.TryGet(texture, material))
{
// Create custom material per custom texture
@@ -237,7 +229,6 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Actor
TextureToMaterial[texture]->SetParameterValue(TEXT("Image"), Variant(texture));
material = TextureToMaterial[texture];
}
draw.Buffer->At(0).Material = material;
}
else
@@ -246,6 +237,7 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Actor
draw.Buffer = &InstanceBuffers[static_cast<int32>(iconType)];
}
// Draw icon
draw.World = &world;
draw.Bounds = sphere;
QuadModel->Draw(renderContext, draw);
+1 -1
View File
@@ -228,7 +228,7 @@ public:
/// </summary>
/// <param name="index">The index.</param>
/// <returns><c>true</c> if is valid a index; otherwise, <c>false</c>.</returns>
bool IsValidIndex(const int32 index) const
FORCE_INLINE bool IsValidIndex(const int32 index) const
{
return index < _count && index >= 0;
}
-6
View File
@@ -356,8 +356,6 @@ void Foliage::DrawCluster(DrawContext& context, FoliageCluster* cluster, Mesh::D
Matrix::Transformation(transform.Scale, transform.Orientation, translation, world);
// Disable motion blur
GeometryDrawStateData drawState;
drawState.PrevWorld = world;
instance.DrawState.PrevWorld = world;
// Draw model
@@ -365,7 +363,6 @@ void Foliage::DrawCluster(DrawContext& context, FoliageCluster* cluster, Mesh::D
draw.LightmapUVs = &instance.Lightmap.UVsArea;
draw.Buffer = &type.Entries;
draw.World = &world;
draw.DrawState = &drawState;
draw.Bounds = sphere;
draw.PerInstanceRandom = instance.Random;
draw.DrawModes = type._drawModes;
@@ -1290,15 +1287,12 @@ void Foliage::Draw(RenderContext& renderContext)
Matrix world;
const Transform transform = _transform.LocalToWorld(instance.Transform);
renderContext.View.GetWorldMatrix(transform, world);
GeometryDrawStateData drawState;
drawState.PrevWorld = world;
Mesh::DrawInfo draw;
draw.Flags = GetStaticFlags();
draw.Lightmap = _scene ? _scene->LightmapsData.GetReadyLightmap(instance.LightmapTextureIndex) : nullptr;
draw.LightmapUVs = &instance.LightmapUVsArea;
draw.Buffer = &type.Entries;
draw.World = &world;
draw.DrawState = &drawState;
draw.Bounds = instance.Bounds;
draw.PerInstanceRandom = instance.Random;
draw.DrawModes = type._drawModes & view.Pass & view.GetShadowsDrawPassMask(type.ShadowsMode);
+2 -2
View File
@@ -302,7 +302,7 @@ void Mesh::Draw(const RenderContext& renderContext, const DrawInfo& info, float
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = (float)info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition?
drawCall.Surface.GeometrySize = _box.GetSize();
drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
drawCall.Surface.PrevWorld = info.DrawState ? info.DrawState->PrevWorld : drawCall.World;
drawCall.Surface.Lightmap = (info.Flags & StaticFlags::Lightmap) != StaticFlags::None ? info.Lightmap : nullptr;
drawCall.Surface.LightmapUVsArea = info.LightmapUVs ? *info.LightmapUVs : Half4::Zero;
drawCall.Surface.LODDitherFactor = (int8)(lodDitherFactor * 127);
@@ -365,7 +365,7 @@ void Mesh::Draw(const RenderContextBatch& renderContextBatch, const DrawInfo& in
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = (float)info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition?
drawCall.Surface.GeometrySize = _box.GetSize();
drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
drawCall.Surface.PrevWorld = info.DrawState ? info.DrawState->PrevWorld : drawCall.World;
drawCall.Surface.Lightmap = (info.Flags & StaticFlags::Lightmap) != StaticFlags::None ? info.Lightmap : nullptr;
drawCall.Surface.LightmapUVsArea = info.LightmapUVs ? *info.LightmapUVs : Half4::Zero;
drawCall.Surface.LODDitherFactor = (int8)(lodDitherFactor * 127);
+3 -3
View File
@@ -14,7 +14,7 @@
#include "CollisionProxy.h"
#endif
struct GeometryDrawStateData;
struct GeometryDrawState;
struct RenderContext;
struct RenderContextBatch;
class Task;
@@ -347,9 +347,9 @@ public:
Matrix* World;
/// <summary>
/// The instance drawing state data container. Used for LOD transition handling and previous world transformation matrix updating.
/// The instance drawing state data container (optional). Used for LOD transition handling and previous world transformation matrix updating.
/// </summary>
GeometryDrawStateData* DrawState;
GeometryDrawState* DrawState;
/// <summary>
/// The instance deformation utility.
+15 -6
View File
@@ -31,6 +31,18 @@ FORCE_INLINE void ModelDraw(ModelType* model, const RenderContext& renderContext
return;
if (!info.Buffer->IsValidFor(model))
info.Buffer->Setup(model);
if (!info.DrawState || renderContext.View.IsSingleFrame)
{
// No LOD transition
int32 lodIndex = info.ForcedLOD != -1 ? info.ForcedLOD : RenderTools::ComputeModelLOD(model, info.Bounds.Center, (float)info.Bounds.Radius, renderContext);
if (lodIndex != -1)
{
lodIndex += info.LODBias + renderContext.View.ModelLODBias;
lodIndex = model->ClampLODIndex(lodIndex);
model->LODs.Get()[lodIndex].Draw(context, info, 0.0f);
}
return;
}
const auto frame = Engine::FrameCount;
const auto modelFrame = info.DrawState->PrevFrame + 1;
@@ -46,7 +58,7 @@ FORCE_INLINE void ModelDraw(ModelType* model, const RenderContext& renderContext
if (lodIndex == -1)
{
// Handling model fade-out transition
if (modelFrame == frame && info.DrawState->PrevLOD != -1 && !renderContext.View.IsSingleFrame && ModelDrawTransition(model, info))
if (modelFrame == frame && info.DrawState->PrevLOD != -1 && ModelDrawTransition(model, info))
{
// Check if start transition
if (info.DrawState->LODTransition == 255)
@@ -75,11 +87,8 @@ FORCE_INLINE void ModelDraw(ModelType* model, const RenderContext& renderContext
lodIndex += info.LODBias + renderContext.View.ModelLODBias;
lodIndex = model->ClampLODIndex(lodIndex);
if (renderContext.View.IsSingleFrame)
{
}
// Check if it's the new frame and could update the drawing state (note: model instance could be rendered many times per frame to different viewports)
else if (modelFrame == frame)
if (modelFrame == frame)
{
// Check if materials use transition
if (!ModelDrawTransition(model, info))
@@ -111,7 +120,7 @@ FORCE_INLINE void ModelDraw(ModelType* model, const RenderContext& renderContext
}
// Draw
if (info.DrawState->PrevLOD == lodIndex || info.DrawState->LODTransition == 255 || renderContext.View.IsSingleFrame)
if (info.DrawState->PrevLOD == lodIndex || info.DrawState->LODTransition == 255)
{
model->LODs.Get()[lodIndex].Draw(context, info, 0.0f);
}
@@ -377,7 +377,7 @@ void SkinnedMesh::Draw(const RenderContext& renderContext, const DrawInfo& info,
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = (float)info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition?
drawCall.Surface.GeometrySize = _box.GetSize();
drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
drawCall.Surface.PrevWorld = info.DrawState ? info.DrawState->PrevWorld : drawCall.World;
drawCall.Surface.Skinning = info.WithPrevBones ? DrawCall::SkinningMode::WithPrevBones : DrawCall::SkinningMode::Active;
drawCall.Surface.SkinningBones = info.SkinningBones;
drawCall.Surface.SkinningBonesOffset = info.SkinningBonesOffset;
@@ -422,7 +422,7 @@ void SkinnedMesh::Draw(const RenderContextBatch& renderContextBatch, const DrawI
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = (float)info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition?
drawCall.Surface.GeometrySize = _box.GetSize();
drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
drawCall.Surface.PrevWorld = info.DrawState ? info.DrawState->PrevWorld : drawCall.World;
drawCall.Surface.Skinning = info.WithPrevBones ? DrawCall::SkinningMode::WithPrevBones : DrawCall::SkinningMode::Active;
drawCall.Surface.SkinningBones = info.SkinningBones;
drawCall.Surface.SkinningBonesOffset = info.SkinningBonesOffset;
+63
View File
@@ -304,3 +304,66 @@ RenderBuffers::ReadOnlyDepthBuffer RenderBuffers::GetReadOnlyDepthBuffer() const
GPUTextureView* depthBufferSRV = depthBufferReadOnly ? depthBuffer->ViewReadOnlyDepth() : depthBuffer->View();
return { depthBufferRTV, depthBufferSRV };
}
void RenderBuffers::OnSceneRendering(SceneRendering* scene)
{
if (!Scenes.ContainsKey(scene))
{
PROFILE_CPU_NAMED("Init Scene");
// Register scene
auto& sceneData = Scenes[scene];
ListenSceneRendering(scene);
// Put all existing actors into the render buffer geo storage used for LOD transitions, etc.
for (int32 i = 0; i < SceneRendering::MAX; i++)
{
auto& list = scene->Actors[i];
auto& geo = sceneData.Geo[i];
geo.Resize(list.Count());
auto geoPtr = geo.Get();
for (int32 j = 0; j < list.Count(); j++)
geoPtr[j] = GeometryDrawState();
}
}
}
GeometryDrawState* RenderBuffers::GetGeometryDrawState(SceneRendering* scene, int32 key, const Actor* actor) const
{
if (auto* sceneData = Scenes.TryGet(scene))
{
auto& list = sceneData->Geo[actor->_drawCategory];
if (list.IsValidIndex(key))
{
return list.Get() + key;
}
}
// TODO: what about loose actors drawn from code? dynamically manage their state here?
return nullptr;
}
void RenderBuffers::OnSceneRenderingAddActor(SceneRendering* scene, int32 key, Actor* a)
{
// Init geo state of that object
if (auto* sceneData = Scenes.TryGet(scene))
{
auto& list = sceneData->Geo[a->_drawCategory];
ASSERT(key >= 0);
if (list.Count() <= key)
list.Resize(key + 1);
list.Get()[key] = GeometryDrawState();
}
}
void RenderBuffers::OnSceneRenderingUpdateActor(SceneRendering* scene, int32 key, Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags)
{
}
void RenderBuffers::OnSceneRenderingRemoveActor(SceneRendering* scene, int32 key, Actor* a)
{
}
void RenderBuffers::OnSceneRenderingClear(SceneRendering* scene)
{
Scenes.Remove(scene);
}
+30 -1
View File
@@ -4,8 +4,11 @@
#include "Engine/Core/Math/Viewport.h"
#include "Engine/Core/Collections/Array.h"
#include "Engine/Core/Collections/Dictionary.h"
#include "Engine/Scripting/ScriptingObject.h"
#include "Engine/Graphics/Textures/GPUTexture.h"
#include "Engine/Level/Scene/SceneRendering.h"
#include "Engine/Renderer/DrawCall.h"
// GBuffer render targets formats
#define GBUFFER0_FORMAT PixelFormat::R8G8B8A8_UNorm
@@ -24,10 +27,13 @@
// [7] | <unsued>
#define STENCIL_BUFFER_OBJECT_LAYER(value) uint8(value & 0x1f)
class Actor;
class SceneRendering;
/// <summary>
/// The scene rendering buffers container.
/// </summary>
API_CLASS() class FLAXENGINE_API RenderBuffers : public ScriptingObject
API_CLASS() class FLAXENGINE_API RenderBuffers : public ScriptingObject, private ISceneRenderingListener
{
DECLARE_SCRIPTING_TYPE(RenderBuffers);
@@ -114,6 +120,14 @@ public:
// Maps the custom buffer type into the object that holds the state.
Array<CustomBuffer*, HeapAllocation> CustomBuffers;
// Scene drawing cache with the per-object state (eg. LOD transitions, motion-vectors movement)
struct SceneData
{
// Per-object drawing state (eg. LOD transition). Indexing matches actor/object key of object registered in SceneRendering.
Array<GeometryDrawState> Geo[SceneRendering::DrawCategory::MAX];
};
Dictionary<SceneRendering*, SceneData> Scenes;
public:
/// <summary>
/// Finalizes an instance of the <see cref="RenderBuffers"/> class.
@@ -268,4 +282,19 @@ public:
/// Gets the depth buffer binding for rendering as read-only (both shader resource and render target).
/// </summary>
ReadOnlyDepthBuffer GetReadOnlyDepthBuffer() const;
// Internal event called by SceneRendering to initiate drawing.
void OnSceneRendering(SceneRendering* scene);
/// <summary>
/// Gets the geometry drawing state container for a specific actor/object. Returns null for invalid object (-1) or when view is not using LOD transitions (single-shot frame).
/// </summary>
GeometryDrawState* GetGeometryDrawState(SceneRendering* scene, int32 key, const Actor* actor) const;
public:
// [ISceneRenderingListener]
void OnSceneRenderingAddActor(SceneRendering* scene, int32 key, Actor* a) override;
void OnSceneRenderingUpdateActor(SceneRendering* scene, int32 key, Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags) override;
void OnSceneRenderingRemoveActor(SceneRendering* scene, int32 key, Actor* a) override;
void OnSceneRenderingClear(SceneRendering* scene) override;
};
+2 -2
View File
@@ -468,12 +468,12 @@ API_STRUCT(NoDefault) struct FLAXENGINE_API RenderContext
DECLARE_SCRIPTING_TYPE_MINIMAL(RenderContext);
/// <summary>
/// The render buffers.
/// The render buffers that contain drawing state (eg. LOD transitions) and scene buffers (eg. GBuffer, DDGI, Shadow Maps).
/// </summary>
API_FIELD() RenderBuffers* Buffers = nullptr;
/// <summary>
/// The render list.
/// The render list that collects draw calls.
/// </summary>
API_FIELD() RenderList* List = nullptr;
+2 -1
View File
@@ -32,6 +32,7 @@ API_CLASS(Abstract) class FLAXENGINE_API Actor : public SceneObject
friend SceneRendering;
friend Prefab;
friend PrefabInstanceData;
friend class RenderBuffers;
protected:
uint16 _isActive : 1;
uint16 _isActiveInHierarchy : 1;
@@ -48,7 +49,7 @@ protected:
BoundingBox _box;
String _name;
Scene* _scene;
PhysicsScene* _physicsScene;
PhysicsScene* _physicsScene; // TODO: move it into physics-related actors (coliders, rigidbodies, etc.)
private:
// Disable copying
+10 -6
View File
@@ -16,8 +16,10 @@
#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Graphics/GPUPass.h"
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/RenderBuffers.h"
#include "Engine/Graphics/Models/MeshAccessor.h"
#include "Engine/Graphics/Models/MeshDeformation.h"
#include "Engine/Renderer/DrawCall.h"
#include "Engine/Renderer/RenderList.h"
#include "Engine/Level/Scene/Scene.h"
#include "Engine/Level/SceneObjectsFactory.h"
@@ -1256,8 +1258,9 @@ void AnimatedModel::Draw(RenderContext& renderContext)
return;
if (renderContext.View.Pass == DrawPass::GlobalSurfaceAtlas)
return; // Not supported
auto drawState = renderContext.Buffers->GetGeometryDrawState(&GetScene()->Rendering, _sceneRenderingKey, this);
ACTOR_GET_WORLD_MATRIX(this, view, world);
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
GEOMETRY_DRAW_STATE_EVENT_BEGIN(drawState, world);
_lastMinDstSqr = Math::Min(_lastMinDstSqr, Vector3::DistanceSquared(_transform.Translation, renderContext.View.WorldPosition));
if (_bones.IsAllocated)
@@ -1281,7 +1284,7 @@ void AnimatedModel::Draw(RenderContext& renderContext)
}
}
draw.World = &world;
draw.DrawState = &_drawState;
draw.DrawState = drawState;
draw.Deformation = _deformation;
PRAGMA_DISABLE_DEPRECATION_WARNINGS
draw.DrawModes = DrawModes & renderContext.View.GetShadowsDrawPassMask(ShadowsMode);
@@ -1297,7 +1300,7 @@ void AnimatedModel::Draw(RenderContext& renderContext)
SkinnedModel->Draw(renderContext, draw);
}
GEOMETRY_DRAW_STATE_EVENT_END(_drawState, world);
GEOMETRY_DRAW_STATE_EVENT_END(drawState, world);
}
void AnimatedModel::Draw(RenderContextBatch& renderContextBatch)
@@ -1308,7 +1311,8 @@ void AnimatedModel::Draw(RenderContextBatch& renderContextBatch)
Matrix world;
const Float3 translation = _transform.Translation - renderContext.View.Origin;
Matrix::Transformation(_transform.Scale, _transform.Orientation, translation, world);
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
auto drawState = renderContext.Buffers->GetGeometryDrawState(&GetScene()->Rendering, _sceneRenderingKey, this);
GEOMETRY_DRAW_STATE_EVENT_BEGIN(drawState, world);
_lastMinDstSqr = Math::Min(_lastMinDstSqr, Vector3::DistanceSquared(_transform.Translation, renderContext.View.WorldPosition));
if (_bones.IsAllocated)
@@ -1332,7 +1336,7 @@ void AnimatedModel::Draw(RenderContextBatch& renderContextBatch)
}
}
draw.World = &world;
draw.DrawState = &_drawState;
draw.DrawState = drawState;
draw.Deformation = _deformation;
draw.DrawModes = DrawModes;
draw.Bounds = _sphere;
@@ -1361,7 +1365,7 @@ void AnimatedModel::Draw(RenderContextBatch& renderContextBatch)
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
GEOMETRY_DRAW_STATE_EVENT_END(_drawState, world);
GEOMETRY_DRAW_STATE_EVENT_END(drawState, world);
}
#if USE_EDITOR
@@ -5,7 +5,6 @@
#include "ModelInstanceActor.h"
#include "Engine/Content/Assets/SkinnedModel.h"
#include "Engine/Content/Assets/AnimationGraph.h"
#include "Engine/Renderer/DrawCall.h"
#include "Engine/Core/Delegate.h"
/// <summary>
@@ -96,7 +95,6 @@ private:
void Flush();
};
GeometryDrawStateData _drawState;
AnimationUpdateMode _actualMode;
SkinnedBones _bones;
uint32 _counter;
-2
View File
@@ -366,11 +366,9 @@ void Camera::Draw(RenderContext& renderContext)
renderContext.View.GetWorldMatrix(_transform, tmp);
Matrix::RotationY(PI * -0.5f, rot);
Matrix::Multiply(rot, tmp, world);
GeometryDrawStateData drawState;
Mesh::DrawInfo draw;
draw.Buffer = &_previewModelBuffer;
draw.World = &world;
draw.DrawState = &drawState;
draw.Flags = StaticFlags::Transform;
draw.DrawModes = (DrawPass::Depth | DrawPass::GBuffer | DrawPass::Forward) & renderContext.View.Pass;
BoundingSphere::FromBox(_previewModelBox, draw.Bounds);
+10 -6
View File
@@ -8,12 +8,14 @@
#include "Engine/Graphics/GPUBufferDescription.h"
#include "Engine/Graphics/GPUContext.h"
#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Graphics/RenderBuffers.h"
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/Models/MeshDeformation.h"
#include "Engine/Graphics/Shaders/GPUVertexLayout.h"
#include "Engine/Serialization/Serialization.h"
#include "Engine/Level/Prefabs/PrefabManager.h"
#include "Engine/Level/Scene/Scene.h"
#include "Engine/Renderer/DrawCall.h"
#include "Engine/Renderer/GlobalSignDistanceFieldPass.h"
#include "Engine/Renderer/GI/GlobalSurfaceAtlasPass.h"
#include "Engine/Utilities/Encryption.h"
@@ -380,15 +382,16 @@ void StaticModel::Draw(RenderContext& renderContext)
GlobalSurfaceAtlasPass::Instance()->RasterizeActor(this, this, _sphere, _transform, Model->LODs.Last().GetBox());
return;
}
auto drawState = renderContext.Buffers->GetGeometryDrawState(&GetScene()->Rendering, _sceneRenderingKey, this);
ACTOR_GET_WORLD_MATRIX(this, view, world);
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
GEOMETRY_DRAW_STATE_EVENT_BEGIN(drawState, world);
if (_vertexColorsDirty)
FlushVertexColors();
Mesh::DrawInfo draw;
draw.Buffer = &Entries;
draw.World = &world;
draw.DrawState = &_drawState;
draw.DrawState = drawState;
draw.Deformation = _deformation;
draw.Lightmap = _scene && Lightmap.TextureIndex != -1 ? _scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex) : nullptr;
draw.LightmapUVs = &Lightmap.UVsArea;
@@ -409,7 +412,7 @@ void StaticModel::Draw(RenderContext& renderContext)
Model->Draw(renderContext, draw);
GEOMETRY_DRAW_STATE_EVENT_END(_drawState, world);
GEOMETRY_DRAW_STATE_EVENT_END(drawState, world);
}
void StaticModel::Draw(RenderContextBatch& renderContextBatch)
@@ -417,15 +420,16 @@ void StaticModel::Draw(RenderContextBatch& renderContextBatch)
if (!Model || !Model->IsLoaded())
return;
const RenderContext& renderContext = renderContextBatch.GetMainContext();
auto drawState = renderContext.Buffers->GetGeometryDrawState(&GetScene()->Rendering, _sceneRenderingKey, this);
ACTOR_GET_WORLD_MATRIX(this, view, world);
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
GEOMETRY_DRAW_STATE_EVENT_BEGIN(drawState, world);
if (_vertexColorsDirty)
FlushVertexColors();
Mesh::DrawInfo draw;
draw.Buffer = &Entries;
draw.World = &world;
draw.DrawState = &_drawState;
draw.DrawState = drawState;
draw.Deformation = _deformation;
draw.Lightmap = _scene && Lightmap.TextureIndex != -1 ? _scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex) : nullptr;
draw.LightmapUVs = &Lightmap.UVsArea;
@@ -446,7 +450,7 @@ void StaticModel::Draw(RenderContextBatch& renderContextBatch)
Model->Draw(renderContextBatch, draw);
GEOMETRY_DRAW_STATE_EVENT_END(_drawState, world);
GEOMETRY_DRAW_STATE_EVENT_END(drawState, world);
}
bool StaticModel::IntersectsItself(const Ray& ray, Real& distance, Vector3& normal)
+1 -3
View File
@@ -4,7 +4,6 @@
#include "ModelInstanceActor.h"
#include "Engine/Content/Assets/Model.h"
#include "Engine/Renderer/DrawCall.h"
#include "Engine/Renderer/Lightmaps.h"
/// <summary>
@@ -15,15 +14,14 @@ class FLAXENGINE_API StaticModel : public ModelInstanceActor, IAssetReference
{
DECLARE_SCENE_OBJECT(StaticModel);
private:
GeometryDrawStateData _drawState;
float _scaleInLightmap;
float _boundsScale;
DrawPass _drawModes = DrawPass::Default;
char _lodBias;
char _forcedLod;
bool _vertexColorsDirty;
byte _vertexColorsCount;
int8 _sortOrder;
DrawPass _drawModes = DrawPass::Default;
Array<Color32> _vertexColorsData[MODEL_MAX_LODS];
GPUBuffer* _vertexColorsBuffer[MODEL_MAX_LODS];
Model* _residencyChangedModel = nullptr;
+8 -3
View File
@@ -1,11 +1,13 @@
// Copyright (c) Wojciech Figat. All rights reserved.
// Enable to put CPU profiler sections for each actor drawing to inspect slow actors draw issues
#define SCENE_RENDERING_USE_PROFILER_PER_ACTOR 0
#include "SceneRendering.h"
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/RenderView.h"
#include "Engine/Renderer/RenderList.h"
#include "Engine/Graphics/RenderBuffers.h"
#include "Engine/Threading/JobSystem.h"
#include "Engine/Physics/Actors/IPhysicsDebug.h"
#include "Engine/Profiler/ProfilerCPU.h"
@@ -38,6 +40,7 @@ void ISceneRenderingListener::ListenSceneRendering(SceneRendering* scene)
{
if (!_scenes.Contains(scene))
{
PROFILE_MEM(Graphics);
_scenes.Add(scene);
scene->_listeners.Add(this);
}
@@ -67,6 +70,8 @@ void SceneRendering::Draw(RenderContextBatch& renderContextBatch, DrawCategory c
// Register scene
for (const auto& renderContext : renderContextBatch.Contexts)
renderContext.List->Scenes.Add(this);
auto buffers = renderContextBatch.GetMainContext().Buffers;
buffers->OnSceneRendering(this);
}
else if (category == PostRender)
{
@@ -188,7 +193,7 @@ void SceneRendering::AddActor(Actor* a, int32& key)
e.Bounds = a->GetSphere();
e.NoCulling = a->_drawNoCulling;
for (auto* listener : _listeners)
listener->OnSceneRenderingAddActor(a);
listener->OnSceneRenderingAddActor(this, key, a);
}
void SceneRendering::UpdateActor(Actor* a, int32& key, ISceneRenderingListener::UpdateFlags flags)
@@ -204,7 +209,7 @@ void SceneRendering::UpdateActor(Actor* a, int32& key, ISceneRenderingListener::
if (e.Actor == a)
{
for (auto* listener : _listeners)
listener->OnSceneRenderingUpdateActor(a, e.Bounds, flags);
listener->OnSceneRenderingUpdateActor(this, key, a, e.Bounds, flags);
if (flags & ISceneRenderingListener::Layer)
e.LayerMask = a->GetLayerMask();
if (flags & ISceneRenderingListener::Bounds)
@@ -227,7 +232,7 @@ void SceneRendering::RemoveActor(Actor* a, int32& key)
if (e.Actor == a)
{
for (auto* listener : _listeners)
listener->OnSceneRenderingRemoveActor(a);
listener->OnSceneRenderingRemoveActor(this, key, a);
e.Actor = nullptr;
e.LayerMask = 0;
FreeActors[category].Add(key);
+10 -10
View File
@@ -51,22 +51,22 @@ public:
// Actor properties that were modified.
enum UpdateFlags
{
Visual = 1,
Bounds = 2,
Layer = 4,
StaticFlags = 8,
AutoDelayDuringRendering = 16, // Conditionally allow updating data during rendering when writes are locked
DrawModes = 32,
Auto = Visual | Bounds | Layer,
Visual = 1, // Visual appearance of the object (eg. material changed).
Bounds = 2, // Object bounding volume was changed (eg. after scaling).
Layer = 4, // Object changed layer.
StaticFlags = 8, // Object changed static state.
AutoDelayDuringRendering = 16, // Conditionally allow updating data during rendering when writes are locked.
DrawModes = 32, // Object changed draw modes flags.
Auto = Visual | Bounds | Layer, // Default set of flags for common changes.
};
// Starts listening to the scene rendering events.
void ListenSceneRendering(SceneRendering* scene);
// Events called by Scene Rendering
virtual void OnSceneRenderingAddActor(Actor* a) = 0;
virtual void OnSceneRenderingUpdateActor(Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags = Auto) = 0;
virtual void OnSceneRenderingRemoveActor(Actor* a) = 0;
virtual void OnSceneRenderingAddActor(SceneRendering* scene, int32 key, Actor* a) = 0;
virtual void OnSceneRenderingUpdateActor(SceneRendering* scene, int32 key, Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags = Auto) = 0;
virtual void OnSceneRenderingRemoveActor(SceneRendering* scene, int32 key, Actor* a) = 0;
virtual void OnSceneRenderingClear(SceneRendering* scene) = 0;
};
+7 -7
View File
@@ -322,7 +322,7 @@ struct TIsPODType<DrawCall>
/// Data container for meshes and skinned meshes rendering with minimal state caching.
/// Used to update previous world transformation matrix for motion vectors pass and handle LOD transitions blending.
/// </summary>
struct GeometryDrawStateData
struct GeometryDrawState
{
/// <summary>
/// The previous frame world transformation matrix for the given geometry instance.
@@ -347,23 +347,23 @@ struct GeometryDrawStateData
};
template<>
struct TIsPODType<GeometryDrawStateData>
struct TIsPODType<GeometryDrawState>
{
enum { Value = true };
};
#define GEOMETRY_DRAW_STATE_EVENT_BEGIN(drawState, worldMatrix) \
const auto frame = Engine::FrameCount; \
if (drawState.PrevFrame + 1 < frame && !renderContext.View.IsSingleFrame) \
if (drawState && drawState->PrevFrame + 1 < frame && !renderContext.View.IsSingleFrame) \
{ \
drawState.PrevWorld = worldMatrix; \
drawState->PrevWorld = worldMatrix; \
}
#define GEOMETRY_DRAW_STATE_EVENT_END(drawState, worldMatrix) \
if (drawState.PrevFrame != frame && !renderContext.View.IsSingleFrame) \
if (drawState && drawState->PrevFrame != frame && !renderContext.View.IsSingleFrame) \
{ \
drawState.PrevWorld = worldMatrix; \
drawState.PrevFrame = frame; \
drawState->PrevWorld = worldMatrix; \
drawState->PrevFrame = frame; \
}
#if USE_LARGE_WORLDS
@@ -716,11 +716,11 @@ public:
}
// [ISceneRenderingListener]
void OnSceneRenderingAddActor(Actor* a) override
void OnSceneRenderingAddActor(SceneRendering* scene, int32 key, Actor* a) override
{
}
void OnSceneRenderingUpdateActor(Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags) override
void OnSceneRenderingUpdateActor(SceneRendering* scene, int32 key, Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags) override
{
GlobalSurfaceAtlasObject* object = Objects.TryGet(a);
if (object)
@@ -744,7 +744,7 @@ public:
}
}
void OnSceneRenderingRemoveActor(Actor* a) override
void OnSceneRenderingRemoveActor(SceneRendering* scene, int32 key, Actor* a) override
{
// TODO: use it to speed up atlas/buffers defragmentation when streaming out scenes (CompactObjects cleans up objects)
}
@@ -475,17 +475,17 @@ public:
}
// [ISceneRenderingListener]
void OnSceneRenderingAddActor(Actor* a) override
void OnSceneRenderingAddActor(SceneRendering* scene, int32 key, Actor* a) override
{
OnSceneRenderingDirty(a);
}
void OnSceneRenderingUpdateActor(Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags) override
void OnSceneRenderingUpdateActor(SceneRendering* scene, int32 key, Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags) override
{
OnSceneRenderingDirty(a, &prevBounds, flags);
}
void OnSceneRenderingRemoveActor(Actor* a) override
void OnSceneRenderingRemoveActor(SceneRendering* scene, int32 key, Actor* a) override
{
OnSceneRenderingDirty(a);
}
+1 -1
View File
@@ -328,7 +328,7 @@ struct RenderListAlloc
};
/// <summary>
/// Rendering cache container object for the draw calls collecting, sorting and executing.
/// Rendering cache container object for the draw calls collecting, sorting and executing. Reusable between frames or drawing tasks.
/// </summary>
API_CLASS(Sealed) class FLAXENGINE_API RenderList : public ScriptingObject
{
+3 -3
View File
@@ -409,13 +409,13 @@ public:
}
// [ISceneRenderingListener]
void OnSceneRenderingAddActor(Actor* a) override
void OnSceneRenderingAddActor(SceneRendering* scene, int32 key, Actor* a) override
{
if (a->HasStaticFlag(StaticFlags::Shadow))
DirtyStaticBounds(a->GetSphere());
}
void OnSceneRenderingUpdateActor(Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags) override
void OnSceneRenderingUpdateActor(SceneRendering* scene, int32 key, Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags) override
{
// Dirty static objects to redraw when changed (eg. material modification)
if (a->HasStaticFlag(StaticFlags::Shadow))
@@ -438,7 +438,7 @@ public:
}
}
void OnSceneRenderingRemoveActor(Actor* a) override
void OnSceneRenderingRemoveActor(SceneRendering* scene, int32 key, Actor* a) override
{
if (a->HasStaticFlag(StaticFlags::Shadow))
DirtyStaticBounds(a->GetSphere());
@@ -5,6 +5,8 @@
#include "Engine/Core/Types/TimeSpan.h"
#include "Engine/Engine/Engine.h"
#include "Engine/Renderer/Renderer.h"
#include "Engine/Renderer/DrawCall.h"
#include "Engine/Renderer/Lightmaps.h"
#include "Engine/Level/Scene/Lightmap.h"
#include "Engine/Level/Actors/StaticModel.h"
#include "Engine/Level/Actors/BoxBrush.h"
+9 -6
View File
@@ -7,7 +7,9 @@
#include "Engine/Graphics/Models/Types.h"
#include "Engine/Graphics/RenderView.h"
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Level/Scene/SceneRendering.h"
#include "Engine/Graphics/RenderBuffers.h"
#include "Engine/Graphics/RenderTools.h"
#include "Engine/Graphics/Shaders/GPUVertexLayout.h"
#include "Engine/Render2D/Font.h"
#include "Engine/Render2D/FontAsset.h"
#include "Engine/Render2D/FontManager.h"
@@ -20,8 +22,8 @@
#include "Engine/Content/Content.h"
#include "Engine/Content/Deprecated.h"
#include "Engine/Core/Types/Variant.h"
#include "Engine/Graphics/RenderTools.h"
#include "Engine/Graphics/Shaders/GPUVertexLayout.h"
#include "Engine/Level/Scene/Scene.h"
#include "Engine/Level/Scene/SceneRendering.h"
#include "Engine/Localization/Localization.h"
#if USE_EDITOR
#include "Editor/Editor.h"
@@ -370,7 +372,8 @@ void TextRender::Draw(RenderContext& renderContext)
UpdateLayout();
Matrix world;
renderContext.View.GetWorldMatrix(_transform, world);
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
auto drawState = renderContext.Buffers->GetGeometryDrawState(&GetScene()->Rendering, _sceneRenderingKey, this);
GEOMETRY_DRAW_STATE_EVENT_BEGIN(drawState, world);
const DrawPass drawModes = DrawModes & renderContext.View.Pass & renderContext.View.GetShadowsDrawPassMask(ShadowsMode);
if (_vb.Data.Count() > 0 && drawModes != DrawPass::None)
@@ -389,7 +392,7 @@ void TextRender::Draw(RenderContext& renderContext)
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = (float)_sphere.Radius;
drawCall.Surface.GeometrySize = _localBox.GetSize();
drawCall.Surface.PrevWorld = _drawState.PrevWorld;
drawCall.Surface.PrevWorld = drawState ? drawState->PrevWorld : world;
drawCall.PerInstanceRandom = GetPerInstanceRandom();
drawCall.SetStencilValue(_layer);
drawCall.Geometry.IndexBuffer = _ib.GetBuffer();
@@ -409,7 +412,7 @@ void TextRender::Draw(RenderContext& renderContext)
}
}
GEOMETRY_DRAW_STATE_EVENT_END(_drawState, world);
GEOMETRY_DRAW_STATE_EVENT_END(drawState, world);
}
#if USE_EDITOR
-1
View File
@@ -42,7 +42,6 @@ private:
int32 _sceneRenderingKey = -1;
BoundingBox _localBox;
GeometryDrawStateData _drawState;
DynamicIndexBuffer _ib;
DynamicVertexBuffer _vb;
#if MODEL_USE_PRECISE_MESH_INTERSECTS