Skip to content

Instantly share code, notes, and snippets.

@DGriffin91
Last active July 21, 2022 07:46
Show Gist options
  • Save DGriffin91/c0e580502fd73314f976a46d9ca5b669 to your computer and use it in GitHub Desktop.
Save DGriffin91/c0e580502fd73314f976a46d9ca5b669 to your computer and use it in GitHub Desktop.
Bevy Lambert Material Example
// License: Apache-2.0 / MIT
// lambert_material.wgsl:
/*
#import bevy_pbr::mesh_view_bindings
#import bevy_pbr::mesh_bindings
#import bevy_pbr::pbr_types
#import bevy_pbr::utils
#import bevy_pbr::clustered_forward
#import bevy_pbr::lighting
#import bevy_pbr::shadows
#import bevy_pbr::pbr_functions
struct CustomMaterial {
color: vec4<f32>,
};
@group(1) @binding(0)
var<uniform> material: CustomMaterial;
@group(1) @binding(1)
var base_color_texture: texture_2d<f32>;
@group(1) @binding(2)
var base_color_sampler: sampler;
struct FragmentInput {
@builtin(front_facing) is_front: bool,
@builtin(position) frag_coord: vec4<f32>,
#import bevy_pbr::mesh_vertex_output
};
@fragment
fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {
//Compute normals
let normal = prepare_normal(
0u,
in.world_normal,
#ifdef VERTEX_TANGENTS
#ifdef STANDARDMATERIAL_NORMAL_MAP
in.world_tangent,
#endif
#endif
#ifdef VERTEX_UVS
in.uv,
#endif
in.is_front,
);
var diffuse_color = material.color;
//Sample textures if we have vertex uvs
#ifdef VERTEX_UVS
diffuse_color = diffuse_color * textureSample(base_color_texture, base_color_sampler, in.uv);
#endif
// accumulate color
var light_accum: vec3<f32> = vec3<f32>(0.0);
let view_z = dot(vec4<f32>(
view.inverse_view[0].z,
view.inverse_view[1].z,
view.inverse_view[2].z,
view.inverse_view[3].z
), in.world_position);
let cluster_index = fragment_cluster_index(in.frag_coord.xy, view_z, false);
let offset_and_counts = unpack_offset_and_counts(cluster_index);
// directional lights
let n_directional_lights = lights.n_directional_lights;
for (var i: u32 = 0u; i < n_directional_lights; i = i + 1u) {
let light = lights.directional_lights[i];
var shadow: f32 = 1.0;
if ((mesh.flags & MESH_FLAGS_SHADOW_RECEIVER_BIT) != 0u
&& (light.flags & DIRECTIONAL_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) {
shadow = fetch_directional_shadow(i, in.world_position, in.world_normal);
}
let incident_light = light.direction_to_light.xyz;
let NoL = saturate(dot(normal, incident_light)); // Lambert
let light_contrib = diffuse_color.rgb * light.color.rgb * NoL;
light_accum = light_accum + light_contrib * shadow;
}
let output_color = vec4<f32>(light_accum + diffuse_color.rgb * lights.ambient_color.rgb, 1.0);
return tone_mapping(output_color);
}
*/
// A shader and a material that uses it.
use bevy::{
prelude::*,
reflect::TypeUuid,
render::render_resource::{AsBindGroup, ShaderRef},
};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugin(MaterialPlugin::<LambertMaterial>::default())
.add_startup_system(setup)
.run();
}
/// set up a simple 3D scene
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<LambertMaterial>>,
) {
// plane
commands.spawn().insert_bundle(MaterialMeshBundle {
mesh: meshes.add(Mesh::from(shape::Plane { size: 5.0 })),
transform: Transform::from_xyz(0.0, 0.5, 0.0),
material: materials.add(LambertMaterial {
color: Color::rgb(0.3, 0.5, 0.3),
color_texture: None,
}),
..default()
});
// sphere
commands.spawn().insert_bundle(MaterialMeshBundle {
mesh: meshes.add(Mesh::from(shape::UVSphere {
radius: 0.5,
..default()
})),
transform: Transform::from_xyz(0.0, 1.0, 0.0),
material: materials.add(LambertMaterial {
color: Color::rgb(0.5, 0.5, 0.5),
color_texture: None,
}),
..default()
});
// directional 'sun' light
const HALF_SIZE: f32 = 10.0;
commands.spawn_bundle(DirectionalLightBundle {
directional_light: DirectionalLight {
// Configure the projection to better fit the scene
shadow_projection: OrthographicProjection {
left: -HALF_SIZE,
right: HALF_SIZE,
bottom: -HALF_SIZE,
top: HALF_SIZE,
near: -10.0 * HALF_SIZE,
far: 10.0 * HALF_SIZE,
..default()
},
illuminance: 10000.0,
shadows_enabled: true,
..default()
},
transform: Transform {
translation: Vec3::new(0.0, 2.0, 0.0),
rotation: Quat::from_euler(
EulerRot::XYZ,
(-15.0f32).to_radians(),
(40.0f32).to_radians(),
0.0,
),
..default()
},
..default()
});
// camera
commands.spawn_bundle(Camera3dBundle {
transform: Transform::from_xyz(-2.0, 2.5, 5.0)
.looking_at(Vec3::new(0.0, 1.0, 0.0), Vec3::Y),
..default()
});
}
/// 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!
impl Material for LambertMaterial {
fn fragment_shader() -> ShaderRef {
"shaders/lambert_material.wgsl".into()
}
}
// This is the struct that will be passed to your shader
#[derive(AsBindGroup, TypeUuid, Debug, Clone)]
#[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"]
pub struct LambertMaterial {
#[uniform(0)]
color: Color,
#[texture(1)]
#[sampler(2)]
color_texture: Option<Handle<Image>>,
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment