This updates the shield depth prepass from the Bevy 0.10 post to Bevy 0.14.
https://bevyengine.org/news/bevy-0-10/#depth-and-normal-prepass
This updates the shield depth prepass from the Bevy 0.10 post to Bevy 0.14.
https://bevyengine.org/news/bevy-0-10/#depth-and-normal-prepass
#import bevy_pbr::{ | |
mesh_view_bindings::{globals, view}, | |
prepass_utils, | |
forward_io::VertexOutput, | |
} | |
fn mod289(x: vec2<f32>) -> vec2<f32> { | |
return x - floor(x * (1. / 289.)) * 289.; | |
} | |
fn mod289_3(x: vec3<f32>) -> vec3<f32> { | |
return x - floor(x * (1. / 289.)) * 289.; | |
} | |
fn permute3(x: vec3<f32>) -> vec3<f32> { | |
return mod289_3(((x * 34.) + 1.) * x); | |
} | |
// MIT License. © Ian McEwan, Stefan Gustavson, Munrocket | |
fn simplexNoise2(v: vec2<f32>) -> f32 { | |
let C = vec4( | |
0.211324865405187, // (3.0-sqrt(3.0))/6.0 | |
0.366025403784439, // 0.5*(sqrt(3.0)-1.0) | |
-0.577350269189626, // -1.0 + 2.0 * C.x | |
0.024390243902439 // 1.0 / 41.0 | |
); | |
// First corner | |
var i = floor(v + dot(v, C.yy)); | |
let x0 = v - i + dot(i, C.xx); | |
// Other corners | |
var i1 = select(vec2(0., 1.), vec2(1., 0.), x0.x > x0.y); | |
// x0 = x0 - 0.0 + 0.0 * C.xx ; | |
// x1 = x0 - i1 + 1.0 * C.xx ; | |
// x2 = x0 - 1.0 + 2.0 * C.xx ; | |
var x12 = x0.xyxy + C.xxzz; | |
x12.x = x12.x - i1.x; | |
x12.y = x12.y - i1.y; | |
// Permutations | |
i = mod289(i); // Avoid truncation effects in permutation | |
var p = permute3(permute3(i.y + vec3(0., i1.y, 1.)) + i.x + vec3(0., i1.x, 1.)); | |
var m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), vec3(0.)); | |
m *= m; | |
m *= m; | |
// Gradients: 41 points uniformly over a line, mapped onto a diamond. | |
// The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) | |
let x = 2. * fract(p * C.www) - 1.; | |
let h = abs(x) - 0.5; | |
let ox = floor(x + 0.5); | |
let a0 = x - ox; | |
// Normalize gradients implicitly by scaling m | |
// Approximation of: m *= inversesqrt( a0*a0 + h*h ); | |
m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h); | |
// Compute final noise value at P | |
let g = vec3(a0.x * x0.x + h.x * x0.y, a0.yz * x12.xz + h.yz * x12.yw); | |
return 130. * dot(m, g); | |
} | |
fn rand2(n: vec2<f32>) -> f32 { | |
return fract(sin(dot(n, vec2<f32>(12.9898, 4.1414))) * 43758.5453); | |
} | |
fn noise2(n: vec2<f32>) -> f32 { | |
// let d = vec2<f32>(0., 1.); | |
// let b = floor(n); | |
// let f = smoothstep(vec2<f32>(0.), vec2<f32>(1.), fract(n)); | |
// return mix(mix(rand2(b), rand2(b + d.yx), f.x), mix(rand2(b + d.xy), rand2(b + d.yy), f.x), f.y); | |
return simplexNoise2(n); | |
} | |
// MIT License. © Inigo Quilez, Munrocket | |
// | |
fn fbm(p: vec2<f32>) -> f32 { | |
// var m2: mat2x2<f32> = mat2x2<f32>(vec2<f32>(0.8, 0.6), vec2<f32>(-0.6, 0.8)); | |
// var f: f32 = 0.; | |
// f = f + 0.5000 * noise2(p); | |
// var p = m2 * p * 2.02; | |
// f = f + 0.2500 * noise2(p); | |
// p = m2 * p * 2.03; | |
// f = f + 0.1250 * noise2(p); | |
// p = m2 * p * 2.01; | |
// f = f + 0.0625 * noise2(p); | |
// return f / 0.9375; | |
return fbm2(p, 1.0, 4u); | |
} | |
fn fbm2(x: vec2<f32>, H: f32, numOctaves: u32) -> f32 { | |
var G = exp2(-H); | |
var f = 1.0; | |
var a = 1.0; | |
var t = 0.0; | |
for(var i = 0u; i < numOctaves; i++ ) { | |
t += a*noise2(f*x); | |
f *= 2.0; | |
a *= G; | |
} | |
return t; | |
} | |
fn prepass_depth(frag_coord: vec4<f32>, sample_index: u32) -> f32 { | |
return bevy_pbr::prepass_utils::prepass_depth(frag_coord, sample_index); | |
} | |
@fragment | |
fn fragment( | |
#ifdef MULTISAMPLED | |
@builtin(sample_index) sample_index: u32, | |
#endif | |
@builtin(position) frag_coord: vec4<f32>, | |
@builtin(front_facing) is_front: bool, | |
@location(0) world_position: vec4<f32>, | |
@location(1) world_normal: vec3<f32>, | |
@location(2) uv: vec2<f32>, | |
) -> @location(0) vec4<f32> { | |
let emissive_intensity = 20.0; | |
let fresnel_color = vec3(0.5, 1.0, 1.0); | |
// var interesection_color = vec3(1.0, 0.0, 0.0); | |
var interesection_color = fresnel_color; | |
let offset = 0.92; | |
let fresnel_exp = 5.0; | |
let intersection_intensity = 10.0; | |
let noise_scale = 4.0; | |
let time_scale = 0.2; | |
let time = globals.time * time_scale; | |
let depth = prepass_depth(frag_coord, sample_index); | |
var intersection = 1.0 - ((frag_coord.z - depth) * 100.0) - offset; | |
intersection = smoothstep(0.0, 1.0, intersection); | |
if is_front{ | |
intersection *= intersection_intensity; | |
} else { | |
intersection *= intersection_intensity / 2.0; | |
} | |
let V = normalize(view.world_position.xyz - world_position.xyz); | |
var fresnel = 1.0 - dot(world_normal, V); | |
fresnel = pow(fresnel, fresnel_exp); | |
var a = 0.0; | |
a += fbm(uv * noise_scale + vec2(time)); | |
a += fbm(uv * noise_scale - vec2(time)); | |
// a = a * 0.5 + 0.5; | |
a = clamp(a, 0.0, 1.0); | |
// if a <= 0.0 { | |
// a = 0.1; | |
// } | |
a += intersection; | |
if is_front { | |
a += fresnel; | |
} | |
var color = intersection * interesection_color; | |
if is_front { | |
color += fresnel * fresnel_color; | |
} | |
color *= emissive_intensity; | |
if all(color <= vec3(1.0)) { | |
color += fresnel_color/emissive_intensity; | |
} | |
return vec4(color * a, 0.0); | |
} |
//! A simple 3D scene with light shining over a cube sitting on a plane. | |
use std::f32::consts::FRAC_PI_2; | |
use bevy::{ | |
core_pipeline::{ | |
bloom::BloomSettings, prepass::DepthPrepass, | |
}, | |
pbr::{NotShadowCaster, NotShadowReceiver}, | |
prelude::*, | |
render::render_resource::{ | |
AsBindGroup, ShaderRef, ShaderType, | |
}, | |
}; | |
fn main() { | |
App::new() | |
.add_plugins(( | |
DefaultPlugins, | |
MaterialPlugin::<ForceFieldMaterial>::default(), | |
MaterialPlugin::<PrepassOutputMaterial> { | |
prepass_enabled: false, | |
..default() | |
}, | |
)) | |
.add_systems(Startup, setup) | |
.add_systems(Update, update_show_prepass) | |
.run(); | |
} | |
/// set up a simple 3D scene | |
fn setup( | |
mut commands: Commands, | |
mut meshes: ResMut<Assets<Mesh>>, | |
mut materials: ResMut<Assets<StandardMaterial>>, | |
mut force_field_materials: ResMut< | |
Assets<ForceFieldMaterial>, | |
>, | |
mut depth_materials: ResMut< | |
Assets<PrepassOutputMaterial>, | |
>, | |
) { | |
// plane | |
commands.spawn(PbrBundle { | |
mesh: meshes | |
.add(Rectangle::from_size(Vec2::splat(5.0))), | |
material: materials.add(Color::srgb(0.3, 0.5, 0.3)), | |
transform: Transform::from_rotation( | |
Quat::from_rotation_x(-FRAC_PI_2), | |
), | |
..default() | |
}); | |
//cube | |
commands.spawn(PbrBundle { | |
mesh: meshes | |
.add(Cuboid::from_size(Vec3::splat(0.5))), | |
material: materials.add(Color::WHITE), | |
transform: Transform::from_xyz(0.0, 0.25, 0.0), | |
..default() | |
}); | |
// sphere | |
commands.spawn(( | |
MaterialMeshBundle { | |
mesh: meshes | |
.add(Sphere::new(1.25).mesh().uv(64, 64)), | |
material: force_field_materials | |
.add(ForceFieldMaterial {}), | |
transform: Transform::from_xyz(0.0, 0.5, 0.0) | |
.with_rotation(Quat::from_axis_angle( | |
Vec3::X, | |
std::f32::consts::FRAC_PI_2, | |
)), | |
..default() | |
}, | |
NotShadowReceiver, | |
NotShadowCaster, | |
)); | |
// Quad to show the depth prepass | |
commands.spawn(( | |
MaterialMeshBundle { | |
mesh: meshes.add(Rectangle::from_size( | |
Vec2::new(20.0, 20.0), | |
)), | |
material: depth_materials.add( | |
PrepassOutputMaterial { | |
settings: ShowPrepassSettings::default( | |
), | |
}, | |
), | |
transform: Transform::from_xyz( | |
-0.75, 1.25, 3.0, | |
) | |
.looking_at( | |
Vec3::new(2.0, -2.5, -5.0), | |
Vec3::Y, | |
), | |
..default() | |
}, | |
NotShadowCaster, | |
)); | |
// light | |
commands.spawn(PointLightBundle { | |
point_light: PointLight { | |
intensity: 1500.0, | |
shadows_enabled: true, | |
..default() | |
}, | |
transform: Transform::from_xyz(4.0, 8.0, 4.0), | |
..default() | |
}); | |
// camera | |
commands.spawn(( | |
Camera3dBundle { | |
camera: Camera { | |
hdr: true, | |
..default() | |
}, | |
transform: Transform::from_xyz(-2.0, 2.5, 5.0) | |
.looking_at(Vec3::ZERO, Vec3::Y), | |
..default() | |
}, | |
DepthPrepass, | |
BloomSettings::default(), | |
)); | |
} | |
// This is the struct that will be passed to your shader | |
#[derive(Asset, TypePath, AsBindGroup, Debug, Clone)] | |
pub struct ForceFieldMaterial {} | |
impl Material for ForceFieldMaterial { | |
fn fragment_shader() -> ShaderRef { | |
"shaders/force_field.wgsl".into() | |
} | |
fn alpha_mode(&self) -> AlphaMode { | |
AlphaMode::Add | |
} | |
fn specialize( | |
_pipeline: &bevy::pbr::MaterialPipeline<Self>, | |
descriptor: &mut bevy::render::render_resource::RenderPipelineDescriptor, | |
_layout: &bevy::render::mesh::MeshVertexBufferLayoutRef, | |
_key: bevy::pbr::MaterialPipelineKey<Self>, | |
) -> Result<(), bevy::render::render_resource::SpecializedMeshPipelineError>{ | |
descriptor.primitive.cull_mode = None; | |
Ok(()) | |
} | |
} | |
#[derive(Debug, Clone, Default, ShaderType)] | |
struct ShowPrepassSettings { | |
show_depth: u32, | |
show_normals: u32, | |
padding_1: u32, | |
padding_2: u32, | |
} | |
// This shader simply loads the prepass texture and outputs it directly | |
#[derive(Asset, TypePath, AsBindGroup, Debug, Clone)] | |
pub struct PrepassOutputMaterial { | |
#[uniform(0)] | |
settings: ShowPrepassSettings, | |
} | |
impl Material for PrepassOutputMaterial { | |
fn fragment_shader() -> ShaderRef { | |
"shaders/show_prepass.wgsl".into() | |
} | |
// This needs to be transparent in order to show the scene behind the mesh | |
fn alpha_mode(&self) -> AlphaMode { | |
AlphaMode::Blend | |
} | |
} | |
/// Every time you press space, it will cycle between transparent, depth and normals view | |
fn update_show_prepass( | |
keycode: Res<ButtonInput<KeyCode>>, | |
material_handle: Query<&Handle<PrepassOutputMaterial>>, | |
mut materials: ResMut<Assets<PrepassOutputMaterial>>, | |
) { | |
if keycode.just_pressed(KeyCode::Space) { | |
let handle = material_handle.single(); | |
let mat = materials.get_mut(handle).unwrap(); | |
if mat.settings.show_depth == 1 { | |
mat.settings.show_depth = 0; | |
} else { | |
mat.settings.show_depth = 1; | |
} | |
} | |
} |
(Sorry about that, but we can’t show files that are this big right now.)