diff --git a/assets/shaders/dissolve.wgsl b/assets/shaders/dissolve.wgsl new file mode 100644 index 0000000..fe54d38 --- /dev/null +++ b/assets/shaders/dissolve.wgsl @@ -0,0 +1,81 @@ +#import bevy_pbr::{ + pbr_fragment::pbr_input_from_standard_material, + forward_io::{VertexOutput, FragmentOutput}, + mesh_view_bindings::globals, + pbr_functions::{ + alpha_discard, + apply_pbr_lighting, + main_pass_post_lighting_processing + }, +} + +struct DissovleExtension { + percentage: f32, +} + +@group(1) @binding(100) +var dissolve: DissovleExtension; + +fn random(st: vec2) -> f32 { + var a = vec2(12.9898, 78.233); + var b = 43758.5453123; + return fract(sin(dot(st.xy, a)) * b); +} + +fn noise(st: vec2) -> f32 { + var i = floor(st); + var f = fract(st); + + var a = random(i); + var b = random(i + vec2(1.0, 0.0)); + var c = random(i + vec2(0.0, 1.0)); + var d = random(i + vec2(1.0, 1.0)); + + var u = smoothstep(vec2(0.0), vec2(1.0), f); + + return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y; +} + +const octaves: i32 = 6; + +fn fbm(st: vec2) -> f32 { + var _st = st; + var value = 0.0; + var amplitude = 0.5; + var frequency = 0.0; + + for (var i = 0 ; i < octaves; i++) { + value += amplitude * noise(_st); + _st *= 2.0; + amplitude *= 0.5; + } + + return value; +} + +@fragment +fn fragment( + in: VertexOutput, + @builtin(front_facing) is_front: bool, +) -> FragmentOutput { + var pbr_input = pbr_input_from_standard_material(in, is_front); + + var out: FragmentOutput; + out.color = apply_pbr_lighting(pbr_input); + + var pos = vec2(in.uv * 2.0); + + var n = fbm(pos); + + var cutoff = dissolve.percentage; + + if n > cutoff { + discard; + } + + if n > (cutoff - 0.01) { + out.color = vec4(0.0, 1.0, 1.0, 1.0); + } + + return out; +} \ No newline at end of file diff --git a/src/display3d.rs b/src/display3d.rs index 6135f54..5b25f65 100644 --- a/src/display3d.rs +++ b/src/display3d.rs @@ -12,9 +12,9 @@ use bevy::{ Skybox, }, input::mouse::{MouseButtonInput, MouseMotion, MouseScrollUnit, MouseWheel}, - pbr::{ScreenSpaceAmbientOcclusionBundle, ScreenSpaceAmbientOcclusionSettings}, + pbr::{ScreenSpaceAmbientOcclusionBundle, ScreenSpaceAmbientOcclusionSettings, MaterialExtension, ExtendedMaterial, OpaqueRendererMethod}, render::{ - render_resource::{TextureViewDescriptor, TextureViewDimension}, + render_resource::{TextureViewDescriptor, TextureViewDimension, ShaderRef,AsBindGroup}, view::ColorGrading, }, window::PrimaryWindow, @@ -25,7 +25,10 @@ pub(crate) struct Display3dPlugin; impl Plugin for Display3dPlugin { fn build(&self, app: &mut App) { - app.add_plugins(TemporalAntiAliasPlugin) + app.add_plugins(( + TemporalAntiAliasPlugin, + MaterialPlugin::::default(), + )) .insert_resource(Msaa::Off) .add_systems( OnExit(GameState::Loading), @@ -1246,43 +1249,90 @@ pub(super) mod tweaks { } } +/// Type expressing the extended material of standardMaterial + dissolveMaterial +type DissolveMaterial = ExtendedMaterial; + +/// Material extension for dissolving effect +#[derive(Asset, AsBindGroup, Reflect, Debug, Clone)] +struct DissolveExtension { + #[uniform(100)] + percentage: f32, +} + +impl MaterialExtension for DissolveExtension { + fn fragment_shader() -> ShaderRef { + "shaders/dissolve.wgsl".into() + } +} + +// Component for 'backing up' components which are temporarily not used +#[derive(Debug, Component, Clone)] +struct Backup(T); + /// When a piece is captured... /// 1. Play a cool "captured" animation and a neat sound /// 2. Move the piece to the side of the board /// 3. Play the same "captured" animation in reverse /// The animation is like a 'beam me up scotty' sorta thing. fn capture_piece( - mut events: Query, Added)>, + events: Query, Added)>, mut query: Query<(&mut Visibility, &mut Transform, &Side), (With, With)>, mut state: Local>, + standard_materials: ResMut>, + mut dissolve_materials: ResMut>, + object_standard_materials: Query<&Handle>, + object_dissolve_materials: Query<&Handle>, + backup_material: Query<&Backup>>, + children: Query<&Children>, mut commands: Commands, + time: Res