bevy_psx

Crates.iobevy_psx
lib.rsbevy_psx
version0.1.2
created_at2025-10-14 15:41:43.590592+00
updated_at2025-10-17 11:25:06.346034+00
descriptionA Bevy plugin that provides authentic PlayStation 1 (PSX) style rendering capabilities, including low-resolution rendering, vertex snapping, and palette quantization
homepagehttps://github.com/tajo48/bevy_psx
repositoryhttps://github.com/tajo48/bevy_psx
max_upload_size
id1882576
size298,850
Piotr Wojciech Świercz (tajo48)

documentation

README

Bevy PSX

A Bevy plugin that provides authentic PlayStation 1 (PSX) style rendering capabilities, including low-resolution rendering, vertex snapping, and palette quantization.

Features

  • Low-Resolution Rendering: Render your 3D scenes at classic PSX resolutions (320x240, 512x448, etc.)
  • Vertex Snapping: Authentic PSX-style vertex jittering that recreates the characteristic "wobbly" geometry
  • Optional Palette Quantization: Apply color palettes to achieve retro color limitations (off by default)
  • Aspect Ratio Matching: Automatically adjusts resolution to match your window's aspect ratio while maintaining the retro aesthetic
  • Pixelated Upscaling: Choose between nearest-neighbor (pixelated) or linear filtering for the final output
  • Multiple Palettes: Load and switch between different color palettes at runtime
  • Automatic Material Conversion: Seamlessly converts standard Bevy materials to PSX-enhanced materials

Quick Start

Add the plugin to your Bevy app:

use bevy::prelude::*;
use bevy_psx::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(PsxCameraPlugin)  // Add the PSX plugin
        .add_systems(Startup, setup)
        .run();
}

fn setup(mut commands: Commands) {
    // Spawn a camera with PSX rendering
    commands.spawn((
        Camera3d::default(),
        Transform::from_xyz(4.0, 2.5, 4.0).looking_at(Vec3::ZERO, Vec3::Y),
        PsxCamera,  // This component enables PSX rendering!
    ));

    // Your 3D objects will automatically get PSX vertex snapping
    // Palette quantization is available but disabled by default
}

That's it! Your camera will now render at PSX resolution with automatic vertex snapping applied to all 3D models. Palette quantization is available but disabled by default.

Configuration

Render Settings

Control the PSX rendering behavior with PsxRenderSettings:

fn configure_psx(mut settings: ResMut<PsxRenderSettings>) {
    // Set resolution
    settings.render_resolution = UVec2::new(320, 240);  // Classic PSX
    settings.base_resolution = UVec2::new(320, 240);

    // Enable/disable features
    settings.pixelated = true;              // Nearest-neighbor filtering
    settings.aspect_ratio_matching = true;  // Adjust to window aspect ratio
}

Vertex Snapping

Control vertex snapping with PsxSettings:

fn configure_vertex_snapping(mut settings: ResMut<PsxSettings>) {
    settings.snap_enabled = true;
    settings.snap_amount = 64.0;  // Lower = more jittery, Higher = smoother
    
    // Jitter levels guide:
    // 8.0-16.0:   Extreme jitter (very wobbly, experimental)
    // 16.0-32.0:  Maximum jitter (authentic PSX look)
    // 64.0-96.0:  Moderate jitter (recommended for most games)
    // 128.0-256.0: Minimal jitter (smoother movement)
    // 512.0+:     Almost no jitter (modern look with slight retro feel)
}

Understanding Vertex Snapping Jitter

The snap_amount value controls how "wobbly" your 3D geometry appears, recreating the characteristic PSX vertex jitter:

  • How it works: Vertices are snapped to a grid in screen space. Lower values create fewer grid points, causing dramatic jumps between positions as objects move or rotate.

  • Visual impact:

    • 8.0-32.0: Very noticeable vertex "popping" - vertices jump visibly between positions
    • 64.0: Classic PSX feel - noticeable but not overwhelming jitter
    • 128.0+: Subtle effect - maintains retro feel without being distracting
  • Performance: All snap amounts have similar performance impact since the calculation is done on the GPU.

  • Recommendation: Start with 64.0 for an authentic PSX experience, then adjust based on your artistic vision.

Palette Quantization (Optional)

Color palettes are now handled through the unified shader system with PsxSettings:

fn configure_unified_shader(mut settings: ResMut<PsxSettings>) {
    settings.use_palette = true;      // Turn on palette quantization
    settings.quantize_steps = 32;     // Color reduction steps
}

Controls

The plugin includes built-in keyboard controls (can be seen in the examples):

Rendering Controls:

  • 1, 2, 3, 4: Switch between preset resolutions
  • A: Toggle aspect ratio matching
  • F: Toggle pixelated/smooth filtering

Common Controls (most examples):

  • V: Increase vertex snap amount (smoother)
  • B: Decrease vertex snap amount (more jittery)
  • P: Toggle palette quantization on/off
  • N: Switch to next palette
  • M: Switch to previous palette
  • Q: Toggle basic quantization on/off
  • E: Decrease quantization steps (more posterized)
  • R: Increase quantization steps (smoother gradients)
  • D: Toggle dithering on/off
  • G: Switch dither patterns (forward)
  • H: Switch dither patterns (backward)

Variable Controls (example-specific):

  • T: Toggle vertex snapping (lights example) OR Decrease dither strength (other examples)
  • Y: Increase dither strength

⚠️ Important: Each example may use slightly different key mappings! When you run an example, check the console output for the specific controls available. The most comprehensive controls are in the lights.rs example.

Palettes (Optional Feature)

The plugin automatically loads color palettes but keeps them off by default. Each demo can choose whether to turn on palette quantization. Supported formats:

  • Hex files (.hex): Each line contains a hex color (with or without #)

Example palette file:

# My Custom Palette
000000
ffffff
ff0000
00ff00
0000ff

Built-in palettes include:

  • Game Boy (4 colors)
  • Lospec 2000 (various colors)
  • Axulart 32-color palette
  • And more!

Examples

Run any of these examples to see the PSX plugin in action:

🎮 Simple PSX Scene

cargo run --example simple_psx

A basic demonstration of PSX rendering with interactive controls for all features.

🔄 Rotating Scene with Multiple Objects

cargo run --example rotating_scene

Multiple animated objects showcasing vertex snapping and palette effects.

💡 Advanced Lighting with PSX Camera

cargo run --example lights

The most comprehensive example - demonstrates complex lighting scenarios with PSX rendering:

Features:

  • Physical Camera System: Full exposure controls with aperture, shutter speed, and ISO
  • Multiple Light Types: Point lights, spot lights, directional lights, and ambient lighting
  • Dynamic Lighting: Animated directional light and interactive object movement
  • PSX Integration: See how complex lighting works with vertex snapping and palette quantization
  • Real-time Comparison: Toggle between full-color and palette-quantized lighting effects

Controls:

  • 1/2 - Adjust camera aperture (f-stops)
  • 3/4 - Adjust shutter speed
  • 5/6 - Adjust ISO sensitivity
  • R - Reset exposure settings
  • Space - Toggle ambient light on/off
  • Arrow Keys - Move objects around the scene
  • Z - Toggle red point light on/off
  • X - Toggle green spot light on/off
  • C - Toggle blue point light on/off
  • G - Toggle directional light on/off
  • P - Toggle palette quantization (compare lighting effects!)
  • N/M - Switch between color palettes
  • V/B - Adjust vertex snapping intensity
  • T - Toggle vertex snapping on/off
  • Q/E - Adjust color quantization steps

⚡ Stress Test (Performance Testing)

cargo run --example object_spawner

Extreme performance testing with automatic object spawning up to 1000 objects per frame.

Technical Details

Rendering Pipeline

  1. Your 3D scene renders to a low-resolution texture
  2. Vertex snapping is applied during vertex processing
  3. Fragment colors are quantized using the active palette
  4. The low-res texture is upscaled to fill your window
  5. Filtering (pixelated vs smooth) is applied during upscaling

Automatic Material Conversion

The plugin automatically converts standard Bevy StandardMaterials to PSX-enhanced materials with:

  • Vertex snapping in the vertex shader (always enabled)
  • Palette quantization in the fragment shader (when enabled by the demo)
  • Maintains all original material properties (textures, colors, etc.)

Aspect Ratio Matching

When enabled, the plugin automatically adjusts the render resolution based on your window's aspect ratio:

  • Wide windows (16:9, 21:9): Keeps height at base resolution, adjusts width
  • Tall windows: Keeps width at base resolution, adjusts height
  • Square windows: Uses base resolution as-is

This prevents stretching while maintaining the low-resolution aesthetic.

Common Resolutions

  • PSX: 320×240 (4:3)
  • PS2: 512×448 (8:7, close to 4:3)
  • SNES: 256×224 (8:7)
  • Custom: Any resolution you want!

Performance

The PSX rendering adds minimal overhead:

  • Low-resolution rendering actually improves performance
  • Vertex snapping is GPU-accelerated
  • Automatic material conversion happens once per material

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit issues and pull requests.

Compatibility

  • Bevy Version: 0.17.1
  • Platforms: All platforms supported by Bevy
  • Rendering: Compatible with Bevy's PBR pipeline

Acknowledgments

Inspired by the distinctive visual style of original PlayStation games and the technical limitations that created their unique aesthetic.

Commit count: 0

cargo fmt