Frame Rendering
renderFrame() Flow
Called once per frame from the C# game loop:
- Early out: Skip if no entities exist
- Rebuild geometry: If
buffersNeedRebuild_, callsrebuildGeometryBuffers()(staging → device-local) - Early out: Skip if vertex/index buffers are null
- Wait for fence:
vkWaitForFences(inFlightFences_[currentFrame_])— blocks until previous frame's GPU work completes - Acquire image:
vkAcquireNextImageKHR— gets next swapchain image index. IfOUT_OF_DATE, recreates swapchain and returns - Reset fence:
vkResetFences— unsignal the fence for this frame - Update UBO:
updateUniformBuffer(currentFrame_)— uploads view/proj matrices and light data - Build UI: If debug overlay enabled, calls
buildDebugOverlayGeometry() - Reset + record command buffer:
vkResetCommandBuffer→recordCommandBuffer - Submit:
vkQueueSubmitwith wait on imageAvailable, signal renderFinished, signal fence - Present:
vkQueuePresentKHR— ifOUT_OF_DATEorSUBOPTIMALorframebufferResized_, recreates swapchain - Advance frame:
currentFrame_ = (currentFrame_ + 1) % 2
recordCommandBuffer()
The command buffer records a single render pass:
updateUniformBuffer()
Uploads per-frame data to persistently-mapped UBOs:
Near plane = 0.1, far plane = 100.0.
Entity Management
createEntity(meshId)
- Validates mesh ID
- Creates
EntityDatawith identity transform,active = true - Reuses a free slot from
freeEntitySlots_if available, otherwise appends - Returns entity ID
setEntityTransform(entityId, float* mat4x4)
Directly memcpys 16 floats into the entity's transform matrix. Silently ignores invalid/inactive entity IDs.
removeEntity(entityId)
Sets active = false and pushes the ID onto freeEntitySlots_ for reuse. Does not compact the entity array.
getActiveEntityCount()
Iterates all entities and counts active ones. Used by the debug overlay.
Debug Wireframe Entities
Debug entities are stored in a separate debugEntities_ vector (with its own freeDebugEntitySlots_ free list) and are only rendered when debugOverlayEnabled_ is true. They use the debugPipeline_ — a wireframe variant of the 3D pipeline.
createDebugEntity(meshId) / removeDebugEntity(entityId)
Same slot-reuse pattern as regular entities. Creates/removes entries in debugEntities_.
setDebugEntityTransform(entityId, float* mat4x4)
Same memcpy pattern as regular entities.
clearDebugEntities()
Clears both debugEntities_ and freeDebugEntitySlots_. Called when the debug overlay is toggled off.
Camera
setCamera(eyeX, eyeY, eyeZ, targetX, targetY, targetZ, upX, upY, upZ, fovDegrees) stores camera parameters. The actual view matrix is constructed in updateUniformBuffer() via glm::lookAt().
Adding post-processing: After vkCmdEndRenderPass, you could begin a second render pass targeting a different framebuffer. Alternatively, render the scene to an offscreen image and blit/compose in a second pass.
Changing clear color: Modify the clearValues[0].color in recordCommandBuffer() — currently {0.1, 0.1, 0.12, 1.0} (dark gray-blue).
Modifying draw order: Entities are drawn in array order. For transparency, you would need to sort entities by depth. For front-to-back (early-Z optimization), sort by distance from camera.