diff --git a/assets/shaders/custom_material.frag b/assets/shaders/custom_material.frag deleted file mode 100644 index b4f4df1..0000000 --- a/assets/shaders/custom_material.frag +++ /dev/null @@ -1,14 +0,0 @@ -#version 450 - -layout(location = 0) in vec2 v_uv; -layout(location = 0) out vec4 o_color; - -layout(set = 0, binding = 0) uniform MaterialUniform { - vec4 color; -} material; - -void main() { - // simple uv-based gradient multiplied by uniform color - vec3 grad = vec3(v_uv, 0.5); - o_color = material.color * vec4(grad, 1.0); -} diff --git a/assets/shaders/custom_material.vert b/assets/shaders/custom_material.vert deleted file mode 100644 index 547cac3..0000000 --- a/assets/shaders/custom_material.vert +++ /dev/null @@ -1,12 +0,0 @@ -#version 450 - -// Minimal passthrough vertex shader for a fullscreen plane. -layout(location = 0) in vec3 Vertex_Position; -layout(location = 1) in vec2 Vertex_Uv; - -layout(location = 0) out vec2 v_uv; - -void main() { - v_uv = Vertex_Uv; - gl_Position = vec4(Vertex_Position, 1.0); -} diff --git a/assets/shaders/default.wgsl b/assets/shaders/default.wgsl new file mode 100644 index 0000000..c736dcd --- /dev/null +++ b/assets/shaders/default.wgsl @@ -0,0 +1,30 @@ +// Simple UV gradient shader (vertex + fragment) + +struct VertexInput { + @location(0) position: vec3, + @location(1) uv: vec2, +} + +struct VertexOutput { + @builtin(position) clip_position: vec4, + @location(0) uv: vec2, +} + +@vertex +fn vertex(in: VertexInput) -> VertexOutput { + var out: VertexOutput; + // assume incoming positions are in clip-space (vec3 with z, or model-transformed) + out.clip_position = vec4(in.position, 1.0); + out.uv = in.uv; + return out; +} + +@fragment +fn fragment(in: VertexOutput) -> @location(0) vec4 { + // very simple vertical gradient between two colors + let bottom = vec3(1.0, 0.8, 0.2); // warm + let top = vec3(0.2, 0.6, 1.0); // cool + + let color = mix(bottom, top, in.uv.y); + return vec4(color, 1.0); +} diff --git a/src/main.rs b/src/main.rs index 2b2e248..9364d99 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,16 +4,18 @@ use bevy::{ prelude::*, reflect::TypePath, render::render_resource::{AsBindGroup, ShaderRef}, + sprite::{AlphaMode2d, Material2d, Material2dPlugin}, + window::PrimaryWindow, }; -/// This example uses shader source files from the assets subdirectory -const VERTEX_SHADER_ASSET_PATH: &str = "shaders/custom_material.vert"; -const FRAGMENT_SHADER_ASSET_PATH: &str = "shaders/custom_material.frag"; +const SHADER_ASSET_PATH: &str = "shaders/default.wgsl"; fn main() { App::new() - .add_plugins(DefaultPlugins) - .add_plugins(MaterialPlugin::::default()) + .add_plugins(( + DefaultPlugins, + Material2dPlugin::::default(), + )) .add_systems(Startup, setup) .run(); } @@ -23,47 +25,36 @@ fn setup( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, + primary_window: Single<&Window, With>, ) { - // Fullscreen flat surface: use a very large, thin cuboid so it behaves like a plane - commands.spawn(( - Mesh3d(meshes.add(Cuboid::default())), - MeshMaterial3d(materials.add(CustomMaterial { - color: LinearRgba::new(0.2, 0.6, 0.9, 1.0), - color_texture: None, - alpha_mode: AlphaMode::Opaque, - })), - // Scale X/Y large to cover the camera view, keep Z very small to make it effectively a plane - Transform::from_scale(Vec3::new(2000.0, 2000.0, 0.01)), - )); + // camera + commands.spawn(Camera2d); - // 2D camera so the scene renders as a flat screen - commands.spawn((Camera2d::default(), Transform::default())); + // quad that fills the whole window + let size = Vec2::new( + primary_window.resolution.width(), + primary_window.resolution.height(), + ); + + commands.spawn(( + Mesh2d(meshes.add(Rectangle::default())), + MeshMaterial2d(materials.add(CustomMaterial {})), + Transform::from_scale(Vec3::new(size.x, size.y, 1.0)), + )); } // This is the struct that will be passed to your shader #[derive(Asset, TypePath, AsBindGroup, Clone)] -struct CustomMaterial { - #[uniform(0)] - color: LinearRgba, - #[texture(1)] - #[sampler(2)] - color_texture: Option>, - alpha_mode: AlphaMode, -} - -/// The Material trait is very configurable, but comes with sensible defaults for all methods. -/// You only need to implement functions for features that need non-default behavior. See the Material api docs for details! -/// When using the GLSL shading language for your shader, the specialize method must be overridden. -impl Material for CustomMaterial { - fn vertex_shader() -> ShaderRef { - VERTEX_SHADER_ASSET_PATH.into() - } +struct CustomMaterial {} +/// The Material2d trait is very configurable, but comes with sensible defaults for all methods. +/// You only need to implement functions for features that need non-default behavior. See the Material2d api docs for details! +impl Material2d for CustomMaterial { fn fragment_shader() -> ShaderRef { - FRAGMENT_SHADER_ASSET_PATH.into() + SHADER_ASSET_PATH.into() } - fn alpha_mode(&self) -> AlphaMode { - self.alpha_mode + fn alpha_mode(&self) -> AlphaMode2d { + AlphaMode2d::Opaque } }