Skip to content

Instantly share code, notes, and snippets.

@ChristopherBiscardi
Last active July 8, 2024 20:16
Show Gist options
  • Save ChristopherBiscardi/04855aa6bb42d3cdd047a25243794f9d to your computer and use it in GitHub Desktop.
Save ChristopherBiscardi/04855aa6bb42d3cdd047a25243794f9d to your computer and use it in GitHub Desktop.
IceSentry Shield from Bevy 0.10 release post
#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;
}
}
}
View raw

(Sorry about that, but we can’t show files that are this big right now.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment