This commit is contained in:
Matthew Deville 2025-08-31 11:39:39 +02:00
parent bc21beeb36
commit abff3f5434
4 changed files with 58 additions and 63 deletions

View file

@ -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);
}

View file

@ -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);
}

View file

@ -0,0 +1,30 @@
// Simple UV gradient shader (vertex + fragment)
struct VertexInput {
@location(0) position: vec3<f32>,
@location(1) uv: vec2<f32>,
}
struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
@location(0) uv: vec2<f32>,
}
@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<f32>(in.position, 1.0);
out.uv = in.uv;
return out;
}
@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
// very simple vertical gradient between two colors
let bottom = vec3<f32>(1.0, 0.8, 0.2); // warm
let top = vec3<f32>(0.2, 0.6, 1.0); // cool
let color = mix(bottom, top, in.uv.y);
return vec4<f32>(color, 1.0);
}

View file

@ -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::<CustomMaterial>::default())
.add_plugins((
DefaultPlugins,
Material2dPlugin::<CustomMaterial>::default(),
))
.add_systems(Startup, setup)
.run();
}
@ -23,47 +25,36 @@ fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<CustomMaterial>>,
primary_window: Single<&Window, With<PrimaryWindow>>,
) {
// 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<Handle<Image>>,
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
}
}