Render extraction system & ECS/graphics refactor

Introduced RenderExtractionSystem for entity-based render data extraction. Added MeshInstance and MeshPalette components with shadow casting support. Refactored QueryBuilder API, SharedComponentStore, and component registration for clarity and flexibility. Updated SystemManager and SystemGroup to use SystemAPI. Replaced RenderingConfig with GraphicsEngineDesc/RenderSystemDesc. RenderFrame now uses CPU/GPU fence values for sync. Removed Camera.cs in favor of ECS-based rendering. Improved Material, RenderingLayerMask, Mesh, and RenderList APIs. Updated package references and fixed naming, error handling, and disposal issues.
This commit is contained in:
2026-03-08 22:51:03 +09:00
parent bfe8588d76
commit 619720feee
26 changed files with 493 additions and 269 deletions

View File

@@ -0,0 +1,9 @@
namespace Ghost.Engine;
public enum ShadowCastingMode
{
Off,
On,
TwoSided,
ShadowsOnly
}

View File

@@ -0,0 +1,47 @@
using Ghost.Core;
using Ghost.Entities;
using Ghost.Graphics.Core;
using Misaki.HighPerformance.LowLevel.Collections;
namespace Ghost.Engine.Components;
public struct MeshPalette : ISharedComponent, IEquatable<MeshPalette>
{
public UnsafeArray<Handle<Mesh>> meshes;
public UnsafeArray<Handle<Material>> materials;
public bool Equals(MeshPalette other)
{
throw new NotImplementedException();
}
public override int GetHashCode()
{
throw new NotImplementedException();
}
public override bool Equals(object? obj)
{
return obj is MeshPalette palette && Equals(palette);
}
public static bool operator ==(MeshPalette left, MeshPalette right)
{
return left.Equals(right);
}
public static bool operator !=(MeshPalette left, MeshPalette right)
{
return !(left == right);
}
}
public struct MeshInstance : IComponent
{
public int meshIndex;
public int materialIndex;
public ShadowCastingMode shadowCastingMode;
public RenderingLayerMask renderingLayerMask;
public byte subMeshIndex;
public bool staticShadowCaster;
}

View File

@@ -1,6 +1,5 @@
using Ghost.Entities;
using Ghost.Graphics;
using Ghost.Graphics.RHI;
using Misaki.HighPerformance.Jobs;
namespace Ghost.Engine;
@@ -30,7 +29,7 @@ internal sealed partial class EngineCore : IEngineContext
_jobScheduler = new JobScheduler(Environment.ProcessorCount - 2); // We -2 here, one for main thread, one for render thread
// TODO: Remove the windows dependency from RenderSystem.
var renderingConfig = new RenderingConfig
var renderingConfig = new RenderSystemDesc
{
FrameBufferCount = 2,
GraphicsAPI = GraphicsAPI.Direct3D12,
@@ -49,4 +48,4 @@ internal sealed partial class EngineCore : IEngineContext
{
_jobScheduler.Dispose();
}
}
}

View File

@@ -0,0 +1,62 @@
using Ghost.Core;
using Ghost.Engine.Components;
using Ghost.Entities;
using Ghost.Graphics.Core;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Utilities;
namespace Ghost.Engine.Systems;
public class RenderExtractionSystem : ISystem
{
private Identifier<EntityQuery> _queryID;
public void Initialize(ref readonly SystemAPI systemAPI)
{
_queryID = new QueryBuilder()
// TODO: We also need to filter by MeshPalette.
.WithAll<MeshInstance, LocalToWorld>()
.Build(systemAPI.World);
}
public void Update(ref readonly SystemAPI systemAPI)
{
if (_queryID.IsInvalid)
{
return;
}
ref var query = ref systemAPI.World.ComponentManager.GetEntityQueryReference(_queryID);
var renderList = new RenderList(1, 64, Allocator.Temp);
// TODO: We should extract the render record for each camera because different cameras may have different culling results.
foreach (var chunk in query.GetChunkIterator())
{
var meshInstances = chunk.GetComponentData<MeshInstance>();
var localToWorlds = chunk.GetComponentData<LocalToWorld>();
for (int i = 0; i < chunk.Count; i++)
{
ref readonly var meshInstance = ref meshInstances[i];
ref readonly var localToWorld = ref localToWorlds[i];
renderList.Add(new RenderRecord
{
localToWorld = localToWorld.matrix,
// TODO: Get mesh and material from palette. This requires some changes to ISharedComponent since it's now fully functional right now.
// mesh = meshInstance.meshIndex,
// material = meshInstance.materialIndex,
renderingLayerMask = meshInstance.renderingLayerMask,
subMeshIndex = meshInstance.subMeshIndex,
}, 0);
}
}
// TODO: Send render list to render pipeline.
}
public void Cleanup(ref readonly SystemAPI systemAPI)
{
}
}