Skip to content

feat: add lighting to rendering state and minmap generation from heightmap#99

Merged
ViTeXFTW merged 3 commits intofeat/terrain-renderingfrom
claude/phase-6-lighting-polish-VCmWz
Feb 23, 2026
Merged

feat: add lighting to rendering state and minmap generation from heightmap#99
ViTeXFTW merged 3 commits intofeat/terrain-renderingfrom
claude/phase-6-lighting-polish-VCmWz

Conversation

@ViTeXFTW
Copy link
Copy Markdown
Owner

Summary

Implements Phase 6 of the rendering pipeline, adding time-of-day lighting, shadow colour tinting, cloud shadow animation, and minimap generation. Introduces LightingState to manage scene lighting state and MinimapGenerator for CPU-side minimap rendering.

Key Changes

Lighting System (Phase 6.1–6.3)

  • LightingState class (src/render/lighting_state.hpp/cpp): Manages active lighting state with support for:

    • Time-of-day switching (Morning/Afternoon/Evening/Night)
    • Terrain and object lighting accessors
    • Push constant generation for terrain rendering
    • Hard-coded fallback defaults when no map is loaded
  • Shadow colour support (Phase 6.2): Decodes ARGB shadow colour from GlobalLighting and applies tinting in terrain fragment shader based on surface orientation

  • Cloud shadow animation (Phase 6.3):

    • Configurable scroll speeds and strength
    • Per-frame time accumulation via update()
    • Procedural 2D noise-based cloud pattern in shader with FBM blending
    • Animated UV coordinates passed through vertex shader

Minimap Generation (Phase 6.4)

  • MinimapGenerator class (src/render/terrain/terrain_minimap.hpp/cpp):
    • Full-resolution and scaled minimap generation from heightmap data
    • Height-to-colour gradient mapping (dark green → light tan)
    • Bilinear sampling for downscaled output
    • RGBA8 pixel format suitable for Vulkan texture upload

Shader Updates

  • terrain.vert/frag: Added cloud shadow animation, shadow colour tinting, and procedural noise functions
  • basic.frag: Integrated scene lighting from UBO (populated by LightingState)
  • Pipeline structures: Extended UniformBufferObject and TerrainPushConstant with lighting and cloud parameters

Integration

  • Renderer: Populates UBO lighting fields from LightingState (or defaults)
  • TerrainRenderable: Added setLighting(LightingState&) method for Phase 6 lighting
  • Test coverage: 40+ unit tests for LightingState and MinimapGenerator (no Vulkan dependency)

Implementation Details

  • Time-of-day slots are indexed 0–3 (Morning/Afternoon/Evening/Night) with separate terrain and object lighting per slot
  • Shadow colour uses ARGB encoding; decoded to normalized [0,1] range in push constant
  • Cloud animation uses hash-based 2D noise with smoothstep interpolation for smooth transitions
  • Minimap generation clamps output dimensions to source size to avoid upscaling artifacts
  • All lighting defaults match pre-Phase-6 hard-coded shader values for backward compatibility

https://claude.ai/code/session_01St1oa77j4XRUuovTYQbAFn

6.1 Time-of-day lighting
- Add LightingState class (src/render/lighting_state.hpp/cpp) that wraps
  GlobalLighting, handles time-of-day slot selection (Morning/Afternoon/
  Evening/Night), and produces TerrainPushConstant and object lighting
  vectors for CPU-side consumers.
- Extend UniformBufferObject with lightDirection, ambientColor, diffuseColor
  vec4s so basic.frag reads scene lighting from the UBO instead of hardcoded
  constants.
- Update Renderer::updateUniformBuffer() to populate UBO lighting from
  LightingState when set, falling back to pre-Phase-6 defaults otherwise.
- Update standard() and skinned() descriptor binding 0 stage flags to expose
  UBO to the fragment shader.

6.2 Shadow color
- Decode GlobalLighting::shadowColor (ARGB uint32) in LightingState and
  expose it via TerrainPushConstant::shadowColor (vec4).
- terrain.frag blends diffuse result toward shadow colour to simulate cast
  shadows.

6.3 Cloud shadows
- Add cloud scroll/strength/time parameters to TerrainPushConstant.
- terrain.vert computes fragCloudCoord (world-space xz * scale + time*scroll).
- terrain.frag applies a 2-octave procedural FBM noise cloud shadow overlay
  without requiring an additional texture binding.
- LightingState::setCloudShadow() / disableCloudShadow() / update() manage
  cloud animation accumulation.
- TerrainRenderable::update(dt) forwards delta time to the push constant.

6.4 Minimap generation
- Add MinimapGenerator (src/render/terrain/terrain_minimap.hpp/cpp) with
  generate() (1:1 pixel per heightmap cell) and generateScaled() (bilinear
  downsampling) producing RGBA8 images from HeightMap data.

Tests (TDD)
- tests/render/test_lighting_state.cpp – 23 tests covering defaults,
  setGlobalLighting, time-of-day switching, push constant generation, ARGB
  shadow decoding, object lighting, and cloud animation.
- tests/terrain/test_terrain_minimap.cpp – 14 tests covering empty/invalid
  inputs, pixel count, gradient variation, bilinear scaling, edge clamping.
- Fix pre-existing test regression: update TestsObjectFlagHelpers to match
  MapObject::shouldRender() behavior introduced in f20af65 (road/bridge
  points are placement markers and correctly return false from shouldRender).
- Add GLFW_INCLUDE_NONE compile definition to suppress GL/gl.h inclusion in
  headless CI environments.

All 24 test targets pass (100%).

https://claude.ai/code/session_01St1oa77j4XRUuovTYQbAFn
@ViTeXFTW
Copy link
Copy Markdown
Owner Author

@greptileai

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Feb 23, 2026

Greptile Summary

Implements Phase 6 lighting, shadows, cloud effects, and minimap generation with comprehensive test coverage. Introduces LightingState class for managing time-of-day lighting and MinimapGenerator for CPU-side minimap rendering.

Key changes:

  • Time-of-day lighting system with 4 slots (Morning/Afternoon/Evening/Night) supporting separate terrain and object lighting
  • Shadow color tinting decoded from ARGB format and applied based on surface orientation
  • Procedural cloud shadow animation using hash-based 2D noise with FBM blending
  • Full-resolution and scaled minimap generation with bilinear sampling
  • Extended UBO and push constant structures with proper alignment for lighting parameters
  • Migrated shaders from hard-coded lighting to dynamic scene lighting
  • 40+ unit tests covering all new functionality with no Vulkan dependencies

Architecture:

  • LightingState provides fallback defaults for model-viewer mode when no map is loaded
  • Shader integration uses push constants for terrain lighting and UBO for object lighting
  • Cloud animation advances via per-frame update() calls with time accumulation
  • All new code follows project conventions: snake_case members, PascalCase classes, proper RAII patterns

Confidence Score: 5/5

  • This PR is safe to merge with no issues found
  • Well-architected implementation following established project patterns with comprehensive test coverage (40+ tests), proper error handling, clean separation of concerns, and backward compatibility via fallback defaults
  • No files require special attention

Important Files Changed

Filename Overview
src/render/lighting_state.hpp New class managing scene lighting state with time-of-day switching, shadow color, and cloud animation - well-documented with fallback defaults
src/render/lighting_state.cpp Implementation of LightingState with proper ARGB decoding and time slot indexing - clean separation of concerns
src/render/terrain/terrain_minimap.hpp Minimap generator interface with full-resolution and scaled variants - clear API with validation
src/render/terrain/terrain_minimap.cpp CPU-side minimap generation with bilinear filtering for downscaling - proper bounds checking and color gradient
shaders/terrain.vert Added cloud shadow UV animation using world-space coordinates with configurable scroll speeds
shaders/terrain.frag Implemented shadow color tinting and procedural cloud pattern with FBM noise - smooth transitions via smoothstep
src/lib/gfx/pipeline.hpp Extended UniformBufferObject and TerrainPushConstant with lighting and cloud parameters - proper alignment directives
tests/render/test_lighting_state.cpp Comprehensive test coverage with 40+ tests for all LightingState functionality including edge cases
tests/terrain/test_terrain_minimap.cpp Thorough minimap generator tests covering dimensions, gradients, scaling, and edge cases

Last reviewed commit: f6bc03f

@ViTeXFTW ViTeXFTW marked this pull request as ready for review February 23, 2026 18:02
@ViTeXFTW ViTeXFTW changed the base branch from claude/phase-5-scene-graph-BUg31 to feat/terrain-rendering February 23, 2026 18:03
@ViTeXFTW ViTeXFTW changed the title Phase 6: Lighting, shadows, cloud effects, and minimap feat: add lighting to rendering state and minmap generation from heightmap Feb 23, 2026
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Feb 23, 2026

Greptile Summary

Implements Phase 6 lighting system with time-of-day management, shadow color tinting, procedural cloud shadows, and CPU-side minimap generation. The implementation follows the project's architecture patterns with proper RAII, extensive test coverage (38+ unit tests), and maintains backward compatibility through fallback defaults.

Key implementations:

  • LightingState class manages scene lighting with time-of-day switching and provides push constant generation for terrain rendering
  • Shadow color decoding from ARGB format with alpha-based tinting in fragment shader
  • Procedural cloud shadow animation using hash-based 2D noise with FBM blending
  • MinimapGenerator creates RGBA8 images from heightmap data with bilinear downscaling
  • Shader updates integrate scene lighting from UBO instead of hardcoded constants

Issues identified:

  • Shadow color decoding logic is duplicated between lighting_state.cpp and terrain_renderable.cpp
  • TerrainRenderable::update() and applyLightingState() may conflict if called in wrong order (time accumulation could be lost)

Confidence Score: 4/5

  • Safe to merge with minor cleanup recommended for code duplication and potential state management issue
  • The implementation is well-structured with comprehensive tests and follows project conventions. Two non-critical issues were found: duplicate shadow color decoding logic (style issue) and a potential state management conflict in TerrainRenderable (logic issue). Both are minor and don't affect correctness in typical usage but should be addressed for code quality.
  • Pay attention to src/render/terrain/terrain_renderable.cpp for the duplicate decoding logic and update/applyLightingState calling order

Important Files Changed

Filename Overview
src/render/lighting_state.cpp Implementation of LightingState with proper fallback defaults, ARGB shadow color decoding, and cloud animation time accumulation
src/render/terrain/terrain_minimap.cpp Minimap generator implementation with height-to-color gradient mapping and bilinear downscaling
shaders/terrain.frag Implemented procedural cloud pattern with hash-based 2D noise, shadow color tinting based on surface orientation, and cloud shadow overlay
src/core/renderer.cpp Integrated LightingState into UBO population with proper fallback to defaults when no lighting is set
src/render/terrain/terrain_renderable.cpp Added applyLightingState() and update() methods for Phase 6 lighting, contains duplicate shadow color decoding logic that should use LightingState
tests/render/test_lighting_state.cpp Comprehensive test suite covering default state, time-of-day switching, shadow color decoding, cloud animation, and edge cases

Last reviewed commit: 02d8047

Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

17 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment thread src/render/terrain/terrain_renderable.cpp Outdated
Comment thread src/render/terrain/terrain_renderable.cpp Outdated
@ViTeXFTW
Copy link
Copy Markdown
Owner Author

@greptileai

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Feb 23, 2026

Greptile Summary

Implements Phase 6 lighting and minimap features for the terrain rendering pipeline. Adds LightingState class for centralized scene lighting management with time-of-day support (Morning/Afternoon/Evening/Night), shadow color tinting, and cloud shadow animation. Introduces MinimapGenerator for CPU-side minimap generation from heightmap data with bilinear scaling.

Key improvements:

  • Centralized lighting state management eliminates shader hard-coded constants
  • Time-of-day switching with separate terrain and object lighting
  • Shadow color tinting based on surface orientation (Phase 6.2)
  • Procedural cloud shadow overlay with FBM noise pattern (Phase 6.3)
  • Full-resolution and scaled minimap generation (Phase 6.4)
  • Comprehensive test coverage (534 lines across 40+ tests, no Vulkan dependency)
  • Clean integration with existing renderer via optional LightingState pointer

Architecture:

  • LightingState provides fallback defaults when no map is loaded, ensuring backward compatibility
  • Push constants used for terrain lighting, UBO for object lighting
  • Shader changes maintain consistent lighting model across terrain and objects

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The implementation is well-architected with clear separation of concerns, comprehensive test coverage (534 lines of tests), and backward compatibility through fallback defaults. Code follows project style guide, uses RAII patterns correctly, and has already addressed previous review comments. All new code is additive with no breaking changes to existing functionality.
  • No files require special attention

Important Files Changed

Filename Overview
src/render/lighting_state.hpp Added new LightingState class to manage scene lighting state with time-of-day support, cloud shadow animation, and push constant generation
src/render/lighting_state.cpp Implements lighting state management with time-of-day switching, shadow color decoding, and cloud animation time accumulation
src/render/terrain/terrain_minimap.hpp Added MinimapGenerator class for CPU-side minimap generation from heightmap data with bilinear scaling support
src/render/terrain/terrain_minimap.cpp Implements minimap generation with height-to-color gradient mapping and bilinear downsampling for scaled output
shaders/terrain.frag Added shadow color tinting based on surface orientation and procedural cloud shadow overlay with FBM noise pattern
shaders/terrain.vert Added cloud shadow UV calculation from world-space coordinates with time-based animation offset
src/core/renderer.cpp Added LightingState integration to populate UBO lighting fields with fallback to default values when no lighting is set
src/lib/gfx/pipeline.hpp Extended UniformBufferObject with scene lighting fields and TerrainPushConstant with shadow color and cloud animation parameters
tests/render/test_lighting_state.cpp Added comprehensive unit tests covering time-of-day switching, lighting accessors, shadow color, and cloud animation (327 lines)
tests/terrain/test_terrain_minimap.cpp Added comprehensive unit tests for minimap generation including edge cases, scaling, and color gradients (207 lines)

Last reviewed commit: 291c939

@ViTeXFTW ViTeXFTW merged commit 2a31996 into feat/terrain-rendering Feb 23, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants