Commit Graph
126 Commits
Author SHA1 Message Date
emil28092005 cd8c6de191 feat: new default scene — chaos architecture
- 28 sphere pyramid (7 layers, physics, DynamicSphere colliders)
- 30 falling diamonds (octahedrons, physics, DynamicBox)
- 8 floating torus rings (decorative, rotated to face center)
- 4 pyramid decorations (static, at corners)
- 4 cone pillars (static, at diagonals, taller scale)
- Central floating torus knot (no physics)
- Dynamic point light moving in chaotic circle
- Floor + grid
- Camera at (0, 5, -15)
- All with PBR + cubemap shadows + soft PCF
2026-06-18 22:37:16 +03:00
emil28092005 55c3a16e61 feat: new OBJ files + chaos architecture scene via MCP
New OBJ files:
- pyramid.obj: 4-sided pyramid with CCW winding
- diamond.obj: octahedron (8 faces, CCW)
- torus.obj: donut shape (24x16 segments)
- cone.obj: 24-sector cone with bottom cap

Scene created via MCP (spawn_model with physics):
- 28 sphere pyramid (7 layers, physics)
- 30 falling diamonds (physics)
- 8 floating torus rings (no physics, decorative)
- 4 pyramid decorations (static)
- 4 cone pillars (static)
2026-06-18 22:35:10 +03:00
emil28092005 4eb0584f6d fix: sphere collider matches visual size — create at radius 0.5
Root cause: CreateSphere(r) baked scale into mesh radius, then Transform
applied scale again → double scaling. Visual radius was scale*0.5*scale
but collider was scale*0.5.

Fix: always create sphere at radius 0.5 (unit sphere, like cube.obj).
Scale is applied through Transform only. Collider radius = maxScale*0.5
matches visual radius = 0.5 * scale.
2026-06-18 22:28:33 +03:00
emil28092005 243e430eab fix: auto-detect sphere from model path — correct sphere colliders
- AiCommandProcessor: checks if modelPath contains 'sphere' (case-insensitive)
- If detected as sphere: uses DynamicSphere physics body (was DynamicBox)
- Works with both shape='sphere' parameter and modelPath='Content/sphere.obj'
- No need to explicitly pass shape parameter when loading sphere.obj
2026-06-18 22:25:11 +03:00
emil28092005 0119cd765b feat: add sphere.obj — 24x16 UV sphere with CCW winding
- 425 vertices, 720 triangles
- Radius 0.5, CCW winding from outside
- Can be loaded via spawn_model with modelPath='Content/sphere.obj'
2026-06-18 22:21:50 +03:00
emil28092005 24eb547711 feat: spawn spheres via MCP — shape parameter cube/sphere
- SpawnModelCommand: added Shape property (default 'cube')
- AiCommandProcessor: if shape='sphere', uses ProceduralMesh.CreateSphere
  instead of loading OBJ file; physics uses DynamicSphere instead of DynamicBox
- EngineMcpTools: added 'shape' parameter to SpawnModel tool
- Engine.AI now references Engine.Graphics for ProceduralMesh access
2026-06-18 22:19:42 +03:00
emil28092005 a90195c600 feat: optional physics in spawn_model MCP command
- SpawnModelCommand: added Physics bool property (default false)
- AiCommandProcessor.SpawnModel: when Physics=true, adds RigidBody.DynamicBox
  with half-extent = max(scale) * 0.5, mass = max(scale) * 2
- EngineMcpTools.SpawnModel: added 'physics' parameter (default false)
- Physics is optional — spawn without physics by default, enable when needed
- Physics bodies are initialized by the existing per-frame IsInitialized check
2026-06-18 22:16:13 +03:00
emil28092005 f8504cd44c fix: MCP server on Task.Run + start after 10th frame
- Changed from Thread to Task.Run for MCP server
- Start delay: 10 frames (was 3) — let scene fully initialize first
- Kestrel on ThreadPool instead of dedicated thread
2026-06-18 22:11:24 +03:00
emil28092005 5312625920 feat: 50 physics balls in scene — stress test for shadows + physics 2026-06-18 22:07:51 +03:00
emil28092005 eb2cfec41f fix: reduce shadow bias to 0.0001 — near zero with back-face culling 2026-06-18 22:03:02 +03:00
emil28092005 576d4586a3 fix: reduce default shadow bias to 0.01 — minimal acne with back-face culling
Back-face culling eliminated most self-shadowing, so bias can be much
lower. Default 0.01 (was 0.08). Slider still allows 0.001-0.5 tuning.
2026-06-18 22:01:43 +03:00
emil28092005 ed919edb0a fix: enable back-face culling — removes self-shadowing artifacts
Root cause: CULL_MODE_NONE in both main and shadow pipelines caused
back faces to render, creating self-shadowing acne on all objects:
- Shadow map: back faces written at closer depth → false shadows on front
- Main render: back faces visible through objects → wrong lighting

Fix:
- Main pipeline: CULL_MODE_BACK (was None) — only front faces render
- Shadow pipeline: CULL_MODE_BACK (was None) — only front faces cast shadows
- Removed normal flip hack (if dot(N,V) < 0 N = -N) — no longer needed
  with proper culling + correct CCW winding in cube.obj
- This is the standard approach: correct geometry + back-face culling
2026-06-18 22:00:03 +03:00
emil28092005 d2078f3ee0 fix: cube.obj winding order — all faces now CCW from outside
Root cause: ALL 12 faces in cube.obj had reversed winding order.
This caused every face normal to point inward, breaking:
- Diffuse lighting (NdotL < 0 → no light on any face)
- Shadow bias (slope-dependent bias used wrong NdotL)
- Shadow self-shadowing (both sides rendered with CULL_NONE)

Fix: reversed all face indices to correct CCW winding:
- Back face: f 1 4 3, f 1 3 2 (was f 1 2 3, f 1 3 4)
- Front face: f 5 6 7, f 5 7 8 (was f 5 7 6, f 5 8 7)
- Left/Right/Bottom/Top: all reversed

Now MeshMath.ComputeFaceNormal produces correct outward normals.
Normal flip in shader (dot(N,V) < 0) is still kept as safety for
double-sided rendering, but cubes now have correct normals natively.
2026-06-18 21:57:32 +03:00
emil28092005 6a473bdc53 fix: flip normal only by view direction — fixes both cubes and spheres
Previous fix flipped normal by both light AND view direction:
  if (dot(N,L) < 0) N = -N;
  if (dot(N,V) < 0) N = -N;
This double-flip broke spheres: when light is behind sphere, front faces
get N flipped by light (now facing away from camera), then flipped back
by view — but back faces get flipped once, causing inconsistency.

Correct approach: flip ONLY by view direction:
  if (dot(N, V) < 0.0) N = -N;
This ensures the normal always faces the camera. Faces pointing away
from light naturally get NdotL=0 (no lighting) — correct behavior.
Spheres keep smooth normals, cubes get inward normals fixed.
2026-06-18 21:56:10 +03:00
emil28092005 2f7430e3b1 fix: flip normals when facing away from light/view — fixes cube lighting
Root cause: cube.obj has inconsistent winding order. Many faces have
normals pointing inward (e.g. back face normal = +Z instead of -Z).
With cullMode=None, both sides render, but inward normals cause:
- No diffuse lighting (NdotL < 0 → max() = 0)
- Wrong shadow bias (slope-dependent bias uses wrong NdotL)
- Inconsistent shadow edges on cube faces

Fix: in fragment shader, flip normal if dot(N,L) < 0 or dot(N,V) < 0
This is the standard approach for double-sided rendering with
non-watertight geometry or inconsistent winding order.
2026-06-18 21:53:15 +03:00
emil28092005 203c22fa98 fix: feed mouse input to ImGui — sliders and buttons now clickable
- ImGui.GetIO().MousePos set from IInputState.MouseX/MouseY each frame
- ImGui.GetIO().MouseDown[0-2] set from MouseLeft/Right/Middle
- DisplaySize also updated each frame (was only set at init)
- Done before BeginImGuiFrame() / ImGui.NewFrame()
2026-06-18 21:50:08 +03:00
emil28092005 29a58d204b feat: ImGui shadow parameters panel with clipboard copy
- Push constant block expanded: 160B → 176B (added vec4 shadowParams)
- shadowParams: x=bias, y=sampleRadius, z=farPlane, w=unused
- Fragment shader: bias and sampleRadius now read from push constants
  (dynamic, adjustable at runtime)
- Shadow.frag: uses pc.shadowParams.z for farPlane (dynamic)
- Slope-dependent bias: bias + bias*2*(1-NdotL) — adaptive
- VulkanRenderer: public ShadowBias, ShadowSampleRadius, ShadowFarPlane properties
- Program.cs: ImGui 'Shadow Parameters' panel with sliders:
  - Light Intensity (0-100), Range (5-100), RGB color
  - Shadow Bias (0.001-0.5), Sample Radius (0.001-0.1), Far Plane (10-120)
  - 'Copy Parameters to Clipboard' button — outputs all values as text
- 227 tests, all pass
2026-06-18 21:48:38 +03:00
emil28092005 8918126c58 fix: increase shadow cubemap resolution to 2048 — sharper edges
- ShadowMapSize: 1024 → 2048 (per face, 6 faces)
- 4x more texels per face — less aliasing on cube edges
- Memory: 6 * 2048² * 4B (R32) + 6 * 2048² * 4B (D32) = ~192MB
2026-06-18 21:42:23 +03:00
emil28092005 2454af1c89 fix: balanced shadow bias — no acne, no peter-panning
- Fragment bias: 0.08 + 0.15 * (1 - NdotL) — smaller base, moderate slope
  (was 0.3 + 0.5 — too much → peter-panning, shadows detached from objects)
- vkCmdSetDepthBias: 1.75/0/2.5 (was 2.5/0/3.5 — too aggressive)
- Removed early exit logic — was causing hard shadow edges
- Always run 16-tap PCF for consistent soft shadow quality
- Smaller sample radius: clamp(0.015 * dist/20, 0.003, 0.05)
2026-06-18 21:40:43 +03:00
emil28092005 23b38f8f17 fix: increase shadow bias — slope-dependent + larger depth bias
- Fragment shader: bias = 0.3 + 0.5 * (1 - NdotL) — slope-dependent
  Grazing angles get larger bias to prevent acne on cube faces
- vkCmdSetDepthBias: 2.5/0/3.5 (was 1.25/0/1.75) — more aggressive
  polygon offset for shadow map rendering
- Early exit tolerance reduced from 4x to 3x bias
2026-06-18 21:38:48 +03:00
emil28092005 7e33b64ac9 feat: soft shadows — 16-tap Poisson disk PCF on cubemap
- 16 precomputed Poisson disk offsets on tangent plane
- Tangent basis built from sampling direction (cross product trick)
- Sample radius scales with distance: closer = sharper, farther = softer
  radius = clamp(0.02 * (dist / 20), 0.005, 0.08)
- Early exit: skip PCF if clearly lit or clearly shadowed (performance)
- Bias increased to 0.15 for cubemap distance comparison
- Only triangle.frag changed — no C# or Vulkan resource changes
- 227 tests, all pass
2026-06-18 21:36:30 +03:00
emil28092005 f761973443 fix: Vulkan cubemap face directions — Y-up vectors corrected
Root cause: used OpenGL cubemap conventions (up=+Y) instead of Vulkan (up=-Y)
for X and Z faces. Also applied M22 *= -1 flip to shadow projection which
is wrong — that flip is only for swapchain rendering, not for offscreen
cubemap rendering.

Fix:
- Faces 0,1,4,5 (+X,-X,+Z,-Z): up = (0,-1,0) — Vulkan cubemap convention
- Face 2 (+Y): up = (0,0,1) — was (0,0,-1), now correct
- Face 3 (-Y): up = (0,0,-1) — was (0,0,1), now correct
- Removed M22 *= -1 from shadow projection (not needed for offscreen cube)
- 227 tests, all pass
2026-06-18 21:32:18 +03:00
emil28092005 a2000b55b5 feat: cubemap shadows with R32_SFLOAT color attachment — linear distance
Root cause of broken shadows: depth buffer stores non-linear NDC depth,
not linear distance. closestDepth * 60.0 was wrong conversion.

Fix: switch from depth-only to R32_SFLOAT color attachment approach:
- Shadow vertex shader outputs world position to fragment
- Shadow fragment shader writes length(fragPos - lightPos) / farPlane
- Main fragment shader samples cubemap, multiplies by FAR_PLANE=60
- Separate color cube (R32_SFLOAT, sampled) + depth cube (D32_SFLOAT, depth test)
- Shadow pipeline: 1 color attachment (R) + depth attachment
- Color clear = 1.0 (max distance), depth clear = 1.0

Tests: 227 total, all pass
- ShadowMapFaceDirectionTests: 6 face directions, 90° FOV, up vectors,
  valid matrices, far plane consistency
- ShadowShaderTests: all 6 SPIR-V shaders exist
2026-06-18 21:27:48 +03:00
emil28092005 a572f9d360 fix: transition all 6 cubemap layers — shadows now work on floor
Root cause: TransitionImageLayoutDepth used LayerCount=1, so only
layer 0 of the 6-layer cubemap was transitioned to ShaderReadOnlyOptimal.
Layers 1-5 stayed in Undefined/DepthStencilAttachmentOptimal → sampling
returned garbage → no shadows on surfaces facing those directions.

Fix: added layerCount parameter to TransitionImageLayoutDepth (default=1).
Shadow cubemap transitions use layerCount=6.
2026-06-18 21:15:50 +03:00
emil28092005 fa937ecd94 feat: cubemap shadow mapping — true omnidirectional point light shadows
- VulkanShadowMap: 1024x1024x6 layer D32_SFLOAT cube image
  - CubeCompatible flag, cube view for sampling, 6 face views for rendering
  - GetFaceViewProj: 6 directions (+X, -X, +Y, -Y, +Z, -Z) with correct up vectors
- 6 shadow render passes per frame (one per cube face)
- Fragment shader: samplerCube instead of sampler2D
  - Shadow: direction from light to fragment, distance comparison
  - No more perspective frustum limitation — omnidirectional shadows
- shadow.vert: same push constant block (160B), uses lightViewProj per face
- triangle.vert: removed fragLightSpacePos (not needed for cubemap)
- Reduced shadow map size to 1024 (6x memory vs single 2048)
- Floor/Grid excluded from shadow casting
2026-06-18 20:35:01 +03:00
emil28092005 c32c75cd69 fix: single push constant range (0-160, Vertex|Fragment) — fixes validation errors
- Vulkan spec: each stage can only appear in ONE push constant range
- Merged 3 ranges into 1: offset=0, size=160, stageFlags=Vertex|Fragment
- Both main and shadow pipelines use same single range
- Push constants packed into 160-byte buffer and sent in one call
- Shadow pass: restored vertex/index buffer binding + push constants
- Fixes: device lost, validation errors, missing shadow geometry
2026-06-18 20:21:54 +03:00
emil28092005 dd86f6e9ad fix: exclude Floor and Grid from shadow pass — no more blocked light
- drawCalls now include castShadow flag (bool)
- Floor and Grid entities: castShadow=false (skip in shadow pass)
- Shadow pass: foreach with 'if (!dc.castShadow) continue;'
- Main pass: renders all objects (floor receives shadows but doesn't cast)
2026-06-18 20:19:16 +03:00
emil28092005 df4b30ecc3 feat: light moves in chaotic circle — dynamic shadows
- Light position animated with sin/cos combinations at different frequencies
- XZ plane: figure-8 pattern (sin*0.7 + cos*0.3, cos*0.6 + sin*0.4)
- Y: oscillates 7-17 with sin*0.5
- Shadows move dynamically as light orbits the scene
2026-06-18 20:15:36 +03:00
emil28092005 d4eafe1f31 fix: reduce light intensity from 50 to 15 2026-06-18 20:13:46 +03:00
emil28092005 7c33a52ff7 feat: static light at top (y=20) instead of physics ball
- Light moved to (0, 20, 0) — static, no physics body
- Intensity 50, range 60, warm white color
- Shadow map renders from this fixed position
- LightBall removed, replaced with MainLight entity
2026-06-18 20:12:59 +03:00
emil28092005 e6e305dfa9 feat: shadow mapping — depth-only render pass from light POV + PCF
- VulkanShadowMap.cs: 2048x2048 D32_SFLOAT image, sampler (clamp-to-border),
  separate shadow pipeline (depth-only, no color, depth bias enabled, CULL_NONE)
- Shadow shaders: shadow.vert (lightViewProj * model * pos), shadow.frag (empty)
- Main shaders updated: fragLightSpacePos output from vertex, PCF 3x3 in fragment
- Push constants expanded to 160B: model(64) + lightPos(16) + lightColor(16) + lightViewProj(64)
- 3 push constant ranges: Vertex(model), Fragment(light), Vertex|Fragment(lightViewProj)
- Descriptor set: 2 bindings — UBO(vp) + CombinedImageSampler(shadowMap)
- Shadow pass: before main pass, renders scene depth from light position
- Image transitions: shadow map UNDEFINED→DEPTH→SHADER_READ_ONLY each frame
- vkCmdSetDepthBias(1.25, 0, 1.75) for acne prevention
- Light VP: CreateLookAt(lightPos, origin, up) * Perspective(60°, 1.0, 0.1, 60)
- 0 validation errors on build
2026-06-18 20:09:32 +03:00
emil28092005 1dde764342 fix: move light data from UBO to push constants — fixes std140 layout issue
Root cause: GLSL std140 layout adds padding after mat4 for vec4 fields,
causing light data to be read at wrong offsets → NaN/artifacts.

Fix:
- UBO back to 64 bytes (mat4 vp only)
- Light data (pos + color, 32 bytes) sent via push constants at offset 64
- Two push constant ranges: Vertex (0-64, model) + Fragment (64-96, light)
- Both vertex and fragment shaders read from same push_constant block
- PBR shader fully restored with Cook-Torrance BRDF
- Dynamic point light follows physics ball
2026-06-18 19:53:45 +03:00
emil28092005 ad8a14a4f7 debug: hardcoded light in fragment shader — no UBO light data
Light at (0,10,0) hardcoded in GLSL. Tests if lighting math works.
If light works: problem is UBO layout for light data (std140 padding).
If artifacts: problem is in fragWorldPos or fragNormal.
2026-06-18 19:50:20 +03:00
emil28092005 7ed81040ed debug: simple diffuse point light — test if light data reaches fragment 2026-06-18 19:47:29 +03:00
emil28092005 b162d681aa debug: albedo-only fragment shader — tests if vp matrix works with 128B UBO
If objects are colored: vp matrix is fine, problem is in lighting
If objects are black: vp matrix is broken by 128B UBO change
2026-06-18 19:46:05 +03:00
emil28092005 4771371021 fix: restore MemoryCopy for UBO + PBR shader with point light
- UBO packing: MemoryCopy for vp (64B) + lightPos (16B) + lightColor (16B)
- PBR fragment shader with Cook-Torrance BRDF + point light
- No directional light, near-zero ambient — only point light illuminates
- Guards against div-by-zero in attenuation and specular
- Depth buffer properly configured in pipeline + rendering info
2026-06-18 19:43:31 +03:00
emil28092005 e37e7a4eed debug: fragment shader outputs light position as color — test UBO
- If objects are colored (not black/artifacts), UBO data reaches fragment shader
- Also: manual float-by-float UBO packing instead of MemoryCopy
- vp matrix packed as M11..M44 (row-major, no row_major in GLSL = transpose)
2026-06-18 19:36:57 +03:00
emil28092005 ff8bec00f6 fix: use MemoryCopy instead of Marshal.StructureToPtr for UBO packing
- Marshal.StructureToPtr may not handle Matrix4x4 correctly (record struct)
- Replaced with MemoryCopy from local copies of vp, lightPos, lightColor
- Removed per-frame light debug logging
- Simple diffuse shader still active for testing
2026-06-18 19:35:44 +03:00
emil28092005 321b1f62cc debug: simple diffuse fragment shader to test point light UBO 2026-06-18 19:33:37 +03:00
emil28092005 aa214cb777 fix: UBO descriptor visible to fragment shader — point light now works
Root cause: descriptor set layout binding had stageFlags=Vertex only.
Fragment shader needs pointLightPos/pointLightColor from UBO but couldn't
access it. Changed to Vertex|Fragment.
2026-06-18 19:29:57 +03:00
emil28092005 905dd839c8 fix: remove static MainLight, increase LightBall intensity to 30, range 40
- Only one light source: the physics LightBall
- Intensity 30 (was 20), range 40 (was 30) for stronger illumination
- Static MainLight removed so renderer picks the dynamic ball
2026-06-18 19:28:17 +03:00
emil28092005 6a7d6ee3eb feat: single point light only — dark scene, dynamic light ball visible
- Removed directional light from fragment shader
- Ambient reduced to near-zero (0.01) — scene is dark
- Only light source is the physics LightBall falling from y=15
- Objects near the ball are illuminated, far objects are in darkness
- Dramatic contrast shows dynamic lighting clearly
2026-06-18 19:27:05 +03:00
emil28092005 e6cc9e6c4e feat: dynamic point light on a physics ball — falls and illuminates
- LightBall entity: sphere mesh + DynamicSphere physics + Light.Point
- Renderer reads light position from Transform (not static Light.Position)
  so the light moves with the physics body
- Light intensity 20, range 30, warm color (1.0, 0.9, 0.7)
- Ball falls from y=15, bounces on floor, light follows it
- Renderer: prefers Light+Transform pair for dynamic position, falls back to Light only
2026-06-18 19:25:02 +03:00
emil28092005 f718e6de49 feat: PBR point light — Unity-style attenuation, warm glow
- UBO expanded from 64 to 128 bytes: vp(64) + lightPos(16) + lightColor(16)
- Vertex shader: passes point light UBO data through
- Fragment shader: refactored calcLight() function, shared by directional + point
  - Point light: Unity-style attenuation pow(1 - dist/range, 2)
  - Directional light reduced intensity (0.4) to balance with point light
  - Point light: position (0,8,0), warm color (1,0.9,0.7), intensity 15, range 25
- Renderer: reads Light component from ECS, packs into UBO with Marshal.StructureToPtr
- Scene: MainLight entity with Light.Point at (0,8,0)
- 0 C# struct changes — pure UBO layout + shader upgrade
2026-06-18 19:23:00 +03:00
emil28092005 22748ed9ba feat: PBR shading — Cook-Torrance BRDF with ACES tonemapping
- Vertex shader: passes world position, world normal, albedo to fragment
- Fragment shader: full PBR implementation
  - D term: Trowbridge-Reitz GGX distribution
  - G term: Smith geometry with Schlick-GGX
  - F term: Schlick Fresnel approximation
  - kD/kS split based on metallic
  - Directional light (0.5, 0.8, 0.3) with warm color
  - Ambient term (0.15, 0.18, 0.22) for fill light
  - ACES filmic tonemapping
  - Gamma 2.2 correction
- Fixed roughness=0.5, metallic=0.1 (per-object materials = future)
- No C# code changes — pure shader upgrade
2026-06-18 19:18:01 +03:00
emil28092005 50e77e705b fix: MCP server starts after 3rd frame to avoid blocking Vulkan init
- MCP server (Kestrel) launched on background thread after 3 frames
  to avoid conflicting with Vulkan/SDL3 initialization
- --mcp-port 0 (default) = disabled, scene works as before
- --mcp-port 5000 = MCP starts after 3rd frame
- Reduced extra balls from 30 to 10 for stability
- Engine.AI/McpEngineServerHost reverted to original (no WebApplicationOptions)
2026-06-18 19:12:11 +03:00
emil28092005 1f7538383e feat: integrate AI/MCP — 7 tools available via --mcp-port flag
- Engine.AI referenced in CortexEngine.App.csproj
- AiCommandProcessor created with world + mesh loader + screenshot callback
- AiCommandQueue marshals commands from MCP thread to main thread
- MCP HTTP server (Kestrel) started on separate background thread
- --mcp-port N flag (default 0 = disabled) controls MCP server
- queue.ProcessPending() called before render each frame
- queue.CompletePendingScreenshots() called after render
- ImGui overlay shows MCP status (port or disabled)
- DummyScreenshotProvider placeholder (real capture = future checkpoint)
- 7 MCP tools: spawn_model, set_transform, set_material, delete_entity,
  list_entities, get_world_state, capture_screenshot
- MCP server has 2s startup delay to avoid blocking Vulkan init
- Default: MCP disabled (--mcp-port 0), scene + physics + ImGui work
2026-06-18 18:56:53 +03:00
emil28092005 bfde04b381 feat: ImGui debug overlay — FPS, camera position, entity count
- ImGui.NET 1.91.6.1 integrated into Engine.Graphics.Vulkan
- VulkanImGui.cs: font atlas upload (staging → VkImage), sampler,
  descriptor set (COMBINED_IMAGE_SAMPLER), separate pipeline with
  alpha blending, no depth write, dynamic scissor
- ImGui shaders: imgui.vert (ortho MVP push constant) + imgui.frag
  (font texture sampler)
- Dynamic vertex/index buffers (HOST_VISIBLE, grow on demand)
- IRenderer interface: BeginImGuiFrame/EndImGuiFrame default methods
- Program.cs: debug window with FPS, camera pos/target, entity count
- 0 critical validation errors, ~750 FPS with physics + ImGui
2026-06-18 17:34:42 +03:00
emil28092005 e67e312d28 feat: Jolt physics — cubes and spheres fall with gravity, hit floor
- Engine.Physics (JoltPhysicsSharp) integrated into CortexEngine.App
- 4 cubes: DynamicBox, mass proportional to scale, fall from height 5-10
- 3 spheres: DynamicSphere, mass 1.5, fall from height 7-12
- Floor: StaticBox (20x0.5x20), friction 0.8
- Torus knot + grid: no physics (visual only)
- Physics bodies initialized lazily on first frame (IsInitialized flag)
- e.Set() moved outside world.Each to avoid mutation during iteration
- physicsWorld.Update + SyncTransforms every frame
- Removed manual rotation — physics handles movement now
- Camera at (0, 5, -15) for better view of falling objects
- 0 validation errors, ~1300 FPS
2026-06-18 17:18:59 +03:00
emil28092005 609b11e3a3 feat: full engine scene — torus knot + 4 cubes + 3 spheres + floor + grid
- 10 entities in ECS World with Transform + Mesh components
- Torus knot (center, scale 1.5) rotating around Y
- 4 cubes (left/right/front/back) rotating at different speeds
- 3 spheres (procedural, 32x16) rotating around X
- Floor (20x20 flat cube) + grid (ProceduralMesh.CreateGrid)
- Camera at (0, 3, -12) looking at (0, 0.5, 0)
- Mesh cache: buffers created lazily per entity ID on first frame
- Diffuse lighting on all objects
- 0 validation errors, ~2300 FPS
2026-06-18 17:10:35 +03:00