Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ add_library(render_renderer STATIC
engine/render/lighting.hpp
engine/render/lighting.cpp
engine/render/texture_types.hpp
engine/render/vfx.hpp
engine/render/vfx.cpp
engine/render/bgfx/renderer_bgfx.cpp
)
add_library(render::renderer ALIAS render_renderer)
Expand Down Expand Up @@ -231,6 +233,11 @@ if(RENDER_BUILD_TESTS)
render_apply_project_options(render_scene_tests)
render_apply_warnings(render_scene_tests)

add_executable(render_vfx_system_tests tests/render/vfx_system_tests.cpp)
target_link_libraries(render_vfx_system_tests PRIVATE render::renderer)
render_apply_project_options(render_vfx_system_tests)
render_apply_warnings(render_vfx_system_tests)

add_test(NAME unit.platform.types COMMAND render_platform_types_tests)
set_tests_properties(unit.platform.types PROPERTIES LABELS "unit;platform")
add_test(NAME unit.core.runtime COMMAND render_core_runtime_tests)
Expand All @@ -251,12 +258,14 @@ if(RENDER_BUILD_TESTS)
set_tests_properties(unit.renderer.debug_views PROPERTIES LABELS "unit;renderer;debug")
add_test(NAME unit.scene.runtime COMMAND render_scene_tests)
set_tests_properties(unit.scene.runtime PROPERTIES LABELS "unit;scene")
add_test(NAME unit.renderer.vfx_system COMMAND render_vfx_system_tests)
set_tests_properties(unit.renderer.vfx_system PROPERTIES LABELS "unit;renderer;vfx")
add_test(NAME headless.smoke.startup COMMAND render_headless_validation)
set_tests_properties(headless.smoke.startup PROPERTIES LABELS "headless;smoke")

add_custom_target(render_test_unit
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure --label-regex unit
DEPENDS render_platform_types_tests render_core_runtime_tests render_serialization_tests render_filesystem_tests render_renderer_lifecycle_tests render_shader_pipeline_tests render_geometry_submission_tests render_lighting_pipeline_tests render_debug_renderer_tests render_scene_tests
DEPENDS render_platform_types_tests render_core_runtime_tests render_serialization_tests render_filesystem_tests render_renderer_lifecycle_tests render_shader_pipeline_tests render_geometry_submission_tests render_lighting_pipeline_tests render_debug_renderer_tests render_scene_tests render_vfx_system_tests
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
COMMENT "Running render unit tests"
)
Expand Down
17 changes: 17 additions & 0 deletions docs/rendering.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Statement 11: scene graph integration (camera/light/renderable extraction).
- Statement 12: geometry submission + batching foundation.
- Statement 13: forward-plus style lighting data path (light selection, fog/bloom/shadow/outline settings, and diagnostics).
- Statement 15: ambient VFX system for spores/dust/embers/resin drips/glow pulses/market ambience.

## Engine-owned shader architecture

Expand Down Expand Up @@ -251,3 +252,19 @@ Tracked pass rows currently include:
- composite/present placeholder

This keeps the instrumentation API stable while deferring backend-specific GPU timer query plumbing to a follow-up statement.


## Ambient VFX layer (Statement 15)

Statement 15 adds `engine/render/vfx.*` as a renderer-owned ambient effect subsystem with scene attachment support.

Highlights:

- typed effect definitions + reusable presets (spores, dust, embers, resin drips, glow pulses, market ambience)
- deterministic CPU simulation with seeded initialization
- GPU instanced sprite submission through existing renderer APIs
- scene integration via `scene::VfxAttachmentComponent` and visibility filtering
- debug counters for VFX active effects/particles/draws/uploads
- shader pipeline integration through `vfx/ambient_sprite` manifest entries and variants

Detailed design and current limits are documented in `docs/vfx.md`.
62 changes: 62 additions & 0 deletions docs/vfx.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Ambient VFX System (Statement 15)

Statement 15 adds an engine-owned ambient VFX subsystem focused on stylized, lightweight atmosphere.

## Architecture

- Runtime module: `engine/render/vfx.hpp/.cpp`.
- Scene bridge: `scene::VfxAttachmentComponent` attaches a scene node to a VFX effect handle.
- Render integration: VFX produces instanced `DrawSubmission` payloads consumed by existing renderer submission APIs.

## Effect model

`EffectDefinition` defines effect templates with typed parameter groups:

- core: `EffectType`, `PrimitiveType`, `max_particles`, `spawn_rate_per_second`, `looping`
- spawn: `EffectSpawnRegion`
- particle motion: `ParticleStyle` (size/lifetime/velocity/drift/emissive)
- resin-specific: `ResinDripStyle`
- pulse-specific: `GlowPulseStyle`
- deterministic seed: `core::Seed`

Runtime state (`EffectState`) stores per-instance RNG, particle arrays, timers, and transform.

## CPU vs GPU responsibilities

Current maturity level intentionally uses a practical hybrid path:

- CPU: spawn/update/lifetime simulation and deterministic seeded randomization.
- GPU: draws all active particles/primitives through instanced sprite submissions.

This keeps costs low for ambient populations while avoiding premature compute complexity.

## Supported classes

Built-in definition helpers:

- spores (`make_spores_definition`)
- dust (`make_dust_definition`)
- embers (`make_embers_definition`)
- resin drips (`make_resin_drips_definition`)
- glow pulses (`make_glow_pulses_definition`)
- market hall ambience preset (`make_market_ambience_preset`)

Market ambience is composite by design (dust + warm specks + pulse accents).

## Renderer pass placement

`render_shell` submits VFX in an explicit `vfx-ambient-pass` after the main lit pass planning and before post placeholders. This keeps atmospheric sprites in the regular frame lifecycle and visible in renderer debug timings.

## Performance policy

- One instanced draw submission per active effect instance.
- Particle payload uploads are contiguous 4x4 transform arrays (`64 bytes/instance`).
- Toggle mask (`VfxToggleMask`) allows category-level disable for profiling.
- Debug counters include active effect/particle counts and VFX draw/upload totals.

## Current limits / deferred follow-ups

- No compute simulation yet.
- No per-instance color buffer (variant-based tinting used currently).
- Billboard facing/orientation is currently lightweight and world-oriented.
- Future statements can add richer resource bindings, textured sprites, collision, and gameplay-driven bursts.
13 changes: 13 additions & 0 deletions engine/render/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,16 @@ Current debug view behavior:
- `light-volumes`: normal shading with overlay diagnostics for light counts.
- `overdraw`: additive/no-depth approximation pass override.
- `gpu-timing`: overlay emphasizes per-pass timing rows; current implementation is CPU-timed with explicit `gpu=n/a` fallback.


## Ambient VFX system (Statement 15)

`vfx.hpp/.cpp` adds an engine-owned atmospheric VFX layer for ambient world motion.

- effect templates + runtime instances (spores, dust, embers, resin drips, glow pulses, market ambience)
- deterministic CPU simulation for spawn/lifetime/drift using `core::Random`
- GPU instanced sprite submission through existing `Renderer::submit_instanced`
- diagnostics for active effects/particles and VFX draw/upload counts
- category toggles (`VfxToggleMask`) for profiling and debug isolation

Scene-level attachment is handled by `scene::VfxAttachmentComponent` (in `engine/scene`) so effects can follow node transforms without exposing backend-specific handles.
7 changes: 7 additions & 0 deletions engine/render/debug_renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@ std::vector<std::string> RendererDebugState::build_overlay_lines() const {
<< " frame_ms=" << snapshot_.frame_time_ms;
lines.push_back(counts.str());

std::ostringstream vfx_counts;
vfx_counts << "vfx effects=" << snapshot_.counters.vfx_active_effects
<< " particles=" << snapshot_.counters.vfx_active_particles
<< " draws=" << snapshot_.counters.vfx_draw_calls
<< " uploads=" << snapshot_.counters.vfx_instance_uploads;
lines.push_back(vfx_counts.str());

if (!snapshot_.gpu_timing_supported) {
lines.push_back("gpu timing unavailable (using cpu pass timings)");
}
Expand Down
4 changes: 4 additions & 0 deletions engine/render/debug_renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ struct RendererDebugCounters {
std::uint32_t submitted_draws{0};
std::uint32_t instanced_draws{0};
std::uint32_t submitted_instances{0};
std::uint32_t vfx_active_effects{0};
std::uint32_t vfx_active_particles{0};
std::uint32_t vfx_draw_calls{0};
std::uint32_t vfx_instance_uploads{0};
};

struct RendererPassTiming {
Expand Down
Loading
Loading