stylized 1-bit rendering

This commit is contained in:
Jonas H
2026-01-21 11:04:55 +01:00
parent 5d2eca0393
commit 2422106725
40 changed files with 2859 additions and 366 deletions

View File

@@ -6,6 +6,8 @@ This file provides guidance to Claude Code when working with code in this reposi
This is a pure Rust game project using SDL3 for windowing/input, wgpu for rendering, rapier3d for physics, and a low-res retro aesthetic with dithering. This is a migration from the Godot-based snow_trail project, implementing the same snow deformation system and character controller without engine dependencies.
**Content Creation:** Blender 5.0 is used for terrain modeling and asset export (glTF meshes + EXR heightmaps).
## Code Style
**Code Documentation Guidelines**:
@@ -143,12 +145,17 @@ SDL Events → InputState → player_input_system() → InputComponent → movem
- Final blit pass upscales framebuffer to window using nearest-neighbor sampling
- Depth buffer for 3D rendering with proper occlusion
**Terrain Height Deformation:**
**Terrain Rendering:**
- glTF mesh exported from Blender 5.0 with baked height values in vertices
- No runtime displacement in shader - vertices rendered directly
- Separate terrain pipeline for terrain-specific rendering
- Terrain mesh has heights pre-baked during export for optimal performance
**Terrain Physics:**
- EXR heightmap files loaded via `exr` crate (single-channel R32Float format)
- Height displacement applied in vertex shader
- Separate terrain pipeline with texture sampling in vertex stage
- TerrainUniforms includes height_scale parameter for tweaking displacement strength
- R32Float textures require non-filterable samplers (FilterMode::Nearest)
- Heightmap loaded directly into rapier3d heightfield collider
- No runtime sampling or computation - instant loading
- Both glTF and EXR exported from same Blender terrain, guaranteed to match
**Lighting Model:**
- Directional light (like Godot's DirectionalLight3D)
@@ -194,7 +201,7 @@ cargo fmt
WGSL shaders are stored in the `shaders/` directory:
- `shaders/standard.wgsl` - Standard mesh rendering with directional lighting
- `shaders/terrain.wgsl` - Terrain rendering with height displacement
- `shaders/terrain.wgsl` - Terrain rendering with shadow mapping (no displacement)
- `shaders/blit.wgsl` - Fullscreen blit for upscaling low-res framebuffer
Shaders are loaded at runtime via `std::fs::read_to_string()`, allowing hot-reloading by restarting the application.
@@ -224,10 +231,9 @@ Shaders are loaded at runtime via `std::fs::read_to_string()`, allowing hot-relo
**Rendering:**
- `render.rs` - wgpu renderer, pipelines, bind groups, DrawCall execution
- `shader.rs` - Standard mesh shader (WGSL) with diffuse+ambient lighting
- `terrain.rs` - Terrain mesh generation and pipeline creation
- `terrain.rs` - Terrain entity spawning, glTF loading, EXR heightmap → physics collider
- `postprocess.rs` - Low-res framebuffer and blit shader for upscaling
- `mesh.rs` - Vertex/Mesh structs, plane/cube mesh generation, glTF loading
- `heightmap.rs` - EXR heightmap loading using `exr` crate
- `draw.rs` - DrawManager (legacy, kept for compatibility)
**Game Logic:**
@@ -260,32 +266,32 @@ Shaders are loaded at runtime via `std::fs::read_to_string()`, allowing hot-relo
- **bytemuck**: Safe byte casting for GPU buffer uploads (Pod/Zeroable for vertex data)
- **anyhow**: Ergonomic error handling
- **gltf**: Loading 3D models in glTF format
- **exr**: Loading EXR heightmap files (single-channel float data)
- **image**: Image loading and processing (includes EXR support)
- **half**: Float16 support (dependency of exr)
- **exr**: Loading EXR heightmap files (single-channel float data for physics colliders)
- **kurbo**: Bezier curve evaluation for movement acceleration curves
## Technical Notes
### EXR Heightmap Loading
When loading EXR files with the `exr` crate:
### EXR Heightmap Loading (Physics Only)
When loading EXR files with the `exr` crate for physics colliders:
- Must import traits: `use exr::prelude::{ReadChannels, ReadLayers};`
- Use builder pattern: `.no_deep_data().largest_resolution_level().all_channels().all_layers().all_attributes().from_file(path)`
- Extract float data: `channel.sample_data.values_as_f32().collect()`
- Create R32Float texture for height data
- R32Float is non-filterable, requires `FilterMode::Nearest` sampler
- Convert to nalgebra DMatrix for rapier3d heightfield collider
- No GPU texture creation - physics data only
### wgpu Texture Formats
- R32Float = single-channel 32-bit float, **non-filterable**
- Use `TextureSampleType::Float { filterable: false }` in bind group layout
- Use `SamplerBindingType::NonFiltering` for sampler binding
- Attempting linear filtering on R32Float causes validation errors
### Blender Export Workflow
**Using Blender 5.0** for terrain creation and export:
- Export terrain as **glTF** with baked height values in mesh vertices
- Export same terrain as **EXR** heightmap (single-channel R32Float)
- Both files represent the same terrain data, guaranteeing visual/physics sync
- glTF used for rendering (vertices rendered directly, no shader displacement)
- EXR used for physics (loaded into rapier3d heightfield collider)
### Multiple Render Pipelines
- `Pipeline` enum determines which pipeline to use per DrawCall
- Different pipelines can have different shaders, bind group layouts, uniforms
- Terrain pipeline: includes height texture binding in vertex stage
- Standard pipeline: basic mesh rendering without height displacement
- Terrain pipeline: shadow-mapped rendering with line hatching shading
- Standard pipeline: basic mesh rendering with diffuse lighting
- Each pipeline writes to its own uniform buffer before rendering
### ECS Component Storages
@@ -589,7 +595,8 @@ let time = Time::get_time_elapsed(); // Anywhere in code
- ✅ Low-res framebuffer (160×120) with Bayer dithering
- ✅ Multiple render pipelines (standard mesh + terrain)
- ✅ Directional lighting with diffuse + ambient
-EXR heightmap loading and terrain displacement
-Terrain rendering (glTF with baked heights, no shader displacement)
- ✅ EXR heightmap loading for physics colliders
- ✅ glTF mesh loading
- ✅ render_system (ECS-based DrawCall generation)