Last active
July 21, 2022 07:46
-
-
Save DGriffin91/c0e580502fd73314f976a46d9ca5b669 to your computer and use it in GitHub Desktop.
Bevy Lambert Material Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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