Files
Cortex_Engine/CORTEX_ENGINE_ARCHITECTURE.md
T

11 KiB
Raw Blame History

CORTEX ENGINE — Technical Architecture

Project: AI-Native 3D Game Engine Language: C# (.NET 9) Render Backend: Pure P/Invoke Vulkan 1.3 Last Updated: June 2026


1. Overview

Cortex Engine is a 3D game engine built from scratch with a pure P/Invoke Vulkan 1.3 render backend. No wrapper libraries — direct Vulkan API calls via vkGetInstanceProcAddr/vkGetDeviceProcAddr.

The engine allows an AI to:

  • See the engine state via rendered-frame screenshots and video recording
  • Read the complete ECS world state through native JSON serialization
  • Modify the running engine via declarative JSON commands through MCP (Model Context Protocol)

Key Technologies

  • Graphics: Vulkan 1.3 (dynamic rendering, synchronization2, imageCubeArray)
  • ECS: Flecs.NET 4.0.4
  • Windowing: SDL3 (ppy.SDL3-CS 2026.520.0)
  • Physics: JoltPhysicsSharp 2.21.0
  • UI: ImGui.NET 1.91.6.1
  • AI: MCP HTTP server (Kestrel + SSE), 7 tools

2. Project Structure

src/
├── Engine.Core/              # Core abstractions, windowing, ECS components
│   ├── IWindow.cs            # Backend-agnostic window interface
│   ├── IInputState.cs        # Input abstraction
│   ├── Sdl3Window.cs         # SDL3 window with Vulkan surface
│   ├── Key.cs                # Key enum
│   ├── InputMapping.cs       # Input state implementation
│   ├── Timing.cs             # Frame timing
│   ├── Vertex.cs             # Vertex struct (Position, Color, Normal)
│   ├── FreeFlyCameraController.cs
│   ├── OrbitCameraController.cs
│   └── Components/
│       ├── Transform.cs      # Position, Rotation, Scale
│       ├── Mesh.cs           # Vertex[], uint[] indices
│       ├── Material.cs       # Albedo, Roughness, Metallic, TexturePath
│       ├── Light.cs          # Point/Directional light
│       ├── Camera.cs         # Perspective camera
│       └── RigidBody.cs      # Physics body (box/sphere)
│
├── Engine.Graphics/         # Graphics HAL + utilities
│   ├── IRenderContext.cs     # Window, CreateRenderer, Resize
│   ├── IRenderer.cs         # RenderWorld, Screenshot, ImGui hooks
│   ├── IScreenshotProvider.cs
│   ├── RenderBackendFactory.cs  # Register/Create by name
│   ├── ObjLoader.cs          # OBJ file parser
│   ├── MeshMath.cs           # Face normal computation
│   ├── ProceduralMesh.cs     # Sphere, Grid generators
│   └── SceneSerializer.cs   # JSON scene save/load
│
├── Engine.Graphics.Vulkan/  # Pure P/Invoke Vulkan 1.3
│   ├── VulkanNative.cs       # Library loading, vkGetInstanceProcAddr
│   ├── VulkanHandles.cs      # Opaque pointer types
│   ├── VulkanEnums.cs        # All Vulkan enums/flags
│   ├── VulkanStructs.cs      # All Vulkan structs (verified sizes)
│   ├── Vk.cs                 # Function delegates + loaded pointers
│   ├── VulkanContext.cs      # Instance, device, queue, surface, debug
│   ├── VulkanSwapchain.cs    # Swapchain, image views, depth buffer
│   ├── VulkanPipeline.cs     # Graphics pipeline (PBR + dynamic rendering)
│   ├── VulkanShadowMap.cs    # Cubemap array shadows (4 lights × 6 faces)
│   ├── VulkanFrameResources.cs  # Command buffers, fences, semaphores, UBO
│   ├── VulkanVertexBuffer.cs # Staging → device-local vertex buffer
│   ├── VulkanIndexBuffer.cs  # Staging → device-local index buffer
│   ├── VulkanImGui.cs        # ImGui font atlas + pipeline + render
│   ├── VulkanRenderer.cs     # Main renderer: shadow passes + main pass
│   ├── VulkanRenderContext.cs
│   ├── VulkanBackendRegistrar.cs
│   └── Shaders/
│       ├── triangle.vert/frag  # PBR + multi-light + shadow sampling
│       ├── shadow.vert/frag    # Depth-only shadow pass
│       └── imgui.vert/frag     # ImGui rendering
│
├── Engine.Physics/          # Jolt physics wrapper
│   └── PhysicsWorld.cs      # Body creation, update, sync transforms
│
├── Engine.AI/               # AI command system + MCP server
│   ├── AiCommandProcessor.cs   # 7 commands (spawn, transform, material, etc.)
│   ├── AiCommandQueue.cs       # Thread-safe queue (MCP → main thread)
│   ├── Commands/               # Command DTOs
│   ├── Mcp/                    # HTTP MCP server (Kestrel + SSE)
│   └── Stdio/                  # Stdio MCP server
│
└── CortexEngine.App/        # Entry point
    └── Program.cs            # Main loop, scene, ImGui panels, video recording

3. Vulkan Backend

3.1 Initialization

  1. Load the platform Vulkan loader via NativeLibrary.Load() (vulkan-1.dll on Windows, libvulkan.so.1 on Linux)
  2. vkGetInstanceProcAddr — only directly-loaded function
  3. Create instance with SDL3 extensions + VK_EXT_debug_utils (if validation available)
  4. Pick physical device — prefer DiscreteGpu
  5. Create logical device with features:
    • VK_KHR_swapchain extension
    • VkPhysicalDeviceDynamicRenderingFeatures (dynamic rendering)
    • VkPhysicalDeviceSynchronization2Features (sync2)
    • VkPhysicalDeviceFeatures.imageCubeArray = VK_TRUE (cubemap array shadows)
  6. Create surface via SDL_Vulkan_CreateSurface()

3.2 Frame Loop

Each frame:
  1. WaitFrame (fence)
  2. Read captured frame buffer (if recording video)
  3. AcquireNextImageKHR
  4. Begin command buffer
  5. Shadow passes (numShadowLights × 6 faces):
     - Transition shadow cubemap array → ColorAttachment + DepthAttachment
     - For each shadow light, for each face:
       - Begin rendering (color R32_SFLOAT + depth D32_SFLOAT)
       - Bind shadow pipeline (depth-only, CULL_NONE, depth bias)
       - Push constants: model + lightViewProj + lightPos + shadowParams (160B)
       - Draw all shadow-casting objects
       - End rendering
     - Transition shadow cubemap array → ShaderReadOnlyOptimal
  6. Main pass:
     - Transition swapchain image → ColorAttachmentOptimal
     - Transition depth image → DepthStencilAttachmentOptimal
     - Begin rendering (color B8G8R8A8_UNORM + depth D32_SFLOAT)
     - Bind pipeline, descriptor sets (SceneUBO + shadowCubeArray)
     - For each object: push constants (model 64B), draw indexed
     - [If recording] End rendering, capture frame (vkCmdCopyImageToBuffer)
     - [If recording] Begin new rendering with loadOp=LOAD for ImGui
     - ImGui render
     - End rendering
     - Transition swapchain → PresentSrcKHR
  7. End command buffer
  8. QueueSubmit2 (sync2)
  9. QueuePresentKHR

3.3 SceneUBO Layout (464B)

Offset 0:    mat4 vp                    (64B)
Offset 64:   int numLights              (4B)
Offset 68:   int numShadowLights        (4B)
Offset 72:   vec2 padding               (8B)
Offset 80:   LightData lights[8]        (256B) — 2 × vec4 per light
Offset 336:  vec4 shadowParams[4]       (64B) — bias, sampleRadius, farPlane
Offset 400:  vec4 ambientColor          (16B)
Total: 416B → padded to 464B (align 64)

3.4 Push Constants

Main pipeline: mat4 model (64B), Vertex|Fragment Shadow pipeline: mat4 model + mat4 lightViewProj + vec4 lightPos + vec4 shadowParams (160B), Vertex|Fragment

3.5 Shadow Mapping

  • Cubemap array: 1 image, 24 layers (4 lights × 6 faces), CubeCompatible flag
  • Color attachment: R32_SFLOAT (stores linear distance / farPlane)
  • Depth attachment: D32_SFLOAT (depth test only)
  • Sampling: samplerCubeArray, texture(shadowArray, vec4(dir, lightIndex))
  • Filtering: 16-tap Poisson disk PCF, slope-dependent bias
  • Vulkan cubemap conventions: up=(0,-1,0) for X/Z faces, up=(0,0,1) for +Y, up=(0,0,-1) for -Y

3.6 PBR Shading

Cook-Torrance BRDF:

  • D: Trowbridge-Reitz GGX distribution
  • G: Smith geometry with Schlick-GGX
  • F: Schlick Fresnel approximation
  • Tonemapping: ACES filmic
  • Gamma: 2.2 correction
  • Multi-light loop in fragment shader

4. AI/MCP Integration

7 MCP Tools

Tool Description
spawn_model Create entity with mesh + optional physics + shape (cube/sphere)
set_transform Update position/rotation/scale by name
set_material Update albedo/roughness/metallic/texture
delete_entity Remove entity by name
list_entities List all named entities
get_world_state Full JSON state dump
capture_screenshot Request screenshot

Threading

  • MCP server runs on Task.Run (Kestrel thread pool)
  • Commands enqueued via AiCommandQueue (thread-safe ConcurrentQueue)
  • Main thread calls ProcessPending() before render each frame
  • CompletePendingScreenshots() after render

5. Physics

  • JoltPhysicsSharp 2.21.0
  • PhysicsWorld: gravity (0, -9.81, 0), 2 object layers (NonMoving, Moving)
  • RigidBody component: DynamicBox, DynamicSphere, StaticBox, StaticPlane
  • Lazy initialization: IsInitialized flag, bodies created on first frame
  • SyncTransforms: pulls Jolt positions/rotations back into ECS Transforms
  • Pause/Resume via physicsEnabled flag
  • Reset Scene: RemoveBody before Destruct to clean Jolt references

6. ImGui

  • Separate pipeline with alpha blending, no depth write
  • Font atlas uploaded to R32_SFLOAT VkImage via staging buffer
  • Mouse input from IInputState fed to ImGui.GetIO() each frame
  • Debug panel: FPS, camera, entity count, physics toggle, reset scene
  • Shadow & Light panel: per-light intensity/range/RGB, shadow bias/radius/farplane, ambient RGB
  • Video recording panel: Start/Stop buttons

7. Video Recording

  • vkCmdCopyImageToBuffer copies swapchain image to HOST_VISIBLE buffer
  • BGRA pixel data piped to FFmpeg via stdin
  • FFmpeg: rawvideo bgra → libx264 yuv420p, 60 FPS input, 30 FPS output
  • Capture before ImGui (video without UI)
  • Deferred read: buffer read at start of next frame (after fence wait)

8. Content

File Description
cube.obj Unit cube, CCW winding
sphere.obj UV sphere 24×16, CCW winding
torusknot.obj Torus knot (3,2), 4800 verts, smooth normals
torus.obj Donut, 24×16 segments, CCW winding
pyramid.obj 4-sided pyramid, CCW winding
diamond.obj Octahedron (8 faces), CCW winding
cone.obj 24-sector cone with bottom cap, CCW winding

9. Testing

227 xUnit tests:

  • VulkanStructSizeTests (47): C# struct sizes match C Vulkan headers
  • VulkanEnumValueTests (40+): sType, format, layout, topology, sync2 flags
  • VertexLayoutTests (5): Vertex struct size (36B), field offsets
  • ObjLoaderTests (8): OBJ parsing, face normals, winding
  • ObjLoaderFaceNormalTests (5): Face normal computation
  • ShadowMapTests (10): Face directions, FOV, up vectors, far plane
  • ShadowShaderTests (5): SPIR-V shader existence
  • CameraTests, TransformTests, TimingTests, CameraControllerTests, AiCommandProcessorTests, RenderBackendFactoryTests, MeshMathAndProceduralTests, SceneSerializerTests: Core functionality