Repository: eliotbo/bevy_shadertoy_wgsl Branch: main Commit: e3221a81dd6f Files: 329 Total size: 32.9 MB Directory structure: gitextract_8_6g6_1p/ ├── .gitignore ├── Cargo.toml ├── LICENSES ├── README.md ├── assets/ │ └── shaders/ │ ├── clouds/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── dancing_tree/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── debugger/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── dry_ice/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── fire/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── fire2/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── fluid/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── image_load.wgsl │ ├── interactive_fluid_simulation/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── liquid/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── liquid_toy/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── love_and_domination/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── minimal/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── mip_fluid/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── mixing_liquid/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── molecular_dynamics/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── paint/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ ├── common.wgsl │ │ └── image.wgsl │ ├── paint2/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ ├── common.wgsl │ │ ├── image.wgsl │ │ └── image2.wgsl │ ├── paint_streams/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── paint_streams2/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── preludes/ │ │ └── image_prelude │ ├── protean_clouds/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── seascape/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── simpler_particles/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── simplest_detailed_fluid/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── soul/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ └── sunset/ │ ├── buffer_a.wgsl │ ├── buffer_b.wgsl │ ├── buffer_c.wgsl │ ├── buffer_d.wgsl │ └── image.wgsl ├── bin/ │ ├── assets/ │ │ └── shaders/ │ │ ├── image_load.wgsl │ │ ├── interactive_fluid_simulation/ │ │ │ ├── buffer_a.wgsl │ │ │ ├── buffer_b.wgsl │ │ │ ├── buffer_c.wgsl │ │ │ ├── buffer_d.wgsl │ │ │ └── image.wgsl │ │ ├── liquid/ │ │ │ ├── buffer_a.wgsl │ │ │ ├── buffer_b.wgsl │ │ │ ├── buffer_c.wgsl │ │ │ ├── buffer_d.wgsl │ │ │ └── image.wgsl │ │ ├── minimal/ │ │ │ ├── buffer_a.wgsl │ │ │ ├── buffer_b.wgsl │ │ │ ├── buffer_c.wgsl │ │ │ ├── buffer_d.wgsl │ │ │ └── image.wgsl │ │ ├── mixing_liquid/ │ │ │ ├── buffer_a.wgsl │ │ │ ├── buffer_b.wgsl │ │ │ ├── buffer_c.wgsl │ │ │ ├── buffer_d.wgsl │ │ │ └── image.wgsl │ │ ├── paint/ │ │ │ ├── buffer_a.wgsl │ │ │ ├── buffer_b.wgsl │ │ │ ├── buffer_c.wgsl │ │ │ ├── buffer_d.wgsl │ │ │ ├── common.wgsl │ │ │ └── image.wgsl │ │ ├── paint2/ │ │ │ ├── buffer_a.wgsl │ │ │ ├── buffer_b.wgsl │ │ │ ├── buffer_c.wgsl │ │ │ ├── buffer_d.wgsl │ │ │ ├── common.wgsl │ │ │ ├── image.wgsl │ │ │ └── image2.wgsl │ │ ├── paint_streams/ │ │ │ ├── buffer_a.wgsl │ │ │ ├── buffer_b.wgsl │ │ │ ├── buffer_c.wgsl │ │ │ ├── buffer_d.wgsl │ │ │ └── image.wgsl │ │ ├── preludes/ │ │ │ └── image_prelude │ │ └── simplest_detailed_fluid/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ └── image.wgsl │ ├── examples/ │ │ ├── minimal/ │ │ │ ├── buffer_a.wgsl │ │ │ ├── buffer_b.wgsl │ │ │ ├── buffer_c.wgsl │ │ │ ├── buffer_d.wgsl │ │ │ ├── common.wgsl │ │ │ └── image.wgsl │ │ ├── mixing_liquid/ │ │ │ ├── buffer_a.wgsl │ │ │ ├── buffer_b.wgsl │ │ │ ├── buffer_c.wgsl │ │ │ ├── buffer_d.wgsl │ │ │ ├── common.wgsl │ │ │ └── image.wgsl │ │ ├── paint/ │ │ │ ├── buffer_a.wgsl │ │ │ ├── buffer_b.wgsl │ │ │ ├── buffer_c.wgsl │ │ │ ├── buffer_d.wgsl │ │ │ ├── common.wgsl │ │ │ └── image.wgsl │ │ └── paint_streams/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ ├── common.wgsl │ │ └── image.wgsl │ ├── main.rs │ ├── templates/ │ │ ├── buffer_a_template.wgsl │ │ ├── buffer_b_template.wgsl │ │ ├── buffer_c_template.wgsl │ │ ├── buffer_d_template.wgsl │ │ ├── common.wgsl │ │ ├── common_prelude.wgsl │ │ ├── image.wgsl │ │ └── image_template.wgsl │ ├── test_renderdoc │ ├── test_renderdoc.d │ ├── texture_a.rs │ ├── texture_b.rs │ ├── texture_c.rs │ └── texture_d.rs ├── examples/ │ ├── debugger/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ ├── common.wgsl │ │ └── image.wgsl │ ├── dry_ice/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ ├── common.wgsl │ │ ├── dry_ice.rs │ │ └── image.wgsl │ ├── fire/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ ├── common.wgsl │ │ └── image.wgsl │ ├── fire2/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ ├── common.wgsl │ │ ├── fire2.rs │ │ └── image.wgsl │ ├── fluid/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ ├── common.wgsl │ │ ├── fluid.rs │ │ └── image.wgsl │ ├── liquid_toy/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ ├── common.wgsl │ │ ├── image.wgsl │ │ └── liquid_toy.rs │ ├── minimal/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ ├── common.wgsl │ │ ├── image.wgsl │ │ └── minimal.rs │ ├── paint/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ ├── common.wgsl │ │ ├── image.wgsl │ │ └── paint.rs │ ├── paint_streams/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ ├── common.wgsl │ │ ├── image.wgsl │ │ └── paint_streams.rs │ ├── protean_clouds/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ ├── common.wgsl │ │ ├── image.wgsl │ │ └── protean_clouds.rs │ ├── seascape/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ ├── common.wgsl │ │ ├── image.wgsl │ │ └── seascape.rs │ ├── simpler_particles/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ ├── common.wgsl │ │ ├── fps.rs │ │ ├── image.wgsl │ │ └── simpler_particles.rs │ ├── soul/ │ │ ├── buffer_a.wgsl │ │ ├── buffer_b.wgsl │ │ ├── buffer_c.wgsl │ │ ├── buffer_d.wgsl │ │ ├── common.wgsl │ │ ├── image.wgsl │ │ └── soul.rs │ └── sunset/ │ ├── buffer_a.wgsl │ ├── buffer_b.wgsl │ ├── buffer_c.wgsl │ ├── buffer_d.wgsl │ ├── common.wgsl │ ├── image.wgsl │ └── sunset.rs └── src/ ├── lib.rs ├── templates/ │ ├── buffer_a_template.wgsl │ ├── buffer_b_template.wgsl │ ├── buffer_c_template.wgsl │ ├── buffer_d_template.wgsl │ ├── common.wgsl │ ├── common_prelude.wgsl │ ├── debugger.wgsl │ ├── image.wgsl │ └── image_template.wgsl ├── texture_a.rs ├── texture_b.rs ├── texture_c.rs └── texture_d.rs ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Generated by Cargo # will have compiled files and executables /target/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk .cargo/config.toml ================================================ FILE: Cargo.toml ================================================ [package] name = "bevy_shadertoy_wgsl" version = "0.1.0" edition = "2021" authors = ["Eliot Bolduc"] [dependencies] bytemuck = "1.5" rand = "0.8" rand_pcg = "0.3" serde = { version = "1.0", features = ["derive"] } anyhow = "1.0" ron = "0.7" bitflags = "1.3" bevy = "0.8" crevice = "0.11" [[bin]] edition = "2021" name = "bevy_shadertoy_wgsl" path = "src/main.rs" # cargo build --release --target wasm32-unknown-unknown # wasm-bindgen --out-name wasm_shadertoy --out-dir wasm --target web target/wasm32-unknown-unknown/release/bevy_shadertoy_wgsl.wasm [[example]] name = "simpler_particles" path = "examples/simpler_particles/simpler_particles.rs" [[example]] name = "liquid_toy" path = "examples/liquid_toy/liquid_toy.rs" [[example]] name = "soul" path = "examples/soul/soul.rs" [[example]] name = "paint_streams" path = "examples/paint_streams/paint_streams.rs" [[example]] name = "minimal" path = "examples/minimal/minimal.rs" [[example]] name = "paint" path = "examples/paint/paint.rs" [[example]] name = "protean_clouds" path = "examples/protean_clouds/protean_clouds.rs" [[example]] name = "seascape" path = "examples/seascape/seascape.rs" [[example]] name = "fluid" path = "examples/fluid/fluid.rs" [[example]] name = "fire2" path = "examples/fire2/fire2.rs" [[example]] name = "fire" path = "examples/fire/fire.rs" [[example]] name = "dry_ice" path = "examples/dry_ice/dry_ice.rs" [[example]] name = "sunset" path = "examples/sunset/sunset.rs" ================================================ FILE: LICENSES ================================================ bevy_shadertoy_wgsl is dual-licensed under either * MIT License (docs/LICENSE-MIT or ) * Apache License, Version 2.0 (docs/LICENSE-APACHE or ) at your option. // // // // The licenses for the examples taken from shadertoy.com are the following: seascape -> Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. fire2 -> MIT License protean_clouds -> License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License sunset -> MIT License fluid -> License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License paint_streams -> License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License dry_ice -> License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 soul -> Attribution-NonCommercial 2.0 Generic (CC BY-NC 2.0) liquid_toy -> Attribution-NonCommercial 2.0 Generic (CC BY-NC 2.0) authors (full name or Shadertoy username): seascape -> TDM fire2 -> Ian McEwan, Ashima Arts protean_clouds -> nimitz sunset -> Dimas Leenman fluid -> Wyatt Flanders paint_streams -> michael0884 dry_ice -> David Gallardo soul -> leon liquid_toy -> leon MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. link to licenses: ================================================ FILE: README.md ================================================ # bevy_shadertoy_wgsl A Shadertoy clone for the Bevy game engine, where the glsl language is replaced by wgsl. Clone the repo, and for example run the following command: ``` cargo run --release --features bevy/dynamic --example paint_streams ``` ![](showcase.gif) Here is a GLSL to WGLSL converter that might be helpful: [https://eliotbo.github.io/glsl2wgsl/](https://eliotbo.github.io/glsl2wgsl/) TODO: make compatible with WASM See the LICENSES file for the individual examples. ================================================ FILE: assets/shaders/clouds/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let color = vec4(0.5); textureStore(buffer_a, location, color); } ================================================ FILE: assets/shaders/clouds/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/clouds/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/clouds/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/clouds/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // [[group(0), binding(1)]] // var buffer_a: texture_storage_2d; // [[group(0), binding(2)]] // var buffer_b: texture_storage_2d; // [[group(0), binding(3)]] // var buffer_c: texture_storage_2d; // [[group(0), binding(4)]] // var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; [[group(0), binding(6)]] var font_texture: texture_2d; [[group(0), binding(7)]] var font_texture_sampler: sampler; [[group(0), binding(8)]] var rgba_noise_256_texture: texture_2d; [[group(0), binding(9)]] var rgba_noise_256_texture_sampler: sampler; // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // let color = vec4(f32(0)); // textureStore(texture, location, color); // } // Sample Pinning // https://www.shadertoy.com/view/XdfXzn // MIT License var STRUCTURED: bool; var sundir: vec3; fn noise(x: vec3) -> f32 { var p: vec3 = floor(x); var f: vec3 = fract(x); f = f * f * (3. - 2. * f); let uv: vec2 = p.xy + vec2(37., 17.) * p.z + f.xy; // let rg: vec2 = textureLod(iChannel0, (uv + 0.5) / 256., 0.).yx; // let rg: vec2 = textureLoad(rgba_noise_256_texture, vec2((uv + 0.5) ), 0).yx; let rg: vec2 = textureSampleLevel( rgba_noise_256_texture, rgba_noise_256_texture_sampler, (uv + 0.5) / 256., 0. ).yx ; return mix(rg.x, rg.y, f.z); } fn map(p: vec3) -> vec4 { var d: f32 = 0.1 + 0.8 * sin(0.6 * p.z) * sin(0.5 * p.x) - p.y; var q: vec3 = p; var f: f32; f = 0.5 * noise(q); q = q * 2.02; f = f + (0.25 * noise(q)); q = q * 2.03; f = f + (0.125 * noise(q)); q = q * 2.01; f = f + (0.0625 * noise(q)); d = d + (2.75 * f); d = clamp(d, 0., 1.); var res: vec4 = vec4(d); var col: vec3 = 1.15 * vec3(1., 0.95, 0.8); col = col + (vec3(1., 0., 0.) * exp2(res.x * 10. - 10.)); var resxyz = res.xyz; resxyz = mix(col, vec3(0.7, 0.7, 0.7), res.x); res.x = resxyz.x; res.y = resxyz.y; res.z = resxyz.z; return res; } fn mysign(x: f32) -> f32 { if (x < 0.) { return -1.; } else { return 1.; }; } fn mysign2(x: vec2) -> vec2 { var x2: vec2; if (x.x < 0.) { x2.x = -1.; } else { x2.x =1.; }; if (x.y < 0.) { x2.y = -1.; } else { x2.y = 1.; } return x2; } fn SetupSampling(t: ptr>, dt: ptr>, wt: ptr>, ro: vec3, rd: vec3) { var rd_var = rd; if (!STRUCTURED) { (*dt) = vec2(1., 1.); (*t) = (*dt); (*wt) = vec2(0.5, 0.5); return ; } var n0: vec3; if (abs(rd_var.x) > abs(rd_var.z)) { n0 = vec3(1., 0., 0.); } else { n0 = vec3(0., 0., 1.); }; var n1: vec3 = vec3(mysign(rd_var.x * rd_var.z), 0., 1.); let ln: vec2 = vec2(length(n0), length(n1)); n0 = n0 / (ln.x); n1 = n1 / (ln.y); let ndotro: vec2 = vec2(dot(ro, n0), dot(ro, n1)); var ndotrd: vec2 = vec2(dot(rd_var, n0), dot(rd_var, n1)); let period: vec2 = ln * 1.; (*dt) = period / abs(ndotrd); let dist: vec2 = abs(ndotro / ndotrd); (*t) = -mysign2(ndotrd) * (ndotro % period) / abs(ndotrd); if (ndotrd.x > 0.) { (*t).x = (*t).x + ((*dt).x); } if (ndotrd.y > 0.) { (*t).y = (*t).y + ((*dt).y); } let minperiod: f32 = 1.; let maxperiod: f32 = sqrt(2.) * 1.; (*wt) = smoothStep(vec2(maxperiod), vec2(minperiod), (*dt) / ln); (*wt) = (*wt) / ((*wt).x + (*wt).y); } fn raymarch(ro: vec3, rd: vec3) -> vec4 { var sum: vec4 = vec4(0., 0., 0., 0.); var t: vec2; var dt: vec2; var wt: vec2; SetupSampling(&t, &dt, &wt, ro, rd); let f: f32 = 0.6; let endFade: f32 = f * f32(40.) * 1.; let startFade: f32 = 0.8 * endFade; for (var i: i32 = 0; i < 40; i = i + 1) { if (sum.a > 0.99) { continue; } var data: vec4; if (t.x < t.y) { data = vec4(t.x, wt.x, dt.x, 0.); } else { data = vec4(t.y, wt.y, 0., dt.y); }; let pos: vec3 = ro + data.x * rd; var w: f32 = data.y; t = t + (data.zw); w = w * (smoothStep(endFade, startFade, data.x)); var col: vec4 = map(pos); let dif: f32 = clamp((col.w - map(pos + 0.6 * sundir).w) / 0.6, 0., 1.); let lin: vec3 = vec3(0.51, 0.53, 0.63) * 1.35 + 0.55 * vec3(0.85, 0.57, 0.3) * dif; var colxyz = col.xyz; colxyz = col.xyz * (lin); col.x = colxyz.x; col.y = colxyz.y; col.z = colxyz.z; var colxyz = col.xyz; colxyz = col.xyz * (col.xyz); col.x = colxyz.x; col.y = colxyz.y; col.z = colxyz.z; col.a = col.a * (0.75); var colrgb = col.rgb; colrgb = col.rgb * (col.a); col.r = colrgb.r; col.g = colrgb.g; col.b = colrgb.b; sum = sum + (col * (1. - sum.a) * w); } var sumxyz = sum.xyz; sumxyz = sum.xyz / (0.001 + sum.w); sum.x = sumxyz.x; sum.y = sumxyz.y; sum.z = sumxyz.z; return clamp(sum, vec4(0.), vec4(1.)); } fn sky(rd: vec3) -> vec3 { var col: vec3 = vec3(0.); let hort: f32 = 1. - clamp(abs(rd.y), 0., 1.); col = col + (0.5 * vec3(0.99, 0.5, 0.) * exp2(hort * 8. - 8.)); col = col + (0.1 * vec3(0.5, 0.9, 1.) * exp2(hort * 3. - 3.)); col = col + (0.55 * vec3(0.6, 0.6, 0.9)); let sun: f32 = clamp(dot(sundir, rd), 0., 1.); col = col + (0.2 * vec3(1., 0.3, 0.2) * pow(sun, 2.)); col = col + (0.5 * vec3(1., 0.9, 0.9) * exp2(sun * 650. - 650.)); col = col + (0.1 * vec3(1., 1., 0.1) * exp2(sun * 100. - 100.)); col = col + (0.3 * vec3(1., 0.7, 0.) * exp2(sun * 50. - 50.)); col = col + (0.5 * vec3(1., 0.3, 0.05) * exp2(sun * 10. - 10.)); let ax: f32 = atan2(rd.y, length(rd.xz)) / 1.; let ay: f32 = atan2(rd.z, rd.x) / 2.; var st: f32 = textureLoad(rgba_noise_256_texture, vec2(vec2(ax, ay) * 255.), 0 ).x; let st2: f32 = textureLoad(rgba_noise_256_texture, vec2(0.25 * vec2(ax, ay) * 255.), 0 ).x; st = st * (st2); st = smoothStep(0.65, 0.9, st); col = mix(col, col + 1.8 * st, clamp(1. - 1.1 * length(col), 0., 1.)); return col; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var fragColor: vec4; var fragCoord = vec2(f32(location.x), f32(location.y) ); STRUCTURED = uni.iMouse.z <= 0.; sundir = normalize(vec3(-1., 0., -1.)); let q: vec2 = fragCoord.xy / uni.iResolution.xy; var p: vec2 = -1. + 2. * q; p.x = p.x * (uni.iResolution.x / uni.iResolution.y); let mo: vec2 = -1. + 2. * uni.iMouse.xy / uni.iResolution.xy; let lookDir: vec3 = vec3(cos(0.53 * uni.iTime), 0., sin(uni.iTime)); let camVel: vec3 = vec3(-20., 0., 0.); let ro: vec3 = vec3(0., 1.5, 0.) + uni.iTime * camVel; let ta: vec3 = ro + lookDir; let ww: vec3 = normalize(ta - ro); let uu: vec3 = normalize(cross(vec3(0., 1., 0.), ww)); let vv: vec3 = normalize(cross(ww, uu)); let fov: f32 = 1.; let rd: vec3 = normalize(fov * p.x * uu + fov * 1.2 * p.y * vv + 1.5 * ww); var clouds: vec4 = raymarch(ro, rd); var col: vec3 = clouds.xyz; if (clouds.w <= 0.99) { col = mix(sky(rd), col, clouds.w); } col = clamp(col, vec3(0.), vec3(1.)); col = smoothStep(vec3(0.), vec3(1.), col); col = col * (pow(16. * q.x * q.y * (1. - q.x) * (1. - q.y), 0.12)); // (*fragColor) = vec4(col, 1.); textureStore(texture, y_inverted_location, vec4(col, 1.)); let test: vec4 = textureSampleLevel( rgba_noise_256_texture, rgba_noise_256_texture_sampler, vec2(location) / R * 2.0, 0. ) ; // textureStore(texture, y_inverted_location, test); } // [[stage(compute), workgroup_size(8, 8, 1)]] // fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { // let R: vec2 = uni.iResolution.xy; // let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // if (uni.iMouse.z > 0.) { useNewApproach = false; } // let q: vec2 = fragCoord.xy / uni.iResolution.xy; // var p: vec2 = -1. + 2. * q; // p.x = p.x * (uni.iResolution.x / uni.iResolution.y); // let mo: vec2 = -1. + 2. * uni.iMouse.xy / uni.iResolution.xy; // let ro: vec3 = vec3(0., 1.9, 0.) + uni.iTime * camVel; // let ta: vec3 = ro + lookDir; // let ww: vec3 = normalize(ta - ro); // let uu: vec3 = normalize(cross(vec3(0., 1., 0.), ww)); // let vv: vec3 = normalize(cross(ww, uu)); // let rd: vec3 = normalize(p.x * uu + 1.2 * p.y * vv + 1.5 * ww); // var col: vec3 = sky(rd); // let rd_layout: vec3 = rd / mix(dot(rd, ww), 1., samplesCurvature); // let clouds: vec4 = raymarch(ro, rd_layout); // col = mix(col, clouds.xyz, clouds.w); // col = clamp(col, 0., 1.); // col = smoothStep(0., 1., col); // col = col * (pow(16. * q.x * q.y * (1. - q.x) * (1. - q.y), 0.12)); // // (*fragColor) = vec4(col, 1.); // textureStore(texture, y_inverted_location, vec4(col, 1.)); // } ================================================ FILE: assets/shaders/dancing_tree/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let color = vec4(0.5); textureStore(buffer_a, location, color); } ================================================ FILE: assets/shaders/dancing_tree/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/dancing_tree/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/dancing_tree/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/dancing_tree/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; [[group(0), binding(6)]] var font_texture: texture_2d; [[group(0), binding(7)]] var font_texture_sampler: sampler; [[group(0), binding(8)]] var rgba_noise_256_texture: texture_2d; [[group(0), binding(9)]] var rgba_noise_256_texture_sampler: sampler; // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // let color = vec4(f32(0)); // textureStore(texture, location, color); // } // Why are the characters so pixelated? // One possible reason is that we are in a compute shader and the textures are not // filtered. let backColorDebug: vec3 = vec3(0.2, 0.2, 0.2); var uv_debug: vec2 ; var tp_debug: vec2 ; var align_debug: vec4; // north, east, south, west var font_size_debug: f32; var dotColor_debug: vec3 = vec3(0.5, 0.5, 0.); var drawColorDebug: vec3 = vec3(1., 1., 0.); var vColor: vec3 = backColorDebug; var aspect_debug: f32 = 1.; var pixelPosDebug: vec2 = vec2(0., 0.); let FONT_SPACE_DEBUG: f32 = 0.5; let headColorDebug: vec3 = vec3(0.9, 0.6, 0.2); let mpColorDebug: vec3 = vec3(0.99, 0.99, 0.); let mxColorDebug: vec3 = vec3(1., 0., 0.); let myColorDebug: vec3 = vec3(0., 1., 0.); let font_png_size_debug: vec2 = vec2(1023.0, 1023.0); fn char(ch: i32) -> f32 { let fr = fract(floor(vec2(f32(ch), 15.999 - f32(ch) / 16.)) / 16.); let q = clamp(tp_debug, vec2(0.), vec2(1.)) / 16. + fr ; let inverted_q = vec2(q.x, 1. - q.y); // // There is aliasing on the characters // let f = textureSampleGrad(font_texture, // font_texture_sampler, // inverted_q, // vec2(1.0, 0.0), // vec2(0.0, 1.0)); // using textureLoad without sampler let q1 = vec2(font_png_size_debug * q ); let y_inverted_q1 = vec2(q1.x, i32(font_png_size_debug.y) - q1.y); var f: vec4 = textureLoad(font_texture, y_inverted_q1 , 0); // smoothing out the aliasing let dx = vec2(1, 0); let dy = vec2(0, 1); let fx1: vec4 = textureLoad(font_texture, y_inverted_q1 + dx, 0); let fx2: vec4 = textureLoad(font_texture, y_inverted_q1 - dx, 0); let fy1: vec4 = textureLoad(font_texture, y_inverted_q1 + dy, 0); let fy2: vec4 = textureLoad(font_texture, y_inverted_q1 - dy, 0); let rp = 0.25; f = f * rp + (1.0 - rp) * (fx1 + fx2 + fy1 + fy2) / 4.0 ; return f.x * (f.y + 0.3) * (f.z + 0.3) * 2.; } fn SetTextPosition(x: f32, y: f32) { tp_debug = 10. * uv_debug; tp_debug.x = tp_debug.x + 17. - x; tp_debug.y = tp_debug.y - 9.4 + y; } fn SetTextPositionAbs(x: f32, y: f32) { tp_debug.x = 10. * uv_debug.x - x; tp_debug.y = 10. * uv_debug.y - y; } fn drawFract(value: ptr, digits: ptr) -> f32 { var c: f32 = 0.; *value = fract(*value) * 10.; for (var ni: i32 = 1; ni < 60; ni = ni + 1) { c = c + (char(48 + i32(*value))); tp_debug.x = tp_debug.x - (0.5); *digits = *digits - (1); *value = fract(*value) * 10.; if (*digits <= 0 || *value == 0.) { break; } } tp_debug.x = tp_debug.x - (0.5 * f32(*digits)); return c; } fn maxInt(a: i32, b: i32) -> i32 { var ret: i32; if (a > b) { ret = a; } else { ret = b; }; return ret; } fn drawInt(value: ptr, minDigits: ptr) -> f32 { var c: f32 = 0.; if (*value < 0) { *value = -*value; if (*minDigits < 1) { *minDigits = 1; } else { *minDigits = *minDigits - 1; } c = c + (char(45)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); } var fn2: i32 = *value; var digits: i32 = 1; for (var ni: i32 = 0; ni < 10; ni = ni + 1) { fn2 = fn2 / (10); if (fn2 == 0) { break; } digits = digits + 1; } digits = maxInt(*minDigits, digits); tp_debug.x = tp_debug.x - (0.5 * f32(digits)); for (var ni: i32 = 1; ni < 11; ni = ni + 1) { tp_debug.x = tp_debug.x + (0.5); c = c + (char(48 + *value % 10)); *value = *value / (10); if (ni >= digits) { break; } } tp_debug.x = tp_debug.x - (0.5 * f32(digits)); return c; } fn drawIntBackwards(value: ptr, minDigits: ptr) -> f32 { var c: f32 = 0.; let original_value: i32 = *value; if (*value < 0) { *value = -*value; if (*minDigits < 1) { *minDigits = 1; } else { *minDigits = *minDigits - 1; } // tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); // c = c + (char(45)); } var fn2: i32 = *value; var digits: i32 = 1; for (var ni: i32 = 0; ni < 10; ni = ni + 1) { fn2 = fn2 / (10); if (fn2 == 0) { break; } digits = digits + 1; } digits = maxInt(*minDigits, digits); // tp_debug.x = tp_debug.x - (0.5 * f32(digits)); for (var ni: i32 = digits - 1; ni < 11; ni = ni - 1) { tp_debug.x = tp_debug.x + (0.5); c = c + (char(48 + *value % 10)); *value = *value / (10); if (ni == 0) { break; } } if (original_value < 0) { tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); c = c + (char(45)); } // tp_debug.x = tp_debug.x + (0.5 * f32(digits)); return c; } // fn drawFloat(value: ptr, prec: ptr, maxDigits: i32) -> f32 { fn drawFloat(val: f32, prec: ptr, maxDigits: i32) -> f32 { // in case of 0.099999..., round up to 0.1000000 var value = round(val * pow(10., f32(maxDigits))) / pow(10., f32(maxDigits)); let tp_debugx: f32 = tp_debug.x - 0.5 * f32(maxDigits); var c: f32 = 0.; if (value < 0.) { c = char(45); value = -value; } tp_debug.x = tp_debug.x - (0.5); var ival = i32(value); var one: i32 = 1; c = c + (drawInt(&ival, &one)); c = c + (char(46)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); var frac_val = fract(value); c = c + (drawFract(&frac_val, prec)); tp_debug.x = min(tp_debug.x, tp_debugx); return c; } fn drawFloat_f32(value: f32) -> f32 { var two: i32 = 2; return drawFloat(value, &two, 5); } fn drawFloat_f32_prec(value: f32, prec: ptr) -> f32 { return drawFloat(value, prec, 2); } fn drawInt_i32_back(value: ptr) -> f32 { var one: i32 = 1; return drawIntBackwards(value, &one); } fn drawInt_i32(value: ptr) -> f32 { var one: i32 = 1; return drawInt(value, &one); } fn SetColor(red: f32, green: f32, blue: f32) { drawColorDebug = vec3(red, green, blue); } fn WriteFloat(fValue: f32, maxDigits: i32, decimalPlaces: ptr) { // vColor = mix(vColor, drawColorDebug, drawFloat_f32_prec(fValue, decimalPlaces)); vColor = mix(vColor, drawColorDebug, drawFloat(fValue, decimalPlaces, maxDigits)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); ; } fn WriteFloatBox( fValue: f32, maxDigits: i32, decimalPlaces: i32, alpha: f32 ) { var decs = decimalPlaces; vColor = mix(vColor, drawColorDebug, drawFloat(fValue, &decs, maxDigits) * alpha); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); ; } fn WriteInteger(iValue: ptr) { vColor = mix(vColor, drawColorDebug, drawInt_i32(iValue)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); } fn WriteIntegerBack(iValue: ptr) { vColor = mix(vColor, drawColorDebug, drawInt_i32_back(iValue)); tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); } fn WriteFPS() { var fps: f32 = f32(uni.iSampleRate); SetColor(0.8, 0.6, 0.3); var max_digits_one = 1; WriteFloat(fps, 5, &max_digits_one); var c: f32 = 0.; c = c + (char(102)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(112)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(115)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); // let c2 = smoothStep(0.0, 1.0, c ); vColor = mix(vColor, drawColorDebug, c); } fn WriteMousePos(mPos: vec2, y_pos: f32) { let digits: i32 = 3; let radius: f32 = uni.iResolution.x / 400.; if (uni.iMouse.z > 0.) { dotColor_debug = mpColorDebug; } let r: f32 = length(abs(mPos.xy) - pixelPosDebug) - radius; // vColor = vColor + (mix(vec3(0.), dotColor_debug, 1. - clamp(r, 0., 1.))); var max_digits_three: i32 = 3; var mposxi: i32 = i32(mPos.x); var mposyi: i32 = i32(mPos.y); var mposx: f32 = (mPos.x); var mposy: f32 = (mPos.y); let x_pos = align_debug.y - 1. * FONT_SPACE_DEBUG; SetTextPositionAbs( x_pos, y_pos, ); drawColorDebug = myColorDebug; WriteIntegerBack(&mposyi); SetTextPositionAbs( x_pos - 7. * FONT_SPACE_DEBUG, y_pos, ); drawColorDebug = mxColorDebug; WriteIntegerBack(&mposxi); } fn sdRoundedBox(p: vec2, b: vec2, r: vec4) -> f32 { var x = r.x; var y = r.y; x = select(r.z, r.x, p.x > 0.); y = select(r.w, r.y, p.x > 0.); x = select(y, x, p.y > 0.); let q = abs(p) - b + x; return min(max(q.x, q.y), 0.) + length(max(q, vec2(0.))) - x; } fn WriteRGBAValues( location: vec2, value: vec4, screen_poz: vec2, alpha: f32, ) { let poz = screen_poz / uni.iResolution * 20. * vec2(aspect_debug, 1.0); let window_ajusted = uni.iResolution / vec2(960., 600.); let box_pos = vec2(align_debug.w, align_debug.x - FONT_SPACE_DEBUG ) / 10.; // let box_pos = mp; // // box location follows mouse position // let box_location = vec2( // uni.iMouse.x + 100. * window_ajusted.x / ( aspect_debug / 1.6 ) , // uni.iMouse.y - 48. * window_ajusted.y // ); let box_location = vec2( 100. * window_ajusted.x / ( aspect_debug / 1.6 ) , uni.iResolution.y - 60. * window_ajusted.y, ); let inverted_screen_poz = vec2(screen_poz.x, -screen_poz.y) ; // / vec2(aspect_debug, 1.) ; let d_box = sdRoundedBox( vec2(location) - box_location - inverted_screen_poz, vec2(73. / ( aspect_debug / 1.6 ), 75.) * window_ajusted, vec4(5.,5.,5.,5.) * 5.0 ); // let alpha = 0.225; let decimal_places = 3; SetColor(1., 1., 1.); var c: f32 = 0.; let lspace = 0.8; let bg_color = vec3(.8, .7, .9); vColor = mix( vColor, bg_color, (1.0 - step(0.0, d_box)) * alpha ); // red SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1.) - 0.0 + poz.y ) ; c = c + (char(114)); // r tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.r, 3, decimal_places, alpha ); // green SetTextPosition( 10. * ((box_pos.x +1. + lspace)) + poz.x, 10. * (-box_pos.y +1. ) + 1.0 + poz.y, ) ; c = c + (char(103)); // g tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.g, 3, decimal_places, alpha ); // blue SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1. ) + 2.0 + poz.y, ) ; c = c + (char(98)); // b tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.b, 4, decimal_places, alpha ); // alpha SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1. ) + 3.0 + poz.y, ) ; c = c + (char(97)); // a tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.a, 4, decimal_places, alpha ); vColor = mix(vColor, drawColorDebug, c * alpha); } fn sdSegment(p: vec2, a: vec2, b: vec2) -> f32 { let pa = p - a; let ba = b - a; let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.); return length(pa - ba * h); } fn ring(pos: vec2, radius: f32, thick: f32) -> f32 { return mix(1., 0., smoothStep(thick, thick + 0.01, abs(length(uv_debug - pos) - radius))); } fn sdCircle(p: vec2, c: vec2, r: f32) -> f32 { let d = length(p - c); return d - r; } fn draw_ring(location: vec2) { let mouse_click_poz = vec2(abs(uni.iMouse.z) , abs(uni.iMouse.w)); let alpha = 0.75; let ring_dist = sdCircle(vec2(location) , mouse_click_poz, 2.3); let d = smoothStep(0.5, 1.5, abs(ring_dist - 1.)); vColor = mix(vColor, headColorDebug, (1. - d) * alpha ); } fn draw_crossair(location: vec2) { let start = 5.0; let end = 20.; let segment1 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(start, 0.), vec2(end, 0.) ); let segment2 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(-start, 0.), vec2(-end, 0.) ); let segment3 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(0., start), vec2(0., end) ); let segment4 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(0., -start), vec2(0., -end) ); var alpha = 0.75; if (uni.iMouse.z > 0.) { alpha = 1.0; } let d = smoothStep(0.5, 1.5, segment1); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothStep(0.5, 1.5, segment2); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothStep(0.5, 1.5, segment3); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothStep(0.5, 1.5, segment4); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); } fn show_debug_info(location: vec2, color: vec3) -> vec4 { var fragCoord = vec2(f32(location.x), f32(location.y) ); vColor = color; aspect_debug = uni.iResolution.x / uni.iResolution.y; let ratio: vec2 = vec2(aspect_debug, 1.); pixelPosDebug = fragCoord.xy; // mousePosDebug = uni.iMouse.xy; uv_debug = (2. * fragCoord.xy / uni.iResolution.xy - 1.) * ratio; align_debug = 10. * vec4( 1., // North aspect_debug, // East -1., // South -aspect_debug, // West ); WriteMousePos(uni.iMouse.zw, align_debug.z + 2.0 * FONT_SPACE_DEBUG); // Click position WriteMousePos(uni.iMouse.xy, align_debug.z + 0.2 * FONT_SPACE_DEBUG); // Current mouse position var c: f32 = 0.; SetTextPositionAbs( align_debug.y - FONT_SPACE_DEBUG, align_debug.x - 2. * FONT_SPACE_DEBUG, ); SetColor(0.8, 0.8, 0.8); var resx = i32(uni.iResolution.x); var resy = i32(uni.iResolution.y); WriteIntegerBack(&resx); c = c + (char(28)); tp_debug.x = tp_debug.x + 0. * (FONT_SPACE_DEBUG); WriteIntegerBack(&resy); SetTextPositionAbs( align_debug.w - 1. * FONT_SPACE_DEBUG, align_debug.z - 0. * FONT_SPACE_DEBUG, ); WriteFPS(); SetColor(0.9, 0.7, 0.8); let fragColor = vec4(vColor, 1.); let poz = vec2(0., uni.iResolution.y / 2.); // // RGBA probe labels follow mouse // let poz = vec2(uni.iMouse.x , uni.iResolution.y - uni.iMouse.y); let inverted_y_mouse_location = vec2(vec2(uni.iMouse.x, uni.iResolution.y - uni.iMouse.y)); let value: vec4 = textureLoad(texture, inverted_y_mouse_location); WriteRGBAValues(location, value, poz, 0.85); let inverted_y_mouseclick_location = vec2(vec2(abs(uni.iMouse.z), uni.iResolution.y - abs(uni.iMouse.w))); let value2: vec4 = textureLoad(texture, inverted_y_mouseclick_location); WriteRGBAValues(location, value2, vec2(0.), 0.65); draw_crossair(location); draw_ring(location); let fragColor = vec4(vColor, 1.); return fragColor; } // displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a // here // TODO: // // 1. ar light: vec3; for global variables // // 2. p.xy = ... // pattern -> // var pxy = p.xy; // pxy = pxy * matrix; // p.x = pxy.x; // p.y = pxy.y ; let pi = 3.1415926; type v2 = vec2; var light: vec3; fn ln(p2: vec3, a: vec3, b: vec3, R: f32) -> f32 { var r: f32 = dot(p2 - a, b - a) / dot(b - a, b - a); r = clamp(r, 0., 1.); var p = p2; p.x = p.x + (0.2 * sqrt(R) * smoothStep(1., 0., abs(r * 2. - 1.)) * cos(pi * (2. * uni.iTime))); return length(p - a - (b - a) * r) - R * (1.5 - 0.4 * r); } fn ro(a: f32) -> mat2x2 { let s: f32 = sin(a); let c: f32 = cos(a); return mat2x2(c, -s, s, c); } fn map(p2: vec3) -> f32 { var p = p2; var l: f32 = length(p - light) - 0.01; l = min(l, abs(p.y + 0.4) - 0.01); l = min(l, abs(p.z - 0.4) - 0.01); l = min(l, abs(p.x - 0.7) - 0.01); p.y = p.y + (0.4); p.z = p.z + (0.1); var pzx = p.zx; pzx = pzx * ro(0.1 * uni.iTime); p.z = pzx.x; p.x = pzx.y; var rl: vec2 = vec2(0.02, 0.25 + 0.01 * sin(pi * 4. * uni.iTime)); for (var i: i32 = 1; i < 11; i = i + 1) { l = min(l, ln(p, vec3(0.), vec3(0., rl.y, 0.), rl.x)); p.y = p.y - (rl.y); var pxy = p.xy; pxy = pxy * (ro(0.2 * sin(3.1 * uni.iTime + f32(i)) + sin(0.222 * uni.iTime) * (-0.1 * sin(0.4 * pi * uni.iTime) + sin(0.543 * uni.iTime) / max(f32(i), 2.)))); p.x = pxy.x; p.y = pxy.y ; p.x = abs(p.x); var pxy = p.xy; pxy = pxy *(ro(0.6 + 0.4 * sin(uni.iTime) * sin(0.871 * uni.iTime) + 0.05 * f32(i) * sin(2. * uni.iTime))); p.x = pxy.x ; p.y = pxy.y ; var pzx = p.zx; pzx = pzx * (ro(0.5 * pi + 0.2 * sin(0.5278 * uni.iTime) + 0.8 * f32(i) * (sin(0.1 * uni.iTime) * (sin(0.1 * pi * uni.iTime) + sin(0.333 * uni.iTime) + 0.2 * sin(1.292 * uni.iTime))))); p.z = pzx.x; p.x = pzx.y; rl = rl * (0.7 + 0.015 * f32(i) * (sin(uni.iTime) + 0.1 * sin(4. * pi * uni.iTime))); l = min(l, length(p) - 0.15 * sqrt(rl.x)); } return l; } fn march(p2: vec3, d: vec3) -> vec3 { let o: f32 = 1000.; var p = p2; for (var i: i32 = 0; i < 24; i = i + 1) { let l: f32 = map(p); p = p + (l * d); if (l < 0.001) { break; } } return p; } fn norm(p: vec3) -> vec3 { let e: vec2 = vec2(0.001, 0.); return normalize(vec3(map(p + e.xyy) - map(p - e.xyy), map(p + e.yxy) - map(p - e.yxy), map(p + e.yyx) - map(p - e.yyx))); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); light = vec3(0.2 * sin(uni.iTime), 0.5, -0.5); if (uni.iMouse.z > 0.) { light = vec3(vec2(-0.5, 0.5) * 0. + 0.7 * (uni.iMouse.xy - 0.5 * R) / R.y, -0.3); } var U = (vec2(location) - 0.5 * R) / R.y; // U = vec2(U.x, -U.y); var p: vec3 = vec3(0., 0., -1.); var d: vec3 = normalize(vec3(U, 1.)); p = march(p, d); let n: vec3 = norm(p); var C = 0.6 + 0.4 * sin(1.1 * vec4(1., 2., 3., 4.) * dot(d, n)); let D: vec3 = light - p; d = normalize(D); let lp: vec3 = march(p + d * 0.01, d); C = C * (2.5 * dot(d, n) * (0.3 + 0.7 * length(lp - p) / length(light - p))); C = atan(C) / pi * 2.; textureStore(texture, y_inverted_location, C); } ================================================ FILE: assets/shaders/debugger/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // Converts a color from sRGB gamma to linear light gamma fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let color = vec4(0.5); textureStore(buffer_a, location, color); } ================================================ FILE: assets/shaders/debugger/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // Converts a color from sRGB gamma to linear light gamma fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/debugger/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // Converts a color from sRGB gamma to linear light gamma fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/debugger/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // Converts a color from sRGB gamma to linear light gamma fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/debugger/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; [[group(0), binding(6)]] var font_texture: texture_2d; [[group(0), binding(7)]] var font_texture_sampler: sampler; // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // let color = vec4(f32(0)); // textureStore(texture, location, color); // } // Why are the characters so pixelated? // One possible reason is that we are in a compute shader and the textures are not // filtered. let backColorDebug: vec3 = vec3(0.2, 0.2, 0.2); var uv_debug: vec2 ; var tp_debug: vec2 ; var align_debug: vec4; // north, east, south, west var font_size_debug: f32; var dotColor_debug: vec3 = vec3(0.5, 0.5, 0.); var drawColorDebug: vec3 = vec3(1., 1., 0.); var vColor: vec3 = backColorDebug; var aspect_debug: f32 = 1.; var pixelPosDebug: vec2 = vec2(0., 0.); let FONT_SPACE_DEBUG: f32 = 0.5; let headColorDebug: vec3 = vec3(0.9, 0.6, 0.2); let mpColorDebug: vec3 = vec3(0.99, 0.99, 0.); let mxColorDebug: vec3 = vec3(1., 0., 0.); let myColorDebug: vec3 = vec3(0., 1., 0.); let font_png_size_debug: vec2 = vec2(1023.0, 1023.0); fn char(ch: i32) -> f32 { let fr = fract(floor(vec2(f32(ch), 15.999 - f32(ch) / 16.)) / 16.); let q = clamp(tp_debug, vec2(0.), vec2(1.)) / 16. + fr ; let inverted_q = vec2(q.x, 1. - q.y); // // There is aliasing on the characters // let f = textureSampleGrad(font_texture, // font_texture_sampler, // inverted_q, // vec2(1.0, 0.0), // vec2(0.0, 1.0)); // using textureLoad without sampler let q1 = vec2(font_png_size_debug * q ); let y_inverted_q1 = vec2(q1.x, i32(font_png_size_debug.y) - q1.y); var f: vec4 = textureLoad(font_texture, y_inverted_q1 , 0); // smoothing out the aliasing let dx = vec2(1, 0); let dy = vec2(0, 1); let fx1: vec4 = textureLoad(font_texture, y_inverted_q1 + dx, 0); let fx2: vec4 = textureLoad(font_texture, y_inverted_q1 - dx, 0); let fy1: vec4 = textureLoad(font_texture, y_inverted_q1 + dy, 0); let fy2: vec4 = textureLoad(font_texture, y_inverted_q1 - dy, 0); let rp = 0.25; f = f * rp + (1.0 - rp) * (fx1 + fx2 + fy1 + fy2) / 4.0 ; return f.x * (f.y + 0.3) * (f.z + 0.3) * 2.; } fn SetTextPosition(x: f32, y: f32) { tp_debug = 10. * uv_debug; tp_debug.x = tp_debug.x + 17. - x; tp_debug.y = tp_debug.y - 9.4 + y; } fn SetTextPositionAbs(x: f32, y: f32) { tp_debug.x = 10. * uv_debug.x - x; tp_debug.y = 10. * uv_debug.y - y; } fn drawFract(value: ptr, digits: ptr) -> f32 { var c: f32 = 0.; *value = fract(*value) * 10.; for (var ni: i32 = 1; ni < 60; ni = ni + 1) { c = c + (char(48 + i32(*value))); tp_debug.x = tp_debug.x - (0.5); *digits = *digits - (1); *value = fract(*value) * 10.; if (*digits <= 0 || *value == 0.) { break; } } tp_debug.x = tp_debug.x - (0.5 * f32(*digits)); return c; } fn maxInt(a: i32, b: i32) -> i32 { var ret: i32; if (a > b) { ret = a; } else { ret = b; }; return ret; } fn drawInt(value: ptr, minDigits: ptr) -> f32 { var c: f32 = 0.; if (*value < 0) { *value = -*value; if (*minDigits < 1) { *minDigits = 1; } else { *minDigits = *minDigits - 1; } c = c + (char(45)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); } var fn2: i32 = *value; var digits: i32 = 1; for (var ni: i32 = 0; ni < 10; ni = ni + 1) { fn2 = fn2 / (10); if (fn2 == 0) { break; } digits = digits + 1; } digits = maxInt(*minDigits, digits); tp_debug.x = tp_debug.x - (0.5 * f32(digits)); for (var ni: i32 = 1; ni < 11; ni = ni + 1) { tp_debug.x = tp_debug.x + (0.5); c = c + (char(48 + *value % 10)); *value = *value / (10); if (ni >= digits) { break; } } tp_debug.x = tp_debug.x - (0.5 * f32(digits)); return c; } fn drawIntBackwards(value: ptr, minDigits: ptr) -> f32 { var c: f32 = 0.; let original_value: i32 = *value; if (*value < 0) { *value = -*value; if (*minDigits < 1) { *minDigits = 1; } else { *minDigits = *minDigits - 1; } // tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); // c = c + (char(45)); } var fn2: i32 = *value; var digits: i32 = 1; for (var ni: i32 = 0; ni < 10; ni = ni + 1) { fn2 = fn2 / (10); if (fn2 == 0) { break; } digits = digits + 1; } digits = maxInt(*minDigits, digits); // tp_debug.x = tp_debug.x - (0.5 * f32(digits)); for (var ni: i32 = digits - 1; ni < 11; ni = ni - 1) { tp_debug.x = tp_debug.x + (0.5); c = c + (char(48 + *value % 10)); *value = *value / (10); if (ni == 0) { break; } } if (original_value < 0) { tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); c = c + (char(45)); } // tp_debug.x = tp_debug.x + (0.5 * f32(digits)); return c; } // fn drawFloat(value: ptr, prec: ptr, maxDigits: i32) -> f32 { fn drawFloat(val: f32, prec: ptr, maxDigits: i32) -> f32 { // in case of 0.099999..., round up to 0.1000000 var value = round(val * pow(10., f32(maxDigits))) / pow(10., f32(maxDigits)); let tp_debugx: f32 = tp_debug.x - 0.5 * f32(maxDigits); var c: f32 = 0.; if (value < 0.) { c = char(45); value = -value; } tp_debug.x = tp_debug.x - (0.5); var ival = i32(value); var one: i32 = 1; c = c + (drawInt(&ival, &one)); c = c + (char(46)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); var frac_val = fract(value); c = c + (drawFract(&frac_val, prec)); tp_debug.x = min(tp_debug.x, tp_debugx); return c; } fn drawFloat_f32(value: f32) -> f32 { var two: i32 = 2; return drawFloat(value, &two, 5); } fn drawFloat_f32_prec(value: f32, prec: ptr) -> f32 { return drawFloat(value, prec, 2); } fn drawInt_i32_back(value: ptr) -> f32 { var one: i32 = 1; return drawIntBackwards(value, &one); } fn drawInt_i32(value: ptr) -> f32 { var one: i32 = 1; return drawInt(value, &one); } fn SetColor(red: f32, green: f32, blue: f32) { drawColorDebug = vec3(red, green, blue); } fn WriteFloat(fValue: f32, maxDigits: i32, decimalPlaces: ptr) { // vColor = mix(vColor, drawColorDebug, drawFloat_f32_prec(fValue, decimalPlaces)); vColor = mix(vColor, drawColorDebug, drawFloat(fValue, decimalPlaces, maxDigits)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); ; } fn WriteFloatBox( fValue: f32, maxDigits: i32, decimalPlaces: i32, alpha: f32 ) { var decs = decimalPlaces; vColor = mix(vColor, drawColorDebug, drawFloat(fValue, &decs, maxDigits) * alpha); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); ; } fn WriteInteger(iValue: ptr) { vColor = mix(vColor, drawColorDebug, drawInt_i32(iValue)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); } fn WriteIntegerBack(iValue: ptr) { vColor = mix(vColor, drawColorDebug, drawInt_i32_back(iValue)); tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); } fn WriteFPS() { var fps: f32 = f32(uni.iSampleRate); SetColor(0.8, 0.6, 0.3); var max_digits_one = 1; WriteFloat(fps, 5, &max_digits_one); var c: f32 = 0.; c = c + (char(102)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(112)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(115)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); // let c2 = smoothStep(0.0, 1.0, c ); vColor = mix(vColor, drawColorDebug, c); } fn WriteMousePos(mPos: vec2, y_pos: f32) { let digits: i32 = 3; let radius: f32 = uni.iResolution.x / 400.; if (uni.iMouse.z > 0.) { dotColor_debug = mpColorDebug; } let r: f32 = length(abs(mPos.xy) - pixelPosDebug) - radius; // vColor = vColor + (mix(vec3(0.), dotColor_debug, 1. - clamp(r, 0., 1.))); var max_digits_three: i32 = 3; var mposxi: i32 = i32(mPos.x); var mposyi: i32 = i32(mPos.y); var mposx: f32 = (mPos.x); var mposy: f32 = (mPos.y); let x_pos = align_debug.y - 1. * FONT_SPACE_DEBUG; SetTextPositionAbs( x_pos, y_pos, ); drawColorDebug = myColorDebug; WriteIntegerBack(&mposyi); SetTextPositionAbs( x_pos - 7. * FONT_SPACE_DEBUG, y_pos, ); drawColorDebug = mxColorDebug; WriteIntegerBack(&mposxi); } fn sdRoundedBox(p: vec2, b: vec2, r: vec4) -> f32 { var x = r.x; var y = r.y; x = select(r.z, r.x, p.x > 0.); y = select(r.w, r.y, p.x > 0.); x = select(y, x, p.y > 0.); let q = abs(p) - b + x; return min(max(q.x, q.y), 0.) + length(max(q, vec2(0.))) - x; } fn WriteRGBAValues( location: vec2, value: vec4, screen_poz: vec2, alpha: f32, ) { let poz = screen_poz / uni.iResolution * 20. * vec2(aspect_debug, 1.0); let window_ajusted = uni.iResolution / vec2(960., 600.); let box_pos = vec2(align_debug.w, align_debug.x - FONT_SPACE_DEBUG ) / 10.; // let box_pos = mp; // // box location follows mouse position // let box_location = vec2( // uni.iMouse.x + 100. * window_ajusted.x / ( aspect_debug / 1.6 ) , // uni.iMouse.y - 48. * window_ajusted.y // ); let box_location = vec2( 100. * window_ajusted.x / ( aspect_debug / 1.6 ) , uni.iResolution.y - 60. * window_ajusted.y, ); let inverted_screen_poz = vec2(screen_poz.x, -screen_poz.y) ; // / vec2(aspect_debug, 1.) ; let d_box = sdRoundedBox( vec2(location) - box_location - inverted_screen_poz, vec2(73. / ( aspect_debug / 1.6 ), 75.) * window_ajusted, vec4(5.,5.,5.,5.) * 5.0 ); // let alpha = 0.225; let decimal_places = 3; SetColor(1., 1., 1.); var c: f32 = 0.; let lspace = 0.8; let bg_color = vec3(.8, .7, .9); vColor = mix( vColor, bg_color, (1.0 - step(0.0, d_box)) * alpha ); // red SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1.) - 0.0 + poz.y ) ; c = c + (char(114)); // r tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.r, 3, decimal_places, alpha ); // green SetTextPosition( 10. * ((box_pos.x +1. + lspace)) + poz.x, 10. * (-box_pos.y +1. ) + 1.0 + poz.y, ) ; c = c + (char(103)); // g tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.g, 3, decimal_places, alpha ); // blue SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1. ) + 2.0 + poz.y, ) ; c = c + (char(98)); // b tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.b, 4, decimal_places, alpha ); // alpha SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1. ) + 3.0 + poz.y, ) ; c = c + (char(97)); // a tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.a, 4, decimal_places, alpha ); vColor = mix(vColor, drawColorDebug, c * alpha); } fn sdSegment(p: vec2, a: vec2, b: vec2) -> f32 { let pa = p - a; let ba = b - a; let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.); return length(pa - ba * h); } fn ring(pos: vec2, radius: f32, thick: f32) -> f32 { return mix(1., 0., smoothStep(thick, thick + 0.01, abs(length(uv_debug - pos) - radius))); } fn sdCircle(p: vec2, c: vec2, r: f32) -> f32 { let d = length(p - c); return d - r; } fn draw_ring(location: vec2) { let mouse_click_poz = vec2(abs(uni.iMouse.z) , abs(uni.iMouse.w)); let alpha = 0.75; let ring_dist = sdCircle(vec2(location) , mouse_click_poz, 2.3); let d = smoothStep(0.5, 1.5, abs(ring_dist - 1.)); vColor = mix(vColor, headColorDebug, (1. - d) * alpha ); } fn draw_crossair(location: vec2) { let start = 5.0; let end = 20.; let segment1 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(start, 0.), vec2(end, 0.) ); let segment2 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(-start, 0.), vec2(-end, 0.) ); let segment3 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(0., start), vec2(0., end) ); let segment4 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(0., -start), vec2(0., -end) ); var alpha = 0.75; if (uni.iMouse.z > 0.) { alpha = 1.0; } let d = smoothStep(0.5, 1.5, segment1); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothStep(0.5, 1.5, segment2); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothStep(0.5, 1.5, segment3); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothStep(0.5, 1.5, segment4); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); } fn show_debug_info(location: vec2, color: vec3) -> vec4 { var fragCoord = vec2(f32(location.x), f32(location.y) ); vColor = color; aspect_debug = uni.iResolution.x / uni.iResolution.y; let ratio: vec2 = vec2(aspect_debug, 1.); pixelPosDebug = fragCoord.xy; // mousePosDebug = uni.iMouse.xy; uv_debug = (2. * fragCoord.xy / uni.iResolution.xy - 1.) * ratio; align_debug = 10. * vec4( 1., // North aspect_debug, // East -1., // South -aspect_debug, // West ); WriteMousePos(uni.iMouse.zw, align_debug.z + 2.0 * FONT_SPACE_DEBUG); // Click position WriteMousePos(uni.iMouse.xy, align_debug.z + 0.2 * FONT_SPACE_DEBUG); // Current mouse position var c: f32 = 0.; SetTextPositionAbs( align_debug.y - FONT_SPACE_DEBUG, align_debug.x - 2. * FONT_SPACE_DEBUG, ); SetColor(0.8, 0.8, 0.8); var resx = i32(uni.iResolution.x); var resy = i32(uni.iResolution.y); WriteIntegerBack(&resx); c = c + (char(28)); tp_debug.x = tp_debug.x + 0. * (FONT_SPACE_DEBUG); WriteIntegerBack(&resy); SetTextPositionAbs( align_debug.w - 1. * FONT_SPACE_DEBUG, align_debug.z - 0. * FONT_SPACE_DEBUG, ); WriteFPS(); SetColor(0.9, 0.7, 0.8); let fragColor = vec4(vColor, 1.); let poz = vec2(0., uni.iResolution.y / 2.); // // RGBA probe labels follow mouse // let poz = vec2(uni.iMouse.x , uni.iResolution.y - uni.iMouse.y); let inverted_y_mouse_location = vec2(vec2(uni.iMouse.x, uni.iResolution.y - uni.iMouse.y)); let value: vec4 = textureLoad(texture, inverted_y_mouse_location); WriteRGBAValues(location, value, poz, 0.5); let inverted_y_mouseclick_location = vec2(vec2(abs(uni.iMouse.z), uni.iResolution.y - abs(uni.iMouse.w))); let value2: vec4 = textureLoad(texture, inverted_y_mouseclick_location); WriteRGBAValues(location, value2, vec2(0.), 0.25); draw_crossair(location); draw_ring(location); let fragColor = vec4(vColor, 1.); return fragColor; } // Converts a color from sRGB gamma to linear light gamma fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } // Why are the characters so pixelated? // One possible reason is that we are in a compute shader and the textures are not // filtered. // type ivec2 = vec2; // type v2 = vec2; // let backColor: vec3 = vec3(0.2, 0.2, 0.2); // var R: vec2; // var uv: vec2 ; // var tp: vec2 ; // var alignment: vec4; // north, east, south, west // var font_size: f32; // var dotColor: vec3 = vec3(0.5, 0.5, 0.); // var drawColor: vec3 = vec3(1., 1., 0.); // var vColor: vec3 = backColor; // var aspect: f32 = 1.; // var pixelPos: vec2 = vec2(0., 0.); // var mousePos: vec2 = vec2(200., 200.); // var lp: vec2 = vec2(0.5, 0.5); // var mp: vec2 = vec2(0.5, 0.5); // var resolution: vec2; // let FONT_SPACE: f32 = 0.5; // let headColor: vec3 = vec3(0.9, 0.6, 0.2); // let mpColor: vec3 = vec3(0.99, 0.99, 0.); // let mxColor: vec3 = vec3(1., 0., 0.); // let myColor: vec3 = vec3(0., 1., 0.); // let font_png_size: vec2 = vec2(1023.0, 1023.0); // fn char(ch: i32) -> f32 { // let fr = fract(floor(vec2(f32(ch), 15.999 - f32(ch) / 16.)) / 16.); // let q = clamp(tp, v2(0.), v2(1.)) / 16. + fr ; // let inverted_q = v2(q.x, 1. - q.y); // // // There is aliasing on the characters // // let f = textureSampleGrad(font_texture, // // font_texture_sampler, // // inverted_q, // // vec2(1.0, 0.0), // // vec2(0.0, 1.0)); // // using textureLoad without sampler // let q1 = ivec2(font_png_size * q ); // let y_inverted_q1 = ivec2(q1.x, i32(font_png_size.y) - q1.y); // var f: vec4 = textureLoad(font_texture, y_inverted_q1 , 0); // // smoothing out the aliasing // let dx = vec2(1, 0); // let dy = vec2(0, 1); // let fx1: vec4 = textureLoad(font_texture, y_inverted_q1 + dx, 0); // let fx2: vec4 = textureLoad(font_texture, y_inverted_q1 - dx, 0); // let fy1: vec4 = textureLoad(font_texture, y_inverted_q1 + dy, 0); // let fy2: vec4 = textureLoad(font_texture, y_inverted_q1 - dy, 0); // let rp = 0.25; // f = f * rp + (1.0 - rp) * (fx1 + fx2 + fy1 + fy2) / 4.0 ; // return f.x * (f.y + 0.3) * (f.z + 0.3) * 2.; // } // fn SetTextPosition(x: f32, y: f32) { // tp = 10. * uv; // tp.x = tp.x + 17. - x; // tp.y = tp.y - 9.4 + y; // } // fn SetTextPositionAbs(x: f32, y: f32) { // tp.x = 10. * uv.x - x; // tp.y = 10. * uv.y - y; // } // fn drawFract(value: ptr, digits: ptr) -> f32 { // var c: f32 = 0.; // *value = fract(*value) * 10.; // for (var ni: i32 = 1; ni < 60; ni = ni + 1) { // c = c + (char(48 + i32(*value))); // tp.x = tp.x - (0.5); // *digits = *digits - (1); // *value = fract(*value) * 10.; // if (*digits <= 0 || *value == 0.) { // break; // } // } // tp.x = tp.x - (0.5 * f32(*digits)); // return c; // } // fn maxInt(a: i32, b: i32) -> i32 { // var ret: i32; // if (a > b) { ret = a; } else { ret = b; }; // return ret; // } // fn drawInt(value: ptr, minDigits: ptr) -> f32 { // var c: f32 = 0.; // if (*value < 0) { // *value = -*value; // if (*minDigits < 1) { // *minDigits = 1; // } else { // *minDigits = *minDigits - 1; // } // c = c + (char(45)); // tp.x = tp.x - (FONT_SPACE); // } // var fn2: i32 = *value; // var digits: i32 = 1; // for (var ni: i32 = 0; ni < 10; ni = ni + 1) { // fn2 = fn2 / (10); // if (fn2 == 0) { break; } // digits = digits + 1; // } // digits = maxInt(*minDigits, digits); // tp.x = tp.x - (0.5 * f32(digits)); // for (var ni: i32 = 1; ni < 11; ni = ni + 1) { // tp.x = tp.x + (0.5); // c = c + (char(48 + *value % 10)); // *value = *value / (10); // if (ni >= digits) { break; } // } // tp.x = tp.x - (0.5 * f32(digits)); // return c; // } // fn drawIntBackwards(value: ptr, minDigits: ptr) -> f32 { // var c: f32 = 0.; // let original_value: i32 = *value; // if (*value < 0) { // *value = -*value; // if (*minDigits < 1) { // *minDigits = 1; // } else { // *minDigits = *minDigits - 1; // } // // tp.x = tp.x + (FONT_SPACE); // // c = c + (char(45)); // } // var fn2: i32 = *value; // var digits: i32 = 1; // for (var ni: i32 = 0; ni < 10; ni = ni + 1) { // fn2 = fn2 / (10); // if (fn2 == 0) { break; } // digits = digits + 1; // } // digits = maxInt(*minDigits, digits); // // tp.x = tp.x - (0.5 * f32(digits)); // for (var ni: i32 = digits - 1; ni < 11; ni = ni - 1) { // tp.x = tp.x + (0.5); // c = c + (char(48 + *value % 10)); // *value = *value / (10); // if (ni == 0) { break; } // } // if (original_value < 0) { // tp.x = tp.x + (FONT_SPACE); // c = c + (char(45)); // } // // tp.x = tp.x + (0.5 * f32(digits)); // return c; // } // // fn drawFloat(value: ptr, prec: ptr, maxDigits: i32) -> f32 { // fn drawFloat(val: f32, prec: ptr, maxDigits: i32) -> f32 { // // in case of 0.099999..., round up to 0.1000000 // var value = round(val * pow(10., f32(maxDigits))) / pow(10., f32(maxDigits)); // let tpx: f32 = tp.x - 0.5 * f32(maxDigits); // var c: f32 = 0.; // if (value < 0.) { // c = char(45); // value = -value; // } // tp.x = tp.x - (0.5); // var ival = i32(value); // var one: i32 = 1; // c = c + (drawInt(&ival, &one)); // c = c + (char(46)); // tp.x = tp.x - (FONT_SPACE); // var frac_val = fract(value); // c = c + (drawFract(&frac_val, prec)); // tp.x = min(tp.x, tpx); // return c; // } // fn drawFloat_f32(value: f32) -> f32 { // var two: i32 = 2; // return drawFloat(value, &two, 5); // } // fn drawFloat_f32_prec(value: f32, prec: ptr) -> f32 { // return drawFloat(value, prec, 2); // } // fn drawInt_i32_back(value: ptr) -> f32 { // var one: i32 = 1; // return drawIntBackwards(value, &one); // } // fn drawInt_i32(value: ptr) -> f32 { // var one: i32 = 1; // return drawInt(value, &one); // } // fn SetColor(red: f32, green: f32, blue: f32) { // drawColor = vec3(red, green, blue); // } // fn WriteFloat(fValue: f32, maxDigits: i32, decimalPlaces: ptr) { // // vColor = mix(vColor, drawColor, drawFloat_f32_prec(fValue, decimalPlaces)); // vColor = mix(vColor, drawColor, drawFloat(fValue, decimalPlaces, maxDigits)); // tp.x = tp.x - (FONT_SPACE); // ; // } // fn WriteFloatBox( // fValue: f32, // maxDigits: i32, // decimalPlaces: i32, // alpha: f32 // ) { // var decs = decimalPlaces; // vColor = mix(vColor, drawColor, drawFloat(fValue, &decs, maxDigits) * alpha); // tp.x = tp.x - (FONT_SPACE); // ; // } // fn WriteInteger(iValue: ptr) { // vColor = mix(vColor, drawColor, drawInt_i32(iValue)); // tp.x = tp.x - (FONT_SPACE); // } // fn WriteIntegerBack(iValue: ptr) { // vColor = mix(vColor, drawColor, drawInt_i32_back(iValue)); // tp.x = tp.x + (FONT_SPACE); // } // fn WriteFPS() { // var fps: f32 = f32(uni.iSampleRate); // SetColor(0.8, 0.6, 0.3); // var max_digits_one = 1; // WriteFloat(fps, 5, &max_digits_one); // var c: f32 = 0.; // c = c + (char(102)); // tp.x = tp.x - (FONT_SPACE); // c = c + (char(112)); // tp.x = tp.x - (FONT_SPACE); // c = c + (char(115)); // tp.x = tp.x - (FONT_SPACE); // // let c2 = smoothStep(0.0, 1.0, c ); // vColor = mix(vColor, drawColor, c); // } // fn WriteMousePos(mPos: vec2, y_pos: f32) { // let digits: i32 = 3; // let radius: f32 = resolution.x / 400.; // if (uni.iMouse.z > 0.) { dotColor = mpColor; } // let r: f32 = length(abs(mPos.xy) - pixelPos) - radius; // // vColor = vColor + (mix(vec3(0.), dotColor, 1. - clamp(r, 0., 1.))); // var max_digits_three: i32 = 3; // var mposxi: i32 = i32(mPos.x); // var mposyi: i32 = i32(mPos.y); // var mposx: f32 = (mPos.x); // var mposy: f32 = (mPos.y); // let x_pos = alignment.y - 1. * FONT_SPACE; // SetTextPositionAbs( // x_pos, // y_pos, // ); // drawColor = myColor; // WriteIntegerBack(&mposyi); // SetTextPositionAbs( // x_pos - 7. * FONT_SPACE, // y_pos, // ); // drawColor = mxColor; // WriteIntegerBack(&mposxi); // } // fn sdRoundedBox(p: vec2, b: vec2, r: vec4) -> f32 { // var x = r.x; // var y = r.y; // x = select(r.z, r.x, p.x > 0.); // y = select(r.w, r.y, p.x > 0.); // x = select(y, x, p.y > 0.); // let q = abs(p) - b + x; // return min(max(q.x, q.y), 0.) + length(max(q, vec2(0.))) - x; // } // fn WriteRGBAValues( // location: vec2, // value: vec4, // screen_poz: vec2, // alpha: f32, // ) { // let poz = screen_poz / uni.iResolution * 20. * vec2(aspect, 1.0); // let window_ajusted = uni.iResolution / v2(960., 600.); // let box_pos = vec2(alignment.w, alignment.x - FONT_SPACE ) / 10.; // // let box_pos = mp; // // // box location follows mouse position // // let box_location = v2( // // uni.iMouse.x + 100. * window_ajusted.x / ( aspect / 1.6 ) , // // uni.iMouse.y - 48. * window_ajusted.y // // ); // let box_location = v2( // 100. * window_ajusted.x / ( aspect / 1.6 ) , // uni.iResolution.y - 60. * window_ajusted.y, // ); // let inverted_screen_poz = vec2(screen_poz.x, -screen_poz.y) ; // / vec2(aspect, 1.) ; // let d_box = sdRoundedBox( // vec2(location) - box_location - inverted_screen_poz, // vec2(73. / ( aspect / 1.6 ), 75.) * window_ajusted, // vec4(5.,5.,5.,5.) * 5.0 // ); // // let alpha = 0.225; // let decimal_places = 3; // SetColor(1., 1., 1.); // var c: f32 = 0.; // let lspace = 0.8; // let bg_color = vec3(.8, .7, .9); // vColor = mix( vColor, bg_color, (1.0 - step(0.0, d_box)) * alpha ); // // red // SetTextPosition( // 10. * (box_pos.x +1. + lspace) + poz.x, // 10. * (-box_pos.y +1.) - 0.0 + poz.y // ) ; // c = c + (char(114)); // r // tp.x = tp.x - (FONT_SPACE); // c = c + (char(58)); // colon // tp.x = tp.x - (FONT_SPACE); // WriteFloatBox(value.r, 3, decimal_places, alpha ); // // green // SetTextPosition( // 10. * ((box_pos.x +1. + lspace)) + poz.x, // 10. * (-box_pos.y +1. ) + 1.0 + poz.y, // ) ; // c = c + (char(103)); // g // tp.x = tp.x - (FONT_SPACE); // c = c + (char(58)); // colon // tp.x = tp.x - (FONT_SPACE); // WriteFloatBox(value.g, 3, decimal_places, alpha ); // // blue // SetTextPosition( // 10. * (box_pos.x +1. + lspace) + poz.x, // 10. * (-box_pos.y +1. ) + 2.0 + poz.y, // ) ; // c = c + (char(98)); // b // tp.x = tp.x - (FONT_SPACE); // c = c + (char(58)); // colon // tp.x = tp.x - (FONT_SPACE); // WriteFloatBox(value.b, 4, decimal_places, alpha ); // // alpha // SetTextPosition( // 10. * (box_pos.x +1. + lspace) + poz.x, // 10. * (-box_pos.y +1. ) + 3.0 + poz.y, // ) ; // c = c + (char(97)); // a // tp.x = tp.x - (FONT_SPACE); // c = c + (char(58)); // colon // tp.x = tp.x - (FONT_SPACE); // WriteFloatBox(value.a, 4, decimal_places, alpha ); // vColor = mix(vColor, drawColor, c * alpha); // } // fn sdSegment(p: vec2, a: vec2, b: vec2) -> f32 { // let pa = p - a; // let ba = b - a; // let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.); // return length(pa - ba * h); // } // fn ring(pos: vec2, radius: f32, thick: f32) -> f32 { // return mix(1., 0., smoothStep(thick, thick + 0.01, abs(length(uv - pos) - radius))); // } // fn sdCircle(p: vec2, c: vec2, r: f32) -> f32 { // let d = length(p - c); // return d - r; // } // fn draw_ring(location: vec2) { // let mouse_click_poz = vec2(abs(uni.iMouse.z) , abs(uni.iMouse.w)); // let alpha = 0.75; // let ring_dist = sdCircle(vec2(location) , mouse_click_poz, 2.3); // let d = smoothStep(0.5, 1.5, abs(ring_dist - 1.)); // vColor = mix(vColor, headColor, (1. - d) * alpha ); // } // fn draw_crossair(location: vec2) { // let start = 5.0; // let end = 20.; // let segment1 = sdSegment( // vec2(location) - uni.iMouse.xy, // vec2(start, 0.), // vec2(end, 0.) // ); // let segment2 = sdSegment( // vec2(location) - uni.iMouse.xy, // vec2(-start, 0.), // vec2(-end, 0.) // ); // let segment3 = sdSegment( // vec2(location) - uni.iMouse.xy, // vec2(0., start), // vec2(0., end) // ); // let segment4 = sdSegment( // vec2(location) - uni.iMouse.xy, // vec2(0., -start), // vec2(0., -end) // ); // var alpha = 0.75; // if (uni.iMouse.z > 0.) { // alpha = 1.0; // } // let d = smoothStep(0.5, 1.5, segment1); // vColor = mix(vColor, headColor, (1.0 - d) * alpha ); // let d = smoothStep(0.5, 1.5, segment2); // vColor = mix(vColor, headColor, (1.0 - d) * alpha ); // let d = smoothStep(0.5, 1.5, segment3); // vColor = mix(vColor, headColor, (1.0 - d) * alpha ); // let d = smoothStep(0.5, 1.5, segment4); // vColor = mix(vColor, headColor, (1.0 - d) * alpha ); // } // fn show_debug_info(location: vec2) -> vec4 { // var fragCoord = vec2(f32(location.x), f32(location.y) ); // resolution = uni.iResolution.xy; // aspect = resolution.x / resolution.y; // let ratio: vec2 = vec2(aspect, 1.); // pixelPos = fragCoord.xy; // mousePos = uni.iMouse.xy; // uv = (2. * fragCoord.xy / resolution.xy - 1.) * ratio; // alignment = 10. * vec4( // 1., // North // aspect, // East // -1., // South // -aspect, // West // ); // mp = (2. * abs(uni.iMouse.xy) / resolution.xy - 1.) * ratio; // Mouse position in uv coordinates // WriteMousePos(uni.iMouse.zw, alignment.z + 2.0 * FONT_SPACE); // Click position // WriteMousePos(uni.iMouse.xy, alignment.z + 0.2 * FONT_SPACE); // Current mouse position // var c: f32 = 0.; // SetTextPositionAbs( // alignment.y - FONT_SPACE, // alignment.x - 2. * FONT_SPACE, // ); // SetColor(0.8, 0.8, 0.8); // var resx = i32(uni.iResolution.x); // var resy = i32(uni.iResolution.y); // WriteIntegerBack(&resx); // c = c + (char(28)); // tp.x = tp.x + 0. * (FONT_SPACE); // WriteIntegerBack(&resy); // SetTextPositionAbs( // alignment.w - 1. * FONT_SPACE, // alignment.z - 0. * FONT_SPACE, // ); // WriteFPS(); // SetColor(0.9, 0.7, 0.8); // let fragColor = vec4(vColor, 1.); // let poz = vec2(0., uni.iResolution.y / 2.); // // // RGBA probe labels follow mouse // // let poz = vec2(uni.iMouse.x , uni.iResolution.y - uni.iMouse.y); // let inverted_y_mouse_location = vec2(v2(uni.iMouse.x, uni.iResolution.y - uni.iMouse.y)); // let value: vec4 = textureLoad(texture, inverted_y_mouse_location); // WriteRGBAValues(location, value, poz, 0.5); // let inverted_y_mouseclick_location = vec2(v2(abs(uni.iMouse.z), uni.iResolution.y - abs(uni.iMouse.w))); // let value2: vec4 = textureLoad(texture, inverted_y_mouseclick_location); // WriteRGBAValues(location, value2, vec2(0.), 0.25); // draw_crossair(location); // draw_ring(location); // let fragColor = vec4(vColor, 1.); // return fragColor; // } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let y_inverted_location = vec2((location.x), i32(uni.iResolution.y) - (location.y)); let fragColor = show_debug_info(location, vec3(0.5, 0.2, 0.1)); textureStore(texture, y_inverted_location, toLinear(fragColor)); } ================================================ FILE: assets/shaders/dry_ice/buffer_a.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; let dissipation: f32 = 0.95; let ballRadius: f32 = 0.06; let fogHeigth: f32 = 0.24; let nbSlice: i32 = 24; let fogSlice: f32 = 0.01; let nbSphere: i32 = 3; let shadowDensity: f32 = 25.; let fogDensity: f32 = 20.; let lightHeight: f32 = 1.; let tau: f32 = 6.28318530718; fn hash12(p: vec2) -> f32 { var p3: vec3 = fract(vec3(p.xyx) * 0.1031); p3 = p3 + (dot(p3, p3.yzx + 33.33)); return fract((p3.x + p3.y) * p3.z); } fn hash41(p: f32) -> vec4 { var p4: vec4 = fract(vec4(p) * vec4(0.1031, 0.103, 0.0973, 0.1099)); p4 = p4 + (dot(p4, p4.wzxy + 33.33)); return fract((p4.xxyz + p4.yzzw) * p4.zywx); } fn rotate(angle: f32, radius: f32) -> vec2 { return vec2(cos(angle), -sin(angle)) * radius; } fn floorIntersect(ro: vec3, rd: vec3, floorHeight: f32, t: ptr) -> bool { var ro_var = ro; ro_var.y = ro_var.y - (floorHeight); if (rd.y < -0.01) { (*t) = ro_var.y / -rd.y; return true; } return false; } fn sphIntersect(ro: vec3, rd: vec3, ce: vec3, ra: f32) -> vec2 { let oc: vec3 = ro - ce; let b: f32 = dot(oc, rd); let c: f32 = dot(oc, oc) - ra * ra; var h: f32 = b * b - c; if (h < 0.) { return vec2(-1.); } h = sqrt(h); return vec2(-b - h, -b + h); } fn boxIntersection(ro: vec3, rd: vec3, rad: vec3, center: vec3, oN: ptr>) -> vec2 { var ro_var = ro; ro_var = ro_var - (center); let m: vec3 = 1. / rd; let n: vec3 = m * ro_var; let k: vec3 = abs(m) * rad; let t1: vec3 = -n - k; let t2: vec3 = -n + k; let tN: f32 = max(max(t1.x, t1.y), t1.z); let tF: f32 = min(min(t2.x, t2.y), t2.z); if (tN > tF || tF < 0.) { return vec2(-1.); } (*oN) = -sign(rd) * step(t1.yzx, t1.xyz) * step(t1.zxy, t1.xyz); return vec2(tN, tF); } fn spherePosition(id: i32, frame: i32) -> vec2 { let offset: vec4 = hash41(f32(id)) * tau; let fframe: f32 = f32(frame); return vec2(cos(offset.x + fframe * 0.015) + cos(offset.y + fframe * 0.02), cos(offset.z + fframe * 0.017) + cos(offset.w + fframe * 0.022)) * vec2(1., 0.5) * 0.9; } fn dist2(v: vec3) -> f32 { return dot(v, v); } fn sample_texture(ch: texture_storage_2d, U01: vec2) -> vec4 { let U = U01 * uni.iResolution; let f = vec2(floor(U)); let c = vec2(ceil(U)); let fr = fract(U); let upleft = vec2( f.x, c.y ); let upright = vec2( c.x , c.y ); let downleft = vec2( f.x, f.y ); let downright = vec2( c.x , f.y ); let interpolated_2d = ( (1. - fr.x) * (1. - fr.y) * textureLoad(ch, downleft) + (1. - fr.x) * fr.y * textureLoad(ch, upleft) + fr.x * fr.y * textureLoad(ch, upright) + fr.x * (1. - fr.y) * textureLoad(ch, downright) ); return interpolated_2d; } fn noise(p_in: vec3) -> f32 { var p = p_in; let ip: vec3 = floor(p); p = p - (ip); let s: vec3 = vec3(7., 157., 113.); var h: vec4 = vec4(0., s.yz, s.y + s.z) + dot(ip, s); p = p * p * (3. - 2. * p); h = mix(fract(sin(h) * 43758.5), fract(sin(h + s.x) * 43758.5), p.x); var hxy = h.xy; hxy = mix(h.xz, h.yw, p.y); h.x = hxy.x; h.y = hxy.y; return mix(h.x, h.y, p.z); } fn fbm(p_in: vec3, octaveNum: i32) -> vec2 { var p = p_in; var octaveNum_var = octaveNum; var acc: vec2 = vec2(0.); let freq: f32 = 1.; var amp: f32 = 0.5; let shift: vec3 = vec3(100.); for (var i: i32 = 0; i < octaveNum_var; i = i + 1) { acc = acc + (vec2(noise(p), noise(p + vec3(0., 0., 10.))) * amp); p = p * 2. + shift; amp = amp * (0.5); } return acc; } fn sampleMinusGradient(coord: vec2) -> vec3 { var veld: vec3 = sample_texture(buffer_a, (coord / uni.iResolution.xy)).xyz; let left: f32 = sample_texture(buffer_d, ((coord + vec2(-1., 0.)) / uni.iResolution.xy)).x; let right: f32 = sample_texture(buffer_d, ((coord + vec2(1., 0.)) / uni.iResolution.xy)).x; let bottom: f32 = sample_texture(buffer_d, ((coord + vec2(0., -1.)) / uni.iResolution.xy)).x; let top: f32 = sample_texture(buffer_d, ((coord + vec2(0., 1.)) / uni.iResolution.xy)).x; let grad: vec2 = vec2(right - left, top - bottom) * 0.5; return vec3(veld.xy - grad, veld.z); } fn vignette(color: vec3, q: vec2, v: f32) -> vec3 { var color_var = color; color_var = color_var * (mix(1., pow(16. * q.x * q.y * (1. - q.x) * (1. - q.y), v), 0.02)); return color_var; } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var fragColor: vec4; var fragCoord = vec2(f32(location.x), f32(location.y) ); var velocity: vec2 = sampleMinusGradient(fragCoord).xy; var veld: vec3 = sampleMinusGradient(fragCoord - dissipation * velocity).xyz; var density: f32 = veld.z; velocity = veld.xy; let uv: vec2 = (2. * fragCoord - uni.iResolution.xy) / uni.iResolution.y; let detailNoise: vec2 = fbm(vec3(uv * 40., uni.iTime * 0.5 + 30.), 7) - 0.5; velocity = velocity + (detailNoise * 0.2); density = density + (length(detailNoise) * 0.01); let injectionNoise: vec2 = fbm(vec3(uv * 1.5, uni.iTime * 0.1 + 30.), 7) - 0.5; velocity = velocity + (injectionNoise * 0.1); density = density + (max(length(injectionNoise) * 0.04, 0.)); let influenceRadius: f32 = ballRadius * 2.; for (var i: i32 = 0; i < nbSphere; i = i + 1) { let p: vec2 = spherePosition(i, i32(uni.iFrame)); let dist: f32 = distance(uv, p); if (dist < influenceRadius) { let op: vec2 = spherePosition(i, i32(uni.iFrame) + 1); let ballVelocity: vec2 = p - op; density = density - ((influenceRadius - dist) / influenceRadius * 0.15); density = max(0., density); velocity = velocity - (ballVelocity * 5.); } } density = min(1., density); density = density * (0.99); veld = vec3(vec3(velocity, density)); veld = vignette(veld, fragCoord / uni.iResolution.xy, 1.); fragColor = vec4(veld, 1.); textureStore(buffer_a, location, fragColor); } // fn noise(p_in: vec3) -> f32 { // var p = p_in; // let ip: vec3 = floor(p); // p = p - (ip); // let s: vec3 = vec3(7., 157., 113.); // var h: vec4 = vec4(0., s.yz, s.y + s.z) + dot(ip, s); // p = p * p * (3. - 2. * p); // h = mix(fract(sin(h) * 43758.5), fract(sin(h + s.x) * 43758.5), p.x); // var hxy = h.xy; // hxy = mix(h.xz, h.yw, p.y); // h.x = hxy.x; // h.y = hxy.y; // return mix(h.x, h.y, p.z); // } // fn fbm(p_in: vec3, octaveNum: i32) -> vec2 { // var p = p_in; // var octaveNum_var = octaveNum; // var acc: vec2 = vec2(0.); // let freq: f32 = 1.; // var amp: f32 = 0.5; // let shift: vec3 = vec3(100.); // for (var i: i32 = 0; i < octaveNum_var; i = i + 1) { // acc = acc + (vec2(noise(p), noise(p + vec3(0., 0., 10.))) * amp); // p = p * 2. + shift; // amp = amp * (0.5); // } // return acc; // } // fn sampleMinusGradient(coord: vec2) -> vec3 { // var veld: vec3 = sample_texture(buffer_a,(coord / uni.iResolution.xy)).xyz; // let left: f32 = sample_texture(buffer_d, ((coord + vec2(-1., 0.)) / uni.iResolution.xy)).x; // let right: f32 = sample_texture(buffer_d, ((coord + vec2(1., 0.)) / uni.iResolution.xy)).x; // let bottom: f32 = sample_texture(buffer_d, ((coord + vec2(0., -1.)) / uni.iResolution.xy)).x; // let top: f32 = sample_texture(buffer_d, ((coord + vec2(0., 1.)) / uni.iResolution.xy)).x; // let grad: vec2 = vec2(right - left, top - bottom) * 0.5; // return vec3(veld.xy - grad, veld.z); // } // fn vignette(color: vec3, q: vec2, v: f32) -> vec3 { // var color_var = color; // color_var = color_var * (mix(1., pow(16. * q.x * q.y * (1. - q.x) * (1. - q.y), v), 0.02)); // return color_var; // } // [[stage(compute), workgroup_size(8, 8, 1)]] // fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { // let R: vec2 = uni.iResolution.xy; // let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // var fragColor: vec4 = vec4(0.); // var fragCoord = vec2(f32(location.x), f32(location.y) ); // var velocity: vec2 = sampleMinusGradient(fragCoord).xy; // var veld: vec3 = sampleMinusGradient(fragCoord - dissipation * velocity).xyz; // var density: f32 = veld.z; // velocity = veld.xy; // let uv: vec2 = (2. * fragCoord - uni.iResolution.xy) / uni.iResolution.y; // let detailNoise: vec2 = fbm(vec3(uv * 40., uni.iTime * 0.5 + 30.), 7) - 0.5; // velocity = velocity + (detailNoise * 0.2); // density = density + (length(detailNoise) * 0.01); // let injectionNoise: vec2 = fbm(vec3(uv * 1.5, uni.iTime * 0.1 + 30.), 7) - 0.5; // velocity = velocity + (injectionNoise * 0.1); // density = density + (max(length(injectionNoise) * 0.04, 0.)); // let influenceRadius: f32 = ballRadius * 2.; // for (var i: i32 = 0; i < nbSphere; i = i + 1) { // let p: vec2 = spherePosition(i, i32(uni.iFrame)); // let dist: f32 = distance(uv, p); // if (dist < influenceRadius) { // let op: vec2 = spherePosition(i, i32(uni.iFrame) + 1); // let ballVelocity: vec2 = p - op; // density = density - ((influenceRadius - dist) / influenceRadius * 0.15); // density = max(0., density); // velocity = velocity - (ballVelocity * 5.); // } // } // density = min(1., density); // density = density * (0.99); // veld = vec3(vec3(velocity, density)); // // veld = vignette(veld, fragCoord / uni.iResolution.xy, 1.); // fragColor = vec4(veld, 1.); // textureStore(buffer_a, location, fragColor); // } ================================================ FILE: assets/shaders/dry_ice/buffer_b.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; let dissipation: f32 = 0.95; let ballRadius: f32 = 0.06; let fogHeigth: f32 = 0.24; let nbSlice: i32 = 24; let fogSlice: f32 = 0.01; let nbSphere: i32 = 3; let shadowDensity: f32 = 25.; let fogDensity: f32 = 20.; let lightHeight: f32 = 1.; let tau: f32 = 6.28318530718; fn hash12(p: vec2) -> f32 { var p3: vec3 = fract(vec3(p.xyx) * 0.1031); p3 = p3 + (dot(p3, p3.yzx + 33.33)); return fract((p3.x + p3.y) * p3.z); } fn hash41(p: f32) -> vec4 { var p4: vec4 = fract(vec4(p) * vec4(0.1031, 0.103, 0.0973, 0.1099)); p4 = p4 + (dot(p4, p4.wzxy + 33.33)); return fract((p4.xxyz + p4.yzzw) * p4.zywx); } fn rotate(angle: f32, radius: f32) -> vec2 { return vec2(cos(angle), -sin(angle)) * radius; } fn floorIntersect(ro: vec3, rd: vec3, floorHeight: f32, t: ptr) -> bool { var ro_var = ro; ro_var.y = ro_var.y - (floorHeight); if (rd.y < -0.01) { (*t) = ro_var.y / -rd.y; return true; } return false; } fn sphIntersect(ro: vec3, rd: vec3, ce: vec3, ra: f32) -> vec2 { let oc: vec3 = ro - ce; let b: f32 = dot(oc, rd); let c: f32 = dot(oc, oc) - ra * ra; var h: f32 = b * b - c; if (h < 0.) { return vec2(-1.); } h = sqrt(h); return vec2(-b - h, -b + h); } fn boxIntersection(ro: vec3, rd: vec3, rad: vec3, center: vec3, oN: ptr>) -> vec2 { var ro_var = ro; ro_var = ro_var - (center); let m: vec3 = 1. / rd; let n: vec3 = m * ro_var; let k: vec3 = abs(m) * rad; let t1: vec3 = -n - k; let t2: vec3 = -n + k; let tN: f32 = max(max(t1.x, t1.y), t1.z); let tF: f32 = min(min(t2.x, t2.y), t2.z); if (tN > tF || tF < 0.) { return vec2(-1.); } (*oN) = -sign(rd) * step(t1.yzx, t1.xyz) * step(t1.zxy, t1.xyz); return vec2(tN, tF); } fn spherePosition(id: i32, frame: i32) -> vec2 { let offset: vec4 = hash41(f32(id)) * tau; let fframe: f32 = f32(frame); return vec2(cos(offset.x + fframe * 0.015) + cos(offset.y + fframe * 0.02), cos(offset.z + fframe * 0.017) + cos(offset.w + fframe * 0.022)) * vec2(1., 0.5) * 0.9; } fn dist2(v: vec3) -> f32 { return dot(v, v); } fn sample_texture(ch: texture_storage_2d, U01: vec2) -> vec4 { let U = U01 * uni.iResolution; let f = vec2(floor(U)); let c = vec2(ceil(U)); let fr = fract(U); let upleft = vec2( f.x, c.y ); let upright = vec2( c.x , c.y ); let downleft = vec2( f.x, f.y ); let downright = vec2( c.x , f.y ); let interpolated_2d = ( (1. - fr.x) * (1. - fr.y) * textureLoad(ch, downleft) + (1. - fr.x) * fr.y * textureLoad(ch, upleft) + fr.x * fr.y * textureLoad(ch, upright) + fr.x * (1. - fr.y) * textureLoad(ch, downright) ); return interpolated_2d; } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var fragColor: vec4; var fragCoord = vec2(f32(location.x), f32(location.y) ); let icoord: vec2 = vec2(fragCoord); let vel_x_left: f32 = textureLoad(buffer_a, vec2(icoord + vec2(-1, 0))).x; let vel_x_right: f32 = textureLoad(buffer_a, vec2(icoord + vec2(1, 0))).x; let vel_y_bottom: f32 = textureLoad(buffer_a, vec2(icoord + vec2(0, -1))).y; let vel_y_top: f32 = textureLoad(buffer_a, vec2(icoord + vec2(0, 1))).y; let divergence: f32 = (vel_x_right - vel_x_left + vel_y_top - vel_y_bottom) * 0.5; fragColor = vec4(divergence, vec3(1.)); textureStore(buffer_b, location, fragColor); } // [[stage(compute), workgroup_size(8, 8, 1)]] // fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { // let R: vec2 = uni.iResolution.xy; // let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // var fragColor: vec4 = vec4(0.0, 0.0, 0.0, 1.0); // var fragCoord = vec2(f32(location.x), f32(location.y) ); // let icoord: vec2 = vec2(fragCoord); // let vel_x_left: f32 = sample_texture(buffer_a, vec2(icoord + vec2(-1, 0))).x; // let vel_x_right: f32 = sample_texture(buffer_a, vec2(icoord + vec2(1, 0))).x; // let vel_y_bottom: f32 = sample_texture(buffer_a, vec2(icoord + vec2(0, -1))).y; // let vel_y_top: f32 = sample_texture(buffer_a, vec2(icoord + vec2(0, 1))).y; // let divergence: f32 = (vel_x_right - vel_x_left + vel_y_top - vel_y_bottom) * 0.5; // fragColor = vec4(divergence, vec3(1.)); // textureStore(buffer_b, location, fragColor); // } ================================================ FILE: assets/shaders/dry_ice/buffer_c.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; let dissipation: f32 = 0.95; let ballRadius: f32 = 0.06; let fogHeigth: f32 = 0.24; let nbSlice: i32 = 24; let fogSlice: f32 = 0.01; let nbSphere: i32 = 3; let shadowDensity: f32 = 25.; let fogDensity: f32 = 20.; let lightHeight: f32 = 1.; let tau: f32 = 6.28318530718; fn hash12(p: vec2) -> f32 { var p3: vec3 = fract(vec3(p.xyx) * 0.1031); p3 = p3 + (dot(p3, p3.yzx + 33.33)); return fract((p3.x + p3.y) * p3.z); } fn hash41(p: f32) -> vec4 { var p4: vec4 = fract(vec4(p) * vec4(0.1031, 0.103, 0.0973, 0.1099)); p4 = p4 + (dot(p4, p4.wzxy + 33.33)); return fract((p4.xxyz + p4.yzzw) * p4.zywx); } fn rotate(angle: f32, radius: f32) -> vec2 { return vec2(cos(angle), -sin(angle)) * radius; } fn floorIntersect(ro: vec3, rd: vec3, floorHeight: f32, t: ptr) -> bool { var ro_var = ro; ro_var.y = ro_var.y - (floorHeight); if (rd.y < -0.01) { (*t) = ro_var.y / -rd.y; return true; } return false; } fn sphIntersect(ro: vec3, rd: vec3, ce: vec3, ra: f32) -> vec2 { let oc: vec3 = ro - ce; let b: f32 = dot(oc, rd); let c: f32 = dot(oc, oc) - ra * ra; var h: f32 = b * b - c; if (h < 0.) { return vec2(-1.); } h = sqrt(h); return vec2(-b - h, -b + h); } fn boxIntersection(ro: vec3, rd: vec3, rad: vec3, center: vec3, oN: ptr>) -> vec2 { var ro_var = ro; ro_var = ro_var - (center); let m: vec3 = 1. / rd; let n: vec3 = m * ro_var; let k: vec3 = abs(m) * rad; let t1: vec3 = -n - k; let t2: vec3 = -n + k; let tN: f32 = max(max(t1.x, t1.y), t1.z); let tF: f32 = min(min(t2.x, t2.y), t2.z); if (tN > tF || tF < 0.) { return vec2(-1.); } (*oN) = -sign(rd) * step(t1.yzx, t1.xyz) * step(t1.zxy, t1.xyz); return vec2(tN, tF); } fn spherePosition(id: i32, frame: i32) -> vec2 { let offset: vec4 = hash41(f32(id)) * tau; let fframe: f32 = f32(frame); return vec2(cos(offset.x + fframe * 0.015) + cos(offset.y + fframe * 0.02), cos(offset.z + fframe * 0.017) + cos(offset.w + fframe * 0.022)) * vec2(1., 0.5) * 0.9; } fn dist2(v: vec3) -> f32 { return dot(v, v); } fn sample_texture(ch: texture_storage_2d, U01: vec2) -> vec4 { let U = U01 * uni.iResolution; let f = vec2(floor(U)); let c = vec2(ceil(U)); let fr = fract(U); let upleft = vec2( f.x, c.y ); let upright = vec2( c.x , c.y ); let downleft = vec2( f.x, f.y ); let downright = vec2( c.x , f.y ); let interpolated_2d = ( (1. - fr.x) * (1. - fr.y) * textureLoad(ch, downleft) + (1. - fr.x) * fr.y * textureLoad(ch, upleft) + fr.x * fr.y * textureLoad(ch, upright) + fr.x * (1. - fr.y) * textureLoad(ch, downright) ); return interpolated_2d; } var location: vec2; fn div(x: i32, y: i32) -> f32 { return textureLoad(buffer_b, vec2(location + vec2(x, y))).x; } fn getDiv() -> f32 { var p: f32 = 0.; p = p + (1. * div(-9, 0)); p = p + (9. * div(-8, -1)); p = p + (4. * div(-8, 0)); p = p + (9. * div(-8, 1)); p = p + (36. * div(-7, -2)); p = p + (32. * div(-7, -1)); p = p + (97. * div(-7, 0)); p = p + (32. * div(-7, 1)); p = p + (36. * div(-7, 2)); p = p + (84. * div(-6, -3)); p = p + (112. * div(-6, -2)); p = p + (436. * div(-6, -1)); p = p + (320. * div(-6, 0)); p = p + (436. * div(-6, 1)); p = p + (112. * div(-6, 2)); p = p + (84. * div(-6, 3)); p = p + (126. * div(-5, -4)); p = p + (224. * div(-5, -3)); p = p + (1092. * div(-5, -2)); p = p + (1280. * div(-5, -1)); p = p + (2336. * div(-5, 0)); p = p + (1280. * div(-5, 1)); p = p + (1092. * div(-5, 2)); p = p + (224. * div(-5, 3)); p = p + (126. * div(-5, 4)); p = p + (126. * div(-4, -5)); p = p + (280. * div(-4, -4)); p = p + (1694. * div(-4, -3)); p = p + (2752. * div(-4, -2)); p = p + (6656. * div(-4, -1)); p = p + (6464. * div(-4, 0)); p = p + (6656. * div(-4, 1)); p = p + (2752. * div(-4, 2)); p = p + (1694. * div(-4, 3)); p = p + (280. * div(-4, 4)); p = p + (126. * div(-4, 5)); p = p + (84. * div(-3, -6)); p = p + (224. * div(-3, -5)); p = p + (1694. * div(-3, -4)); p = p + (3520. * div(-3, -3)); p = p + (11016. * div(-3, -2)); p = p + (16128. * div(-3, -1)); p = p + (24608. * div(-3, 0)); p = p + (16128. * div(-3, 1)); p = p + (11016. * div(-3, 2)); p = p + (3520. * div(-3, 3)); p = p + (1694. * div(-3, 4)); p = p + (224. * div(-3, 5)); p = p + (84. * div(-3, 6)); p = p + (36. * div(-2, -7)); p = p + (112. * div(-2, -6)); p = p + (1092. * div(-2, -5)); p = p + (2752. * div(-2, -4)); p = p + (11016. * div(-2, -3)); p = p + (21664. * div(-2, -2)); p = p + (47432. * div(-2, -1)); p = p + (59712. * div(-2, 0)); p = p + (47432. * div(-2, 1)); p = p + (21664. * div(-2, 2)); p = p + (11016. * div(-2, 3)); p = p + (2752. * div(-2, 4)); p = p + (1092. * div(-2, 5)); p = p + (112. * div(-2, 6)); p = p + (36. * div(-2, 7)); p = p + (9. * div(-1, -8)); p = p + (32. * div(-1, -7)); p = p + (436. * div(-1, -6)); p = p + (1280. * div(-1, -5)); p = p + (6656. * div(-1, -4)); p = p + (16128. * div(-1, -3)); p = p + (47432. * div(-1, -2)); p = p + (92224. * div(-1, -1)); p = p + (163476. * div(-1, 0)); p = p + (92224. * div(-1, 1)); p = p + (47432. * div(-1, 2)); p = p + (16128. * div(-1, 3)); p = p + (6656. * div(-1, 4)); p = p + (1280. * div(-1, 5)); p = p + (436. * div(-1, 6)); p = p + (32. * div(-1, 7)); p = p + (9. * div(-1, 8)); p = p + (1. * div(0, -9)); p = p + (4. * div(0, -8)); p = p + (97. * div(0, -7)); p = p + (320. * div(0, -6)); p = p + (2336. * div(0, -5)); p = p + (6464. * div(0, -4)); p = p + (24608. * div(0, -3)); p = p + (59712. * div(0, -2)); p = p + (163476. * div(0, -1)); p = p + (409744. * div(0, 0)); p = p + (163476. * div(0, 1)); p = p + (59712. * div(0, 2)); p = p + (24608. * div(0, 3)); p = p + (6464. * div(0, 4)); p = p + (2336. * div(0, 5)); p = p + (320. * div(0, 6)); p = p + (97. * div(0, 7)); p = p + (4. * div(0, 8)); p = p + (1. * div(0, 9)); p = p + (9. * div(1, -8)); p = p + (32. * div(1, -7)); p = p + (436. * div(1, -6)); p = p + (1280. * div(1, -5)); p = p + (6656. * div(1, -4)); p = p + (16128. * div(1, -3)); p = p + (47432. * div(1, -2)); p = p + (92224. * div(1, -1)); p = p + (163476. * div(1, 0)); p = p + (92224. * div(1, 1)); p = p + (47432. * div(1, 2)); p = p + (16128. * div(1, 3)); p = p + (6656. * div(1, 4)); p = p + (1280. * div(1, 5)); p = p + (436. * div(1, 6)); p = p + (32. * div(1, 7)); p = p + (9. * div(1, 8)); p = p + (36. * div(2, -7)); p = p + (112. * div(2, -6)); p = p + (1092. * div(2, -5)); p = p + (2752. * div(2, -4)); p = p + (11016. * div(2, -3)); p = p + (21664. * div(2, -2)); p = p + (47432. * div(2, -1)); p = p + (59712. * div(2, 0)); p = p + (47432. * div(2, 1)); p = p + (21664. * div(2, 2)); p = p + (11016. * div(2, 3)); p = p + (2752. * div(2, 4)); p = p + (1092. * div(2, 5)); p = p + (112. * div(2, 6)); p = p + (36. * div(2, 7)); p = p + (84. * div(3, -6)); p = p + (224. * div(3, -5)); p = p + (1694. * div(3, -4)); p = p + (3520. * div(3, -3)); p = p + (11016. * div(3, -2)); p = p + (16128. * div(3, -1)); p = p + (24608. * div(3, 0)); p = p + (16128. * div(3, 1)); p = p + (11016. * div(3, 2)); p = p + (3520. * div(3, 3)); p = p + (1694. * div(3, 4)); p = p + (224. * div(3, 5)); p = p + (84. * div(3, 6)); p = p + (126. * div(4, -5)); p = p + (280. * div(4, -4)); p = p + (1694. * div(4, -3)); p = p + (2752. * div(4, -2)); p = p + (6656. * div(4, -1)); p = p + (6464. * div(4, 0)); p = p + (6656. * div(4, 1)); p = p + (2752. * div(4, 2)); p = p + (1694. * div(4, 3)); p = p + (280. * div(4, 4)); p = p + (126. * div(4, 5)); p = p + (126. * div(5, -4)); p = p + (224. * div(5, -3)); p = p + (1092. * div(5, -2)); p = p + (1280. * div(5, -1)); p = p + (2336. * div(5, 0)); p = p + (1280. * div(5, 1)); p = p + (1092. * div(5, 2)); p = p + (224. * div(5, 3)); p = p + (126. * div(5, 4)); p = p + (84. * div(6, -3)); p = p + (112. * div(6, -2)); p = p + (436. * div(6, -1)); p = p + (320. * div(6, 0)); p = p + (436. * div(6, 1)); p = p + (112. * div(6, 2)); p = p + (84. * div(6, 3)); p = p + (36. * div(7, -2)); p = p + (32. * div(7, -1)); p = p + (97. * div(7, 0)); p = p + (32. * div(7, 1)); p = p + (36. * div(7, 2)); p = p + (9. * div(8, -1)); p = p + (4. * div(8, 0)); p = p + (9. * div(8, 1)); p = p + (1. * div(9, 0)); return p / 1048576.; } fn pre(x: i32, y: i32) -> f32 { return textureLoad(buffer_d, vec2(location + vec2(x, y))).x; } fn getPre() -> f32 { var p: f32 = 0.; p = p + (1. * pre(-10, 0)); p = p + (10. * pre(-9, -1)); p = p + (10. * pre(-9, 1)); p = p + (45. * pre(-8, -2)); p = p + (100. * pre(-8, 0)); p = p + (45. * pre(-8, 2)); p = p + (120. * pre(-7, -3)); p = p + (450. * pre(-7, -1)); p = p + (450. * pre(-7, 1)); p = p + (120. * pre(-7, 3)); p = p + (210. * pre(-6, -4)); p = p + (1200. * pre(-6, -2)); p = p + (2025. * pre(-6, 0)); p = p + (1200. * pre(-6, 2)); p = p + (210. * pre(-6, 4)); p = p + (252. * pre(-5, -5)); p = p + (2100. * pre(-5, -3)); p = p + (5400. * pre(-5, -1)); p = p + (5400. * pre(-5, 1)); p = p + (2100. * pre(-5, 3)); p = p + (252. * pre(-5, 5)); p = p + (210. * pre(-4, -6)); p = p + (2520. * pre(-4, -4)); p = p + (9450. * pre(-4, -2)); p = p + (14400. * pre(-4, 0)); p = p + (9450. * pre(-4, 2)); p = p + (2520. * pre(-4, 4)); p = p + (210. * pre(-4, 6)); p = p + (120. * pre(-3, -7)); p = p + (2100. * pre(-3, -5)); p = p + (11340. * pre(-3, -3)); p = p + (25200. * pre(-3, -1)); p = p + (25200. * pre(-3, 1)); p = p + (11340. * pre(-3, 3)); p = p + (2100. * pre(-3, 5)); p = p + (120. * pre(-3, 7)); p = p + (45. * pre(-2, -8)); p = p + (1200. * pre(-2, -6)); p = p + (9450. * pre(-2, -4)); p = p + (30240. * pre(-2, -2)); p = p + (44100. * pre(-2, 0)); p = p + (30240. * pre(-2, 2)); p = p + (9450. * pre(-2, 4)); p = p + (1200. * pre(-2, 6)); p = p + (45. * pre(-2, 8)); p = p + (10. * pre(-1, -9)); p = p + (450. * pre(-1, -7)); p = p + (5400. * pre(-1, -5)); p = p + (25200. * pre(-1, -3)); p = p + (52920. * pre(-1, -1)); p = p + (52920. * pre(-1, 1)); p = p + (25200. * pre(-1, 3)); p = p + (5400. * pre(-1, 5)); p = p + (450. * pre(-1, 7)); p = p + (10. * pre(-1, 9)); p = p + (1. * pre(0, -10)); p = p + (100. * pre(0, -8)); p = p + (2025. * pre(0, -6)); p = p + (14400. * pre(0, -4)); p = p + (44100. * pre(0, -2)); p = p + (63504. * pre(0, 0)); p = p + (44100. * pre(0, 2)); p = p + (14400. * pre(0, 4)); p = p + (2025. * pre(0, 6)); p = p + (100. * pre(0, 8)); p = p + (1. * pre(0, 10)); p = p + (10. * pre(1, -9)); p = p + (450. * pre(1, -7)); p = p + (5400. * pre(1, -5)); p = p + (25200. * pre(1, -3)); p = p + (52920. * pre(1, -1)); p = p + (52920. * pre(1, 1)); p = p + (25200. * pre(1, 3)); p = p + (5400. * pre(1, 5)); p = p + (450. * pre(1, 7)); p = p + (10. * pre(1, 9)); p = p + (45. * pre(2, -8)); p = p + (1200. * pre(2, -6)); p = p + (9450. * pre(2, -4)); p = p + (30240. * pre(2, -2)); p = p + (44100. * pre(2, 0)); p = p + (30240. * pre(2, 2)); p = p + (9450. * pre(2, 4)); p = p + (1200. * pre(2, 6)); p = p + (45. * pre(2, 8)); p = p + (120. * pre(3, -7)); p = p + (2100. * pre(3, -5)); p = p + (11340. * pre(3, -3)); p = p + (25200. * pre(3, -1)); p = p + (25200. * pre(3, 1)); p = p + (11340. * pre(3, 3)); p = p + (2100. * pre(3, 5)); p = p + (120. * pre(3, 7)); p = p + (210. * pre(4, -6)); p = p + (2520. * pre(4, -4)); p = p + (9450. * pre(4, -2)); p = p + (14400. * pre(4, 0)); p = p + (9450. * pre(4, 2)); p = p + (2520. * pre(4, 4)); p = p + (210. * pre(4, 6)); p = p + (252. * pre(5, -5)); p = p + (2100. * pre(5, -3)); p = p + (5400. * pre(5, -1)); p = p + (5400. * pre(5, 1)); p = p + (2100. * pre(5, 3)); p = p + (252. * pre(5, 5)); p = p + (210. * pre(6, -4)); p = p + (1200. * pre(6, -2)); p = p + (2025. * pre(6, 0)); p = p + (1200. * pre(6, 2)); p = p + (210. * pre(6, 4)); p = p + (120. * pre(7, -3)); p = p + (450. * pre(7, -1)); p = p + (450. * pre(7, 1)); p = p + (120. * pre(7, 3)); p = p + (45. * pre(8, -2)); p = p + (100. * pre(8, 0)); p = p + (45. * pre(8, 2)); p = p + (10. * pre(9, -1)); p = p + (10. * pre(9, 1)); p = p + (1. * pre(10, 0)); return p / 1048576.; } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var fragColor: vec4 = vec4(0.0, 0.0, 0.0, 0.0); var C = vec2(f32(location.x), f32(location.y) ); let div: f32 = getDiv(); let p: f32 = getPre() - div; fragColor = vec4(p, div, vec2(1.)); textureStore(buffer_c, location, fragColor); } ================================================ FILE: assets/shaders/dry_ice/buffer_d.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; let dissipation: f32 = 0.95; let ballRadius: f32 = 0.06; let fogHeigth: f32 = 0.24; let nbSlice: i32 = 24; let fogSlice: f32 = 0.01; let nbSphere: i32 = 3; let shadowDensity: f32 = 25.; let fogDensity: f32 = 20.; let lightHeight: f32 = 1.; let tau: f32 = 6.28318530718; fn hash12(p: vec2) -> f32 { var p3: vec3 = fract(vec3(p.xyx) * 0.1031); p3 = p3 + (dot(p3, p3.yzx + 33.33)); return fract((p3.x + p3.y) * p3.z); } fn hash41(p: f32) -> vec4 { var p4: vec4 = fract(vec4(p) * vec4(0.1031, 0.103, 0.0973, 0.1099)); p4 = p4 + (dot(p4, p4.wzxy + 33.33)); return fract((p4.xxyz + p4.yzzw) * p4.zywx); } fn rotate(angle: f32, radius: f32) -> vec2 { return vec2(cos(angle), -sin(angle)) * radius; } fn floorIntersect(ro: vec3, rd: vec3, floorHeight: f32, t: ptr) -> bool { var ro_var = ro; ro_var.y = ro_var.y - (floorHeight); if (rd.y < -0.01) { (*t) = ro_var.y / -rd.y; return true; } return false; } fn sphIntersect(ro: vec3, rd: vec3, ce: vec3, ra: f32) -> vec2 { let oc: vec3 = ro - ce; let b: f32 = dot(oc, rd); let c: f32 = dot(oc, oc) - ra * ra; var h: f32 = b * b - c; if (h < 0.) { return vec2(-1.); } h = sqrt(h); return vec2(-b - h, -b + h); } fn boxIntersection(ro: vec3, rd: vec3, rad: vec3, center: vec3, oN: ptr>) -> vec2 { var ro_var = ro; ro_var = ro_var - (center); let m: vec3 = 1. / rd; let n: vec3 = m * ro_var; let k: vec3 = abs(m) * rad; let t1: vec3 = -n - k; let t2: vec3 = -n + k; let tN: f32 = max(max(t1.x, t1.y), t1.z); let tF: f32 = min(min(t2.x, t2.y), t2.z); if (tN > tF || tF < 0.) { return vec2(-1.); } (*oN) = -sign(rd) * step(t1.yzx, t1.xyz) * step(t1.zxy, t1.xyz); return vec2(tN, tF); } fn spherePosition(id: i32, frame: i32) -> vec2 { let offset: vec4 = hash41(f32(id)) * tau; let fframe: f32 = f32(frame); return vec2(cos(offset.x + fframe * 0.015) + cos(offset.y + fframe * 0.02), cos(offset.z + fframe * 0.017) + cos(offset.w + fframe * 0.022)) * vec2(1., 0.5) * 0.9; } fn dist2(v: vec3) -> f32 { return dot(v, v); } fn sample_texture(ch: texture_storage_2d, U01: vec2) -> vec4 { let U = U01 * uni.iResolution; let f = vec2(floor(U)); let c = vec2(ceil(U)); let fr = fract(U); let upleft = vec2( f.x, c.y ); let upright = vec2( c.x , c.y ); let downleft = vec2( f.x, f.y ); let downright = vec2( c.x , f.y ); let interpolated_2d = ( (1. - fr.x) * (1. - fr.y) * textureLoad(ch, downleft) + (1. - fr.x) * fr.y * textureLoad(ch, upleft) + fr.x * fr.y * textureLoad(ch, upright) + fr.x * (1. - fr.y) * textureLoad(ch, downright) ); return interpolated_2d; } var location: vec2; fn div(x: i32, y: i32) -> f32 { return textureLoad(buffer_c, vec2(location + vec2(x, y))).y; } fn pre(x: i32, y: i32) -> f32 { return textureLoad(buffer_c, vec2(location + vec2(x, y))).x; } fn getPre() -> f32 { var p: f32 = 0.; p = p + (1. * pre(-10, 0)); p = p + (10. * pre(-9, -1)); p = p + (10. * pre(-9, 1)); p = p + (45. * pre(-8, -2)); p = p + (100. * pre(-8, 0)); p = p + (45. * pre(-8, 2)); p = p + (120. * pre(-7, -3)); p = p + (450. * pre(-7, -1)); p = p + (450. * pre(-7, 1)); p = p + (120. * pre(-7, 3)); p = p + (210. * pre(-6, -4)); p = p + (1200. * pre(-6, -2)); p = p + (2025. * pre(-6, 0)); p = p + (1200. * pre(-6, 2)); p = p + (210. * pre(-6, 4)); p = p + (252. * pre(-5, -5)); p = p + (2100. * pre(-5, -3)); p = p + (5400. * pre(-5, -1)); p = p + (5400. * pre(-5, 1)); p = p + (2100. * pre(-5, 3)); p = p + (252. * pre(-5, 5)); p = p + (210. * pre(-4, -6)); p = p + (2520. * pre(-4, -4)); p = p + (9450. * pre(-4, -2)); p = p + (14400. * pre(-4, 0)); p = p + (9450. * pre(-4, 2)); p = p + (2520. * pre(-4, 4)); p = p + (210. * pre(-4, 6)); p = p + (120. * pre(-3, -7)); p = p + (2100. * pre(-3, -5)); p = p + (11340. * pre(-3, -3)); p = p + (25200. * pre(-3, -1)); p = p + (25200. * pre(-3, 1)); p = p + (11340. * pre(-3, 3)); p = p + (2100. * pre(-3, 5)); p = p + (120. * pre(-3, 7)); p = p + (45. * pre(-2, -8)); p = p + (1200. * pre(-2, -6)); p = p + (9450. * pre(-2, -4)); p = p + (30240. * pre(-2, -2)); p = p + (44100. * pre(-2, 0)); p = p + (30240. * pre(-2, 2)); p = p + (9450. * pre(-2, 4)); p = p + (1200. * pre(-2, 6)); p = p + (45. * pre(-2, 8)); p = p + (10. * pre(-1, -9)); p = p + (450. * pre(-1, -7)); p = p + (5400. * pre(-1, -5)); p = p + (25200. * pre(-1, -3)); p = p + (52920. * pre(-1, -1)); p = p + (52920. * pre(-1, 1)); p = p + (25200. * pre(-1, 3)); p = p + (5400. * pre(-1, 5)); p = p + (450. * pre(-1, 7)); p = p + (10. * pre(-1, 9)); p = p + (1. * pre(0, -10)); p = p + (100. * pre(0, -8)); p = p + (2025. * pre(0, -6)); p = p + (14400. * pre(0, -4)); p = p + (44100. * pre(0, -2)); p = p + (63504. * pre(0, 0)); p = p + (44100. * pre(0, 2)); p = p + (14400. * pre(0, 4)); p = p + (2025. * pre(0, 6)); p = p + (100. * pre(0, 8)); p = p + (1. * pre(0, 10)); p = p + (10. * pre(1, -9)); p = p + (450. * pre(1, -7)); p = p + (5400. * pre(1, -5)); p = p + (25200. * pre(1, -3)); p = p + (52920. * pre(1, -1)); p = p + (52920. * pre(1, 1)); p = p + (25200. * pre(1, 3)); p = p + (5400. * pre(1, 5)); p = p + (450. * pre(1, 7)); p = p + (10. * pre(1, 9)); p = p + (45. * pre(2, -8)); p = p + (1200. * pre(2, -6)); p = p + (9450. * pre(2, -4)); p = p + (30240. * pre(2, -2)); p = p + (44100. * pre(2, 0)); p = p + (30240. * pre(2, 2)); p = p + (9450. * pre(2, 4)); p = p + (1200. * pre(2, 6)); p = p + (45. * pre(2, 8)); p = p + (120. * pre(3, -7)); p = p + (2100. * pre(3, -5)); p = p + (11340. * pre(3, -3)); p = p + (25200. * pre(3, -1)); p = p + (25200. * pre(3, 1)); p = p + (11340. * pre(3, 3)); p = p + (2100. * pre(3, 5)); p = p + (120. * pre(3, 7)); p = p + (210. * pre(4, -6)); p = p + (2520. * pre(4, -4)); p = p + (9450. * pre(4, -2)); p = p + (14400. * pre(4, 0)); p = p + (9450. * pre(4, 2)); p = p + (2520. * pre(4, 4)); p = p + (210. * pre(4, 6)); p = p + (252. * pre(5, -5)); p = p + (2100. * pre(5, -3)); p = p + (5400. * pre(5, -1)); p = p + (5400. * pre(5, 1)); p = p + (2100. * pre(5, 3)); p = p + (252. * pre(5, 5)); p = p + (210. * pre(6, -4)); p = p + (1200. * pre(6, -2)); p = p + (2025. * pre(6, 0)); p = p + (1200. * pre(6, 2)); p = p + (210. * pre(6, 4)); p = p + (120. * pre(7, -3)); p = p + (450. * pre(7, -1)); p = p + (450. * pre(7, 1)); p = p + (120. * pre(7, 3)); p = p + (45. * pre(8, -2)); p = p + (100. * pre(8, 0)); p = p + (45. * pre(8, 2)); p = p + (10. * pre(9, -1)); p = p + (10. * pre(9, 1)); p = p + (1. * pre(10, 0)); return p / 1048576.; } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var fragColor: vec4 = vec4(0.0, 0.0, 0.0, 0.0); var C = vec2(f32(location.x), f32(location.y) ); let p: f32 = getPre() - div(0, 0); fragColor = vec4(p, vec3(1.)); textureStore(buffer_d, location, fragColor); } ================================================ FILE: assets/shaders/dry_ice/image.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @group(0) @binding(5) var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; @group(0) @binding(6) var font_texture: texture_2d; @group(0) @binding(7) var font_texture_sampler: sampler; @group(0) @binding(8) var rgba_noise_256_texture: texture_2d; @group(0) @binding(9) var rgba_noise_256_texture_sampler: sampler; @group(0) @binding(10) var blue_noise_texture: texture_2d; @group(0) @binding(11) var blue_noise_texture_sampler: sampler; let dissipation: f32 = 0.95; let ballRadius: f32 = 0.06; let fogHeigth: f32 = 0.24; let nbSlice: i32 = 24; let fogSlice: f32 = 0.01; let nbSphere: i32 = 3; let shadowDensity: f32 = 25.; let fogDensity: f32 = 20.; let lightHeight: f32 = 1.; let tau: f32 = 6.28318530718; fn hash12(p: vec2) -> f32 { var p3: vec3 = fract(vec3(p.xyx) * 0.1031); p3 = p3 + (dot(p3, p3.yzx + 33.33)); return fract((p3.x + p3.y) * p3.z); } fn hash41(p: f32) -> vec4 { var p4: vec4 = fract(vec4(p) * vec4(0.1031, 0.103, 0.0973, 0.1099)); p4 = p4 + (dot(p4, p4.wzxy + 33.33)); return fract((p4.xxyz + p4.yzzw) * p4.zywx); } fn rotate(angle: f32, radius: f32) -> vec2 { return vec2(cos(angle), -sin(angle)) * radius; } fn floorIntersect(ro: vec3, rd: vec3, floorHeight: f32, t: ptr) -> bool { var ro_var = ro; ro_var.y = ro_var.y - (floorHeight); if (rd.y < -0.01) { (*t) = ro_var.y / -rd.y; return true; } return false; } fn sphIntersect(ro: vec3, rd: vec3, ce: vec3, ra: f32) -> vec2 { let oc: vec3 = ro - ce; let b: f32 = dot(oc, rd); let c: f32 = dot(oc, oc) - ra * ra; var h: f32 = b * b - c; if (h < 0.) { return vec2(-1.); } h = sqrt(h); return vec2(-b - h, -b + h); } fn boxIntersection(ro: vec3, rd: vec3, rad: vec3, center: vec3, oN: ptr>) -> vec2 { var ro_var = ro; ro_var = ro_var - (center); let m: vec3 = 1. / rd; let n: vec3 = m * ro_var; let k: vec3 = abs(m) * rad; let t1: vec3 = -n - k; let t2: vec3 = -n + k; let tN: f32 = max(max(t1.x, t1.y), t1.z); let tF: f32 = min(min(t2.x, t2.y), t2.z); if (tN > tF || tF < 0.) { return vec2(-1.); } (*oN) = -sign(rd) * step(t1.yzx, t1.xyz) * step(t1.zxy, t1.xyz); return vec2(tN, tF); } fn spherePosition(id: i32, frame: i32) -> vec2 { let offset: vec4 = hash41(f32(id)) * tau; let fframe: f32 = f32(frame); return vec2(cos(offset.x + fframe * 0.015) + cos(offset.y + fframe * 0.02), cos(offset.z + fframe * 0.017) + cos(offset.w + fframe * 0.022)) * vec2(1., 0.5) * 0.9; } fn dist2(v: vec3) -> f32 { return dot(v, v); } fn sample_texture(ch: texture_storage_2d, U01: vec2) -> vec4 { let U = U01 * uni.iResolution; let f = vec2(floor(U)); let c = vec2(ceil(U)); let fr = fract(U); let upleft = vec2( f.x, c.y ); let upright = vec2( c.x , c.y ); let downleft = vec2( f.x, f.y ); let downright = vec2( c.x , f.y ); let interpolated_2d = ( (1. - fr.x) * (1. - fr.y) * textureLoad(ch, downleft) + (1. - fr.x) * fr.y * textureLoad(ch, upleft) + fr.x * fr.y * textureLoad(ch, upright) + fr.x * (1. - fr.y) * textureLoad(ch, downright) ); return interpolated_2d; } // https://www.shadertoy.com/view/WlVyRV // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 fn sceneIntersection(ro: vec3, rd: vec3, inter: ptr>, normal: ptr>, color: ptr>, dist: f32, lightPos: ptr>) -> f32 { var mint: f32 = dist; (*inter) = vec3(0.); (*normal) = vec3(0.); (*color) = vec3(0.); for (var i: i32 = 0; i < nbSphere; i = i + 1) { let p2d: vec2 = spherePosition(i, i32(uni.iFrame)); let pos: vec3 = vec3(p2d.x, ballRadius, p2d.y); var ballColor: vec3 = vec3(1., 0., 0.); if (i == 0) { ballColor = vec3(1.); (*lightPos) = pos + vec3(0., lightHeight, 0.); } var t: f32 = sphIntersect(ro, rd, pos, ballRadius).x; if (t > 0. && t < mint) { mint = t; (*inter) = ro + mint * rd; (*normal) = normalize((*inter) - pos); (*color) = ballColor; } } let aspecRatio: f32 = uni.iResolution.x / uni.iResolution.y; var boxNormal: vec3; let t: f32 = boxIntersection(ro, rd, vec3(aspecRatio, 0.1, 1.), vec3(0., -0.1, 0.), &boxNormal).x; if (t > 0. && t < mint) { mint = t; (*inter) = ro + mint * rd; (*normal) = boxNormal; let tileId: vec2 = vec2(vec2((*inter).x, (*inter).z) * 3. + 100.); if ((tileId.x & 1 ^ tileId.y & 1) == 0) { (*color) =vec3(0.3); } else { (*color) =vec3(0.15); }; } return mint; } fn sampleFog(pos: vec3) -> f32 { var uv: vec2 = pos.xz; uv.x = uv.x * (uni.iResolution.y / uni.iResolution.x); uv = uv * 0.5 + 0.5; if (max(uv.x, uv.y) > 1. || min(uv.x, uv.y) < 0.) { return 0.; } return sample_texture(buffer_a, uv).z; } fn Render(ro: vec3, rd: vec3, dist: f32, fudge: f32) -> vec3 { var inter: vec3; var normal: vec3; var baseColor: vec3; var lightPos: vec3; let mint: f32 = sceneIntersection(ro, rd, &inter, &normal, &baseColor, dist, &lightPos); var color: vec3 = vec3(0.); if (mint < dist) { var lightDir: vec3 = normalize(lightPos - inter); var lightDist2: f32 = dist2(lightPos - inter); var shadowStep: vec3 = fogHeigth / f32(nbSlice) * lightDir / lightDir.y; var shadowDist: f32 = 0.; for (var i: i32 = 0; i < nbSlice; i = i + 1) { var shadowPos: vec3 = inter + shadowStep * f32(i); let v: f32 = sampleFog(shadowPos) * fogHeigth; shadowDist = shadowDist + (min(max(0., v - shadowPos.y), fogSlice) * length(shadowStep) / fogSlice); } var shadowFactor: f32 = exp(-shadowDist * shadowDensity * 0.25); color = baseColor * (max(0., dot(normal, lightDir) * shadowFactor) + 0.2) / lightDist2; } else { color = vec3(0.); } var t: f32; if (floorIntersect(ro, rd, fogHeigth, &t)) { var curPos: vec3 = ro + rd * t; let fogStep: vec3 = fogHeigth / f32(nbSlice) * rd / abs(rd.y); curPos = curPos + (fudge * fogStep); let stepLen: f32 = length(fogStep); var curDensity: f32 = 0.; var transmittance: f32 = 1.; var lightEnergy: f32 = 0.; for (var i: i32 = 0; i < nbSlice; i = i + 1) { if (dot(curPos - ro, rd) > mint) { break; } let curHeigth: f32 = sampleFog(curPos) * fogHeigth; let curSample: f32 = min(max(0., curHeigth - curPos.y), fogSlice) * stepLen / fogSlice; if (curSample > 0.001) { let lightDir: vec3 = normalize(lightPos - curPos); let shadowStep: vec3 = fogHeigth / f32(nbSlice) * lightDir / lightDir.y; let lightDist2: f32 = dist2(lightPos - curPos); var shadowPos: vec3 = curPos + shadowStep * fudge; var shadowDist: f32 = 0.; for (var j: i32 = 0; j < nbSlice; j = j + 1) { shadowPos = shadowPos + (shadowStep); if (shadowPos.y > fogHeigth) { break; } let curHeight: f32 = sampleFog(shadowPos) * fogHeigth; shadowDist = shadowDist + (min(max(0., curHeight - shadowPos.y), fogSlice) * length(shadowStep) / fogSlice); } let shadowFactor: f32 = exp(-shadowDist * shadowDensity) / lightDist2; curDensity = curSample * fogDensity; let absorbedlight: f32 = shadowFactor * (1. * curDensity); lightEnergy = lightEnergy + (absorbedlight * transmittance); transmittance = transmittance * (1. - curDensity); } curPos = curPos + (fogStep); } color = mix(color, vec3(lightEnergy), 1. - transmittance); } return color; } fn vignette(color: vec3, q: vec2, v: f32) -> vec3 { var color_var = color; color_var = color_var * (0.3 + 0.8 * pow(16. * q.x * q.y * (1. - q.x) * (1. - q.y), v)); return color_var; } fn setCamera(ro: vec3, ta: vec3) -> mat3x3 { let cw: vec3 = normalize(ta - ro); let up: vec3 = vec3(0., 1., 0.); let cu: vec3 = normalize(cross(cw, up)); let cv: vec3 = normalize(cross(cu, cw)); return mat3x3(cu, cv, cw); } fn radians (degrees: f32) -> f32 { return degrees * ( 3.1416 / 180.); } fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var fragColor: vec4; var fragCoord = vec2(f32(location.x), f32(location.y) ); var tot: vec3 = vec3(0.); let p: vec2 = (-uni.iResolution.xy + 2. * fragCoord) / uni.iResolution.y; let theta: f32 = radians(360.) * (uni.iMouse.x / uni.iResolution.x - 0.5) - radians(90.); let phi: f32 = -radians(30.); let ro: vec3 = 2. * vec3(sin(phi) * cos(theta), cos(phi), sin(phi) * sin(theta)); let ta: vec3 = vec3(0.); let ca: mat3x3 = setCamera(ro, ta); let rd: vec3 = ca * normalize(vec3(p, 1.5)); let col: vec3 = Render(ro, rd, 6., hash12(fragCoord + uni.iTime)); tot = tot + (col); tot = vignette(tot, fragCoord / uni.iResolution.xy, 0.6); fragColor = vec4(sqrt(tot), 1.); textureStore(texture, y_inverted_location, toLinear(fragColor)); } // fn sceneIntersection( // ro: vec3, // rd: vec3, // inter: ptr>, // normal: ptr>, // color: ptr>, // dist: f32, // lightPos: ptr> // ) -> f32 { // var mint: f32 = dist; // (*inter) = vec3(0.); // (*normal) = vec3(0.); // (*color) = vec3(0.); // for (var i: i32 = 0; i < nbSphere; i = i + 1) { // let p2d: vec2 = spherePosition(i, i32(uni.iFrame)); // let pos: vec3 = vec3(p2d.x, ballRadius, p2d.y); // var ballColor: vec3 = vec3(1., 0., 0.); // if (i == 0) { // ballColor = vec3(1.); // (*lightPos) = pos + vec3(0., lightHeight, 0.); // } // var t: f32 = sphIntersect(ro, rd, pos, ballRadius).x; // if (t > 0. && t < mint) { // mint = t; // (*inter) = ro + mint * rd; // (*normal) = normalize((*inter) - pos); // (*color) = ballColor; // } // } // let aspecRatio: f32 = uni.iResolution.x / uni.iResolution.y; // var boxNormal: vec3 = vec3(0. ); // let t: f32 = boxIntersection(ro, rd, vec3(aspecRatio, 0.1, 1.), vec3(0., -0.1, 0.), &boxNormal).x; // if (t > 0. && t < mint) { // mint = t; // (*inter) = ro + mint * rd; // (*normal) = boxNormal; // let tileId: vec2 = vec2(vec2((*inter).x, (*inter).z) * 3. + 100.); // if ((tileId.x & 1 ^ tileId.y & 1) == 0) {(*color) = vec3(0.3); } else { (*color) = vec3(0.15); }; // } // return mint; // } // fn sampleFog(pos: vec3) -> f32 { // var uv: vec2 = pos.xz; // uv.x = uv.x * (uni.iResolution.y / uni.iResolution.x); // uv = uv * 0.5 + 0.5; // if (max(uv.x, uv.y) > 1. || min(uv.x, uv.y) < 0.) { // return 0.; // } // return sample_texture(buffer_a, uv).z; // } // fn Render(ro: vec3, rd: vec3, dist: f32, fudge: f32) -> vec3 { // var inter: vec3 = vec3(0.); // var normal: vec3 = vec3(0.); // var baseColor: vec3 = vec3(0.); // var lightPos: vec3 = vec3(0.); // let mint: f32 = sceneIntersection(ro, rd, &inter, &normal, &baseColor, dist, &lightPos); // var color: vec3 = vec3(0.); // if (mint < dist) { // var lightDir: vec3 = normalize(lightPos - inter); // var lightDist2: f32 = dist2(lightPos - inter); // var shadowStep: vec3 = fogHeigth / f32(nbSlice) * lightDir / lightDir.y; // var shadowDist: f32 = 0.; // for (var i: i32 = 0; i < nbSlice; i = i + 1) { // var shadowPos: vec3 = inter + shadowStep * f32(i); // let v: f32 = sampleFog(shadowPos) * fogHeigth; // shadowDist = shadowDist + (min(max(0., v - shadowPos.y), fogSlice) * length(shadowStep) / fogSlice); // } // var shadowFactor: f32 = exp(-shadowDist * shadowDensity * 0.25); // color = baseColor * (max(0., dot(normal, lightDir) * shadowFactor) + 0.2) / lightDist2; // } else { // color = vec3(0.); // } // var t: f32 = 0.; // if (floorIntersect(ro, rd, fogHeigth, &t)) { // var curPos: vec3 = ro + rd * t; // let fogStep: vec3 = fogHeigth / f32(nbSlice) * rd / abs(rd.y); // curPos = curPos + (fudge * fogStep); // let stepLen: f32 = length(fogStep); // var curDensity: f32 = 0.; // var transmittance: f32 = 1.; // var lightEnergy: f32 = 0.; // for (var i: i32 = 0; i < nbSlice; i = i + 1) { // if (dot(curPos - ro, rd) > mint) { break; // } // let curHeigth: f32 = sampleFog(curPos) * fogHeigth; // let curSample: f32 = min(max(0., curHeigth - curPos.y), fogSlice) * stepLen / fogSlice; // if (curSample > 0.001) { // let lightDir: vec3 = normalize(lightPos - curPos); // let shadowStep: vec3 = fogHeigth / f32(nbSlice) * lightDir / lightDir.y; // let lightDist2: f32 = dist2(lightPos - curPos); // var shadowPos: vec3 = curPos + shadowStep * fudge; // var shadowDist: f32 = 0.; // for (var j: i32 = 0; j < nbSlice; j = j + 1) { // shadowPos = shadowPos + (shadowStep); // if (shadowPos.y > fogHeigth) { // break; // } // let curHeight: f32 = sampleFog(shadowPos) * fogHeigth; // shadowDist = shadowDist + (min(max(0., curHeight - shadowPos.y), fogSlice) * length(shadowStep) / fogSlice); // } // let shadowFactor: f32 = exp(-shadowDist * shadowDensity) / lightDist2; // curDensity = curSample * fogDensity; // let absorbedlight: f32 = shadowFactor * (1. * curDensity); // lightEnergy = lightEnergy + (absorbedlight * transmittance); // transmittance = transmittance * (1. - curDensity); // } // curPos = curPos + (fogStep); // } // color = mix(color, vec3(lightEnergy), 1. - transmittance); // } // return color; // } // fn vignette(color: vec3, q: vec2, v: f32) -> vec3 { // var color_var = color; // color_var = color_var * (0.3 + 0.8 * pow(16. * q.x * q.y * (1. - q.x) * (1. - q.y), v)); // return color_var; // } // fn setCamera(ro: vec3, ta: vec3) -> mat3x3 { // let cw: vec3 = normalize(ta - ro); // let up: vec3 = vec3(0., 1., 0.); // let cu: vec3 = normalize(cross(cw, up)); // let cv: vec3 = normalize(cross(cu, cw)); // return mat3x3(cu, cv, cw); // } // fn radians(in: f32) -> f32 { // return in * (3.141592653589793 / 180.); // } // fn toLinear(sRGB: vec4) -> vec4 { // let cutoff = vec4(sRGB < vec4(0.04045)); // let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); // let lower = sRGB / vec4(12.92); // return mix(higher, lower, cutoff); // } // [[stage(compute), workgroup_size(8, 8, 1)]] // fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { // let R: vec2 = uni.iResolution.xy; // let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // var fragColor: vec4; // var fragCoord = vec2(f32(location.x), f32(location.y) ); // var tot: vec3 = vec3(0.); // var rook: array,4>; // rook[0] = vec2(1. / 8., 3. / 8.); // rook[1] = vec2(3. / 8., -1. / 8.); // rook[2] = vec2(-1. / 8., -3. / 8.); // rook[3] = vec2(-3. / 8., 1. / 8.); // for (var n: i32 = 0; n < 4; n = n + 1) { // let o: vec2 = rook[n]; // let p: vec2 = (-uni.iResolution.xy + 2. * (fragCoord + o)) / uni.iResolution.y; // let theta: f32 = radians(360.) * (uni.iMouse.x / uni.iResolution.x - 0.5) - radians(90.); // let phi: f32 = -radians(30.); // let ro: vec3 = 2. * vec3(sin(phi) * cos(theta), cos(phi), sin(phi) * sin(theta)); // let ta: vec3 = vec3(0.); // let ca: mat3x3 = setCamera(ro, ta); // let rd: vec3 = ca * normalize(vec3(p, 1.5)); // let col: vec3 = Render(ro, rd, 6., hash12(fragCoord + uni.iTime)); // tot = tot + (col); // } // tot = tot / (4.); // tot = vignette(tot, fragCoord / uni.iResolution.xy, 0.6); // fragColor = vec4(sqrt(tot), 1.); // textureStore(texture, y_inverted_location, toLinear(fragColor)); // } // // fn toLinear(sRGB: vec4) -> vec4 { // // let cutoff = vec4(sRGB < vec4(0.04045)); // // let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); // // let lower = sRGB / vec4(12.92); // // return mix(higher, lower, cutoff); // // } // // [[stage(compute), workgroup_size(8, 8, 1)]] // // fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { // // let R: vec2 = uni.iResolution.xy; // // let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); // // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // // var fragColor: vec4; // // var fragCoord = vec2(f32(location.x), f32(location.y) ); // // fragColor = vec4(vec3(sample_texture(buffer_a, fragCoord / uni.iResolution).z), 1.); // // textureStore(texture, y_inverted_location, toLinear(fragColor)); // // } ================================================ FILE: assets/shaders/fire/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let color = vec4(0.5); textureStore(buffer_a, location, color); } ================================================ FILE: assets/shaders/fire/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/fire/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/fire/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/fire/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // [[group(0), binding(1)]] // var buffer_a: texture_storage_2d; // [[group(0), binding(2)]] // var buffer_b: texture_storage_2d; // [[group(0), binding(3)]] // var buffer_c: texture_storage_2d; // [[group(0), binding(4)]] // var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; [[group(0), binding(6)]] var font_texture: texture_2d; [[group(0), binding(7)]] var font_texture_sampler: sampler; [[group(0), binding(8)]] var rgba_noise_256_texture: texture_2d; [[group(0), binding(9)]] var rgba_noise_256_texture_sampler: sampler; // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // let color = vec4(f32(0)); // textureStore(texture, location, color); // } // https://www.shadertoy.com/view/XsXSWS // no licence fn hash(p: vec2) -> vec2 { var p_var = p; p_var = vec2(dot(p_var, vec2(127.1, 311.7)), dot(p_var, vec2(269.5, 183.3))); return -1. + 2. * fract(sin(p_var) * 43758.547); } fn noise(p: vec2) -> f32 { let K1: f32 = 0.36602542; let K2: f32 = 0.21132487; let i: vec2 = floor(p + (p.x + p.y) * K1); var a: vec2 = p - i + (i.x + i.y) * K2; var o: vec2; if (a.x > a.y) { o = vec2(1., 0.); } else { o = vec2(0., 1.); }; let b: vec2 = a - o + K2; var c: vec2 = a - 1. + 2. * K2; let h: vec3 = max(0.5 - vec3(dot(a, a), dot(b, b), dot(c, c)), vec3(0.)); var n: vec3 = h * h * h * h * vec3(dot(a, hash(i + 0.)), dot(b, hash(i + o)), dot(c, hash(i + 1.))); return dot(n, vec3(70.)); } fn fbm(uv_in: vec2) -> f32 { var f: f32; var uv = uv_in; let m: mat2x2 = mat2x2(1.6, 1.2, -1.2, 1.6); f = 0.5 * noise(uv); uv = m * uv; f = f + (0.25 * noise(uv)); uv = m * uv; f = f + (0.125 * noise(uv)); uv = m * uv; f = f + (0.0625 * noise(uv)); uv = m * uv; f = 0.5 + 0.5 * f; return f; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var fragColor: vec4; var fragCoord = vec2(f32(location.x), f32(location.y) ); let uv: vec2 = fragCoord.xy / uni.iResolution.xy; var q: vec2 = uv; q.x = q.x * (5.); q.y = q.y * (2.); let strength: f32 = floor(q.x + 1.); let T3: f32 = max(3., 1.25 * strength) * uni.iTime; q.x = (q.x % 1.) - 0.5; q.y = q.y - (0.25); let n: f32 = fbm(strength * q - vec2(0., T3)); let c: f32 = 1. - 16. * pow(max(0., length(q * vec2(1.8 + q.y * 1.5, 0.75)) - n * max(0., q.y + 0.25)), 1.2); var c1: f32 = n * c * (1.5 - pow(2.5 * uv.y, 4.)); c1 = clamp(c1, 0., 1.); let col: vec3 = vec3(1.5 * c1, 1.5 * c1 * c1 * c1, c1 * c1 * c1 * c1 * c1 * c1); let a: f32 = c * (1. - pow(uv.y, 3.)); fragColor = vec4(mix(vec3(0.), col, a), 1.); textureStore(texture, y_inverted_location, fragColor); } ================================================ FILE: assets/shaders/fire2/buffer_a.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let color = vec4(0.5); textureStore(buffer_a, location, color); } ================================================ FILE: assets/shaders/fire2/buffer_b.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/fire2/buffer_c.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/fire2/buffer_d.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/fire2/image.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @group(0) @binding(5) var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; @group(0) @binding(6) var font_texture: texture_2d; @group(0) @binding(7) var font_texture_sampler: sampler; @group(0) @binding(8) var rgba_noise_256_texture: texture_2d; @group(0) @binding(9) var rgba_noise_256_texture_sampler: sampler; @group(0) @binding(10) var blue_noise_texture: texture_2d; @group(0) @binding(11) var blue_noise_texture_sampler: sampler; // original code: https://www.shadertoy.com/view/MlKSWm // MIT licence fn mod289(x: vec3) -> vec3 { return x - floor(x * (1. / 289.)) * 289.; } fn mod289_4(x: vec4) -> vec4 { return x - floor(x * (1. / 289.)) * 289.; } fn permute(x: vec4) -> vec4 { return mod289_4((x * 34. + 1.) * x); } fn taylorInvSqrt(r: vec4) -> vec4 { return 1.7928429 - 0.85373473 * r; } fn snoise(v: vec3) -> f32 { let C: vec2 = vec2(1. / 6., 1. / 3.); let D: vec4 = vec4(0., 0.5, 1., 2.); // First corner var i: vec3 = floor(v + dot(v, C.yyy)); let x0: vec3 = v - i + dot(i, C.xxx); // Other corners let g: vec3 = step(x0.yzx, x0.xyz); let l: vec3 = 1. - g; let i1: vec3 = min(g.xyz, l.zxy); let i2: vec3 = max(g.xyz, l.zxy); let x1: vec3 = x0 - i1 + C.xxx; let x2: vec3 = x0 - i2 + C.yyy; let x3: vec3 = x0 - D.yyy; // Permutations i = mod289(i); let p: vec4 = permute(permute(permute(i.z + vec4(0., i1.z, i2.z, 1.)) + i.y + vec4(0., i1.y, i2.y, 1.)) + i.x + vec4(0., i1.x, i2.x, 1.)); // Gradients: 7x7 points over a square, mapped onto an octahedron. // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) let n_: f32 = 0.14285715; let ns: vec3 = n_ * D.wyz - D.xzx; let j: vec4 = p - 49. * floor(p * ns.z * ns.z); let x_: vec4 = floor(j * ns.z); let y_: vec4 = floor(j - 7. * x_); var x: vec4 = x_ * ns.x + ns.yyyy; var y: vec4 = y_ * ns.x + ns.yyyy; let h: vec4 = 1. - abs(x) - abs(y); let b0: vec4 = vec4(x.xy, y.xy); let b1: vec4 = vec4(x.zw, y.zw); let s0: vec4 = floor(b0) * 2. + 1.; let s1: vec4 = floor(b1) * 2. + 1.; let sh: vec4 = -step(h, vec4(0.)); let a0: vec4 = b0.xzyw + s0.xzyw * sh.xxyy; let a1: vec4 = b1.xzyw + s1.xzyw * sh.zzww; //Normalise gradients var p0: vec3 = vec3(a0.xy, h.x); var p1: vec3 = vec3(a0.zw, h.y); var p2: vec3 = vec3(a1.xy, h.z); var p3: vec3 = vec3(a1.zw, h.w); let norm: vec4 = inverseSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); p0 = p0 * (norm.x); p1 = p1 * (norm.y); p2 = p2 * (norm.z); p3 = p3 * (norm.w); // Mix final noise value var m: vec4 = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), vec4(0.)); m = m * m; return 42. * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3))); } // PRNG // From https://www.shadertoy.com/view/4djSRW fn prng(seed: vec2) -> f32 { var seed_var = seed; seed_var = fract(seed_var * vec2(5.3983, 5.4427)); seed_var = seed_var + (dot(seed_var.yx, seed_var.xy + vec2(21.5351, 14.3137))); return fract(seed_var.x * seed_var.y * 95.4337); } let PI: f32 = 3.1415927; fn noiseStack(pos_in: vec3, octaves: i32, falloff: f32) -> f32 { var pos = pos_in; var noise: f32 = snoise(vec3(pos)); var off: f32 = 1.; if (octaves > 1) { pos = pos * (2.); off = off * (falloff); noise = (1. - off) * noise + off * snoise(vec3(pos)); } if (octaves > 2) { pos = pos * (2.); off = off * (falloff); noise = (1. - off) * noise + off * snoise(vec3(pos)); } if (octaves > 3) { pos = pos * (2.); off = off * (falloff); noise = (1. - off) * noise + off * snoise(vec3(pos)); } return (1. + noise) / 2.; } fn noiseStackUV(pos: vec3, octaves: i32, falloff: f32, diff: f32) -> vec2 { let displaceA: f32 = noiseStack(pos, octaves, falloff); let displaceB: f32 = noiseStack(pos + vec3(3984.293, 423.21, 5235.19), octaves, falloff); return vec2(displaceA, displaceB); } fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var fragColor: vec4; var fragCoord = vec2(f32(location.x), f32(location.y) ); let time: f32 = uni.iTime; let resolution: vec2 = uni.iResolution.xy; let drag: vec2 = uni.iMouse.xy; let offset: vec2 = uni.iMouse.xy; let xpart: f32 = fragCoord.x / resolution.x; let ypart: f32 = fragCoord.y / resolution.y; let clip: f32 = 210.; let ypartClip: f32 = fragCoord.y / clip; let ypartClippedFalloff: f32 = clamp(2. - ypartClip, 0., 1.); let ypartClipped: f32 = min(ypartClip, 1.); let ypartClippedn: f32 = 1. - ypartClipped; let xfuel: f32 = 1. - abs(2. * xpart - 1.); let timeSpeed: f32 = 0.5; let realTime: f32 = timeSpeed * time; let coordScaled: vec2 = 0.01 * fragCoord - 0.02 * vec2(offset.x, 0.); let position: vec3 = vec3(coordScaled, 0.) + vec3(1223., 6434., 8425.); let flow: vec3 = vec3(4.1 * (0.5 - xpart) * pow(ypartClippedn, 4.), -2. * xfuel * pow(ypartClippedn, 64.), 0.); let timing: vec3 = realTime * vec3(0., -1.7, 1.1) + flow; let displacePos: vec3 = vec3(1., 0.5, 1.) * 2.4 * position + realTime * vec3(0.01, -0.7, 1.3); let displace3: vec3 = vec3(noiseStackUV(displacePos, 2, 0.4, 0.1), 0.); let noiseCoord: vec3 = (vec3(2., 1., 1.) * position + timing + 0.4 * displace3) / 1.; let noise: f32 = noiseStack(noiseCoord, 3, 0.4); let flames: f32 = pow(ypartClipped, 0.3 * xfuel) * pow(noise, 0.3 * xfuel); let f: f32 = ypartClippedFalloff * pow(1. - flames * flames * flames, 8.); let fff: f32 = f * f * f; let fire: vec3 = 1.5 * vec3(f, fff, fff * fff); // smoke let smokeNoise: f32 = 0.5 + snoise(0.4 * position + timing * vec3(1., 1., 0.2)) / 2.; let smoke: vec3 = vec3(0.3 * pow(xfuel, 3.) * pow(ypart, 2.) * (smokeNoise + 0.4 * (1. - noise))); // sparks var sparkGridSize: f32 = 30.; var sparkCoord: vec2 = fragCoord - vec2(2. * offset.x, 190. * realTime); sparkCoord = sparkCoord - (30. * noiseStackUV(0.01 * vec3(sparkCoord, 30. * time), 1, 0.4, 0.1)); sparkCoord = sparkCoord + (100. * flow.xy); if (((sparkCoord.y / sparkGridSize) % 2.) < 1.) { sparkCoord.x = sparkCoord.x + (0.5 * sparkGridSize); } let sparkGridIndex: vec2 = vec2(floor(sparkCoord / sparkGridSize)); let sparkRandom: f32 = prng(sparkGridIndex); let sparkLife: f32 = min(10. * (1. - min((sparkGridIndex.y + 190. * realTime / sparkGridSize) / (24. - 20. * sparkRandom), 1.)), 1.); var sparks: vec3 = vec3(0.); if (sparkLife > 0.) { let sparkSize: f32 = xfuel * xfuel * sparkRandom * 0.08; let sparkRadians: f32 = 999. * sparkRandom * 2. * PI + 2. * time; let sparkCircular: vec2 = vec2(sin(sparkRadians), cos(sparkRadians)); let sparkOffset: vec2 = (0.5 - sparkSize) * sparkGridSize * sparkCircular; let sparkModulus: vec2 = ((sparkCoord + sparkOffset) % sparkGridSize) - 0.5 * vec2(sparkGridSize); let sparkLength: f32 = length(sparkModulus); let sparksGray: f32 = max(0., 1. - sparkLength / (sparkSize * sparkGridSize)); sparks = sparkLife * sparksGray * vec3(1., 0.3, 0.); } fragColor = vec4(max(fire, sparks) + smoke, 1.); textureStore(texture, y_inverted_location, toLinear(fragColor)); } ================================================ FILE: assets/shaders/fluid/buffer_a.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; // var R: vec2; fn lnln(p: vec2, a: vec2, b: vec2) -> f32 { return length(p - a - (b - a) * clamp(dot(p - a, b - a) / dot(b - a, b - a), 0., 1.)); } fn T(U: vec2) -> vec4 { let f = vec2(floor(U)); let c = vec2(ceil(U)); let fr = fract(U); let upleft = vec2( f.x, c.y ); let upright = vec2( c.x , c.y ); let downleft = vec2( f.x, f.y ); let downright = vec2( c.x , f.y ); let interpolated_2d = ( (1. - fr.x) * (1. - fr.y) * textureLoad(buffer_a, downleft) + (1. - fr.x) * fr.y * textureLoad(buffer_a, upleft) + fr.x * fr.y * textureLoad(buffer_a, upright) + fr.x * (1. - fr.y) * textureLoad(buffer_a, downright) ); return interpolated_2d; } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var Q: vec4; var U = vec2(f32(location.x), f32(location.y) ); // let R = uni.iResolution.xy; let O: vec2 = U; var A: vec2 = U + vec2(1., 0.); var B: vec2 = U + vec2(0., 1.); var C: vec2 = U + vec2(-1., 0.); var D: vec2 = U + vec2(0., -1.); var u: vec4 = T(U); var a: vec4 = T(A); var b: vec4 = T(B); var c: vec4 = T(C); var d: vec4 = T(D); var p: vec4 = vec4(0.); var g: vec2 = vec2(0.); for (var i: i32 = 0; i < 2; i = i + 1) { U = U - (u.xy); A = A - (a.xy); B = B - (b.xy); C = C - (c.xy); D = D - (d.xy); p = p + (vec4(length(U - A), length(U - B), length(U - C), length(U - D)) - 1.); g = g + (vec2(a.z - c.z, b.z - d.z)); u = T(U); a = T(A); b = T(B); c = T(C); d = T(D); } Q = u; let N: vec4 = 0.25 * (a + b + c + d); Q = mix(Q, N, vec4(0., 0., 1., 0.)); var Qxy = Q.xy; Qxy = Q.xy - (g / 10. / f32(2.)); Q.x = Qxy.x; Q.y = Qxy.y; Q.z = Q.z + ((p.x + p.y + p.z + p.w) / 10.); Q.z = Q.z * (0.95); let mouse: vec4 = textureLoad(buffer_d, vec2(vec2(0.5) * R)); let q: f32 = lnln(U, mouse.xy, mouse.zw); let m: vec2 = mouse.xy - mouse.zw; let l: f32 = length(m); if (mouse.z > 0. && l > 0.) { var Qxyw = Q.xyw; Qxyw = mix(Q.xyw, vec3(-normalize(m) * min(l, 20.) / 25., 1.), max(0., 5. - q) / 25.); Q.x = Qxyw.x; Q.y = Qxyw.y; Q.w = Qxyw.z; } // ifuni.iFrame < 1) { #ifdef INIT Q = vec4(0.); #endif if (uni.iFrame < 140. && length(U - 0.5 * R) < 20.) { var Qxyw = Q.xyw; Qxyw = vec3(0., 0.1, 1.); Q.x = Qxyw.x; Q.y = Qxyw.y; Q.w = Qxyw.z; } if (U.x < 1. || U.y < 1. || R.x - U.x < 1. || R.y - U.y < 1.) { var Qxyw = Q.xyw; Qxyw = Q.xyw * (0.); Q.x = Qxyw.x; Q.y = Qxyw.y; Q.w = Qxyw.z; } textureStore(buffer_a, location, Q); } ================================================ FILE: assets/shaders/fluid/buffer_b.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/fluid/buffer_c.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/fluid/buffer_d.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var fragColor: vec4; var fragCoord = vec2(f32(location.x), f32(location.y) ); var p: vec4 = textureLoad(buffer_d, vec2(fragCoord)); if (uni.iMouse.z > 0.) { if (p.z > 0.) { fragColor = vec4(uni.iMouse.xy, p.xy); } else { fragColor = vec4(uni.iMouse.xy, uni.iMouse.xy); } } else { fragColor = vec4(-uni.iResolution.xy, -uni.iResolution.xy); } textureStore(buffer_d, location, fragColor); } ================================================ FILE: assets/shaders/fluid/image.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @group(0) @binding(5) var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; @group(0) @binding(6) var font_texture: texture_2d; @group(0) @binding(7) var font_texture_sampler: sampler; @group(0) @binding(8) var rgba_noise_256_texture: texture_2d; @group(0) @binding(9) var rgba_noise_256_texture_sampler: sampler; fn t(v: vec2) -> vec4 { return textureLoad(buffer_a, vec2(v )); } fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var C: vec4; let U = vec2( f32(location.x), f32(location.y) ); var me: vec4 = t(U); me.z = me.z - (1.); C = 1. - 3. * me.wwww; let d: vec3 = vec3( t(U + vec2(1., 0.)).w - t(U - vec2(1., 0.)).w, t(U + vec2(0., 1.)).w - t(U - vec2(0., 1.)).w, 2. ); var Cxyz = C.xyz; Cxyz = C.xyz - ( max( vec3(0.), sin(vec3( 100. * length(me.xy), -5. * me.z, 368. * d.y ) * me.w) )); C.x = Cxyz.x; C.y = Cxyz.y; C.z = Cxyz.z; C.a = 1.; // let col_debug_info = show_debug_info(location, C.xyz); // textureStore(texture, y_inverted_location, toLinear(col_debug_info)); textureStore(texture, y_inverted_location, (C)); // textureStore(texture, y_inverted_location, t(U)); } ================================================ FILE: assets/shaders/image_load.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: i32; iSampleRate: i32; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; iResolution: vec2; iMouse: vec2; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; fn hash(value: u32) -> u32 { var state = value; state = state ^ 2747636419u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; return state; } fn randomFloat(value: u32) -> f32 { return f32(hash(value)) / 4294967295.0; } [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let randomNumber = randomFloat(invocation_id.y * num_workgroups.x + invocation_id.x); let alive = randomNumber > 0.9; let color = vec4(f32(alive)); textureStore(texture, location, color); } // fn get(location: vec2, offset_x: i32, offset_y: i32) -> i32 { // let value: vec4 = textureLoad(texture, location + vec2(offset_x, offset_y)); // return i32(value.x); // } // fn count_alive(location: vec2) -> i32 { // return get(location, -1, -1) + // get(location, -1, 0) + // get(location, -1, 1) + // get(location, 0, -1) + // get(location, 0, 1) + // get(location, 1, -1) + // get(location, 1, 0) + // get(location, 1, 1); // } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let n_alive = count_alive(location); // let color = vec4(f32(n_alive) / 8.0); // var alive: bool; // if (n_alive == 3) { // alive = true; // } else if (n_alive == 2) { // let currently_alive = get(location, 0, 0); // alive = bool(currently_alive); // } else { // alive = false; // } var alive = true; // let value: vec4 = textureLoad(buffer_a, vec2(0,1)); // if (value.x > 0.51) { // alive = false; // } // let value: vec4 = textureLoad(buffer_b, vec2(0,1)); // if (value.x > 0.74) { // alive = false; // } // let value: vec4 = textureLoad(buffer_c, vec2(0,1)); // if (value.x > 0.61) { // alive = false; // } let value: vec4 = textureLoad(buffer_a, vec2(0,1)); if (value.x > 0.79) { alive = false; } // if (ga > 2) { // alive = true; // } // if (uni.iTime > 1.0) { // alive = false; // } // alive = false; storageBarrier(); textureStore(texture, location, vec4(f32(alive))); } ================================================ FILE: assets/shaders/interactive_fluid_simulation/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_a, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_a, location, vec4(0.094)); if (uni.iTime > 1.0) { textureStore(buffer_a, location, vec4(0.95)); } } ================================================ FILE: assets/shaders/interactive_fluid_simulation/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: i32; iSampleRate: i32; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; iResolution: vec2; iMouse: vec2; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_b, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_b, location, vec4(0.85)); // if (uni.iTime > 1.0) { // textureStore(buffer_b, location, vec4(0.95)); // } } ================================================ FILE: assets/shaders/interactive_fluid_simulation/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_c, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_c, location, vec4(0.95)); // if (uni.iTime > 1.0) { // textureStore(buffer_c, location, vec4(0.95)); // } } ================================================ FILE: assets/shaders/interactive_fluid_simulation/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let color = vec4(0.60); textureStore(buffer_d, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_d, location, vec4(0.7)); // let p: vec4 = texture(iChannel0, fragCoord/iResolution.xy); // if (uni.iMouse.z>0.) { // if (p.z>0.) { fragColor = vec4(uni.iMouse.xy, p.xy); // } else { fragColor = vec4(uni.iMouse.xy, uni.iMouse.xy); // } // } else { fragColor = vec4(-uni.iResolution.xy, -uni.iResolution.xy); // } if (uni.iTime > 1.0) { storageBarrier(); textureStore(buffer_d, location, vec4(0.95)); } // storageBarrier(); } // fn mainImage( fragColor: vec4, fragCoord: vec2) -> () { // let p: vec4 = texture(iChannel0, fragCoord/iResolution.xy); // if (iMouse.z>0.) { // if (p.z>0.) { fragColor = vec4(iMouse.xy, p.xy); // } else { fragColor = vec4(iMouse.xy, iMouse.xy); // } // } else { fragColor = vec4(-iResolution.xy, -iResolution.xy); // } // } ================================================ FILE: assets/shaders/interactive_fluid_simulation/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; fn hash(value: u32) -> u32 { var state = value; state = state ^ 2747636419u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; return state; } fn randomFloat(value: u32) -> f32 { return f32(hash(value)) / 4294967295.0; } [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let randomNumber = randomFloat(invocation_id.y * num_workgroups.x + invocation_id.x); let alive = randomNumber > 0.9; let color = vec4(f32(alive)); textureStore(texture, location, color); } fn t(v: vec2) -> vec4 { return textureLoad(buffer_a, v ); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var me: vec4 = t(location) ; let U = location; me.z = me.z - (1.); var C = 1. - 3.*me.www; let d: vec3 = vec3(t(U+vec2(1, 0)).w-t(U-vec2(1, 0)).w, t(U+vec2(0, 1)).w-t(U-vec2(0, 1)).w, 2.); C = C - (max(vec3(0.), sin(vec3(100.*length(me.xy), -5.*me.z, 368.*d.y)*me.w))); storageBarrier(); textureStore(texture, location, vec4(C.x, C.y, C.z, me.w)); } // fn mainImage( C: vec4, U: vec2) -> () { // let me: vec4 = t(U); // me.z = me.z - (1.); // C = 1.-3.*me.wwww; // let d: vec3 = vec3(t(U+vec2(1, 0)).w-t(U-vec2(1, 0)).w, t(U+vec2(0, 1)).w-t(U-vec2(0, 1)).w, 2.); // C.xyz = C.xyz - (max(vec3(0), sin(vec3(100.*length(me.xy), -5.*me.z, 368.*d.y)*me.w))); // } ================================================ FILE: assets/shaders/liquid/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; struct Particle { position: vec2; velocity: vec2; mass: vec2; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; let fluid_rho: f32 = 0.5; let dt: f32 = 1.5; let border_h = 5.0; let h: f32 = 1.; fn Pf(rho: vec2) -> f32 { //return 0.2*rho.x; //gas let GF: f32 = 1.;//smoothstep(0.49, 0.5, 1. - rho.y); return mix(0.5*rho.x, 0.04*rho.x*(rho.x/fluid_rho - 1.), GF); //water pressure } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { let d = (abs(p) - b) ; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn border(p: vec2, uni: CommonUniform) -> f32 { let R: vec2 = uni.iResolution; let bound: f32 = -sdBox(p - R*0.5, R*vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0.*uni.iTime)*(p - R*vec2(0.5, 0.6)) , R*vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R*vec2(0.5, 0.7), R*vec2(1.5, 0.5)); return max(drain,min(bound, box)); } fn bN( p: vec2, uni: CommonUniform ) -> vec3 { let dx: vec3 = vec3(-h, 0.0 , h); let idx: vec4 = vec4(-1./h, 0., 1./h, 0.25); let r: vec3 = idx.zyw*border(p + dx.zy, uni) + idx.xyw*border(p + dx.xy, uni) + idx.yzw*border(p + dx.yz, uni) + idx.yxw*border(p + dx.yx, uni); return vec3(normalize(r.xy), r.z + 1e-4); } fn pack(x: vec2) -> u32 { var q: vec2; q.x = 65534.0*clamp(0.5*x.x+0.5, 0., 1.); q.y = 65534.0*clamp(0.5*x.y+0.5, 0., 1.); return u32(round(q.x)) + 65535u*u32(round(q.y)); } fn unpack(a: u32) -> vec2 { let q = vec2(a % 65535u, a / 65535u); let p = vec2( clamp(f32(q.x) / 65534.0, 0.,1.)*2.0 - 1.0, clamp(f32(q.y) / 65534.0, 0.,1.)*2.0 - 1.0 ); return p; } fn decode(x: f32) -> vec2 { let X: u32 = bitcast(x); return unpack(X); } fn encode(x: vec2) -> f32 { let X: u32 = pack(x); let casted: f32 = bitcast(X); return casted; } fn getParticle(data: vec4, pos: vec2) -> Particle { var P: Particle; P.position = decode(data.x) + pos; P.velocity = decode(data.y); P.mass = data.zw; return P; } fn saveParticle(in_p: Particle, pos: vec2) -> vec4 { var P: Particle = in_p; // P.position = clamp(P.position - pos, vec2(-0.5), vec2(0.5)); P.position.x = clamp(P.position.x - pos.x, -0.5, 0.5); P.position.y = clamp(P.position.y - pos.y, -0.5, 0.5); return vec4(encode(P.position), encode(P.velocity), P.mass.x, P.mass.y); } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); p3 = p3 + dot(p3, p3.yxz+33.33); return fract((p3.xxy+p3.yzz)*p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x,x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K*0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K*0.5, p - 0.5, p + 0.5); return vec3(0.5*(omin + omax), (omax.x - omin.x)*(omax.y - omin.y)/(K*K)); } //diffusion and advection basically fn Reintegration(buffer: texture_storage_2d, P: Particle, pos: vec2) -> Particle { var particle: Particle = P; //basically integral over all updated neighbor distributions //that fall inside of this pixel //this makes the tracking conservative var i: i32 = -2; loop { if (i > 2) { break; } var j: i32 = -2; loop { if (j > 2) { break; } let tpos: vec2 = pos + vec2(f32(i),f32(j)); let data: vec4 = textureLoad(buffer, vec2(tpos)); var P0: Particle = getParticle(data, tpos); P0.position = P0.position + P0.velocity*dt; //integrate position let difR: f32 = 0.9 + 0.21*smoothStep(fluid_rho*0., fluid_rho*0.333, P0.mass.x); let D: vec3 = distribution(P0.position, pos, difR); //the deposited mass into this cell let m: f32 = P0.mass.x*D.z; //add weighted by mass particle.position = particle.position + D.xy*m; particle.velocity = particle.velocity + P0.velocity*m; particle.mass.y = particle.mass.y + P0.mass.y*m; //add mass particle.mass.x = particle.mass.x + m; } } // range(i, -2, 2) range(j, -2, 2) //normalization if(particle.mass.x != 0.) { particle.position = particle.position / particle.mass.x; particle.velocity= particle.velocity / particle.mass.x; particle.mass.y = particle.mass.y / particle.mass.x; } return particle; } //force calculation and integration fn Simulation( buffer: texture_storage_2d, P: Particle, pos: vec2, Mouse: vec4, uni: CommonUniform ) -> Particle { var particle: Particle = P; //Compute the SPH force var F: vec2 = vec2(0.); var avgV: vec3 = vec3(0.); var i: i32 = -2; loop { if (i > 2) { break; } var j: i32 = -2; loop { if (j > 2) { break; } let tpos: vec2 = pos + vec2(f32(i), f32(j)); // let data: vec4 = texel(ch, tpos); let data: vec4 = textureLoad(buffer, vec2(tpos)); let P0: Particle = getParticle(data, tpos); let dx: vec2 = P0.position - particle.position; let avgP: f32 = 0.5*P0.mass.x*(Pf(particle.mass) + Pf(P0.mass)); F = F - 0.5*G(1.*dx)*avgP*dx; avgV = avgV + P0.mass.x*G(1.*dx)*vec3(P0.velocity,1.); } } avgV.x = avgV.x / avgV.z; avgV.y = avgV.y / avgV.z; //viscosity F = F + 0.*particle.mass.x*(avgV.xy - particle.velocity); //gravity F = F + particle.mass.x*vec2(0., -0.0004); if(Mouse.z > 0.) { let dm: vec2 =(Mouse.xy - Mouse.zw)/10.; let d: f32 = distance(Mouse.xy, particle.position)/20.; F = F + 0.001*dm*exp(-d*d); // particle.mass.y += 0.1*exp(-40.*d*d); } //integrate particle.velocity = particle.velocity + F*dt/particle.mass.x; //border let N: vec3 = bN(particle.position, uni); let vdotN : f32 = step(N.z, border_h) * dot(-N.xy, particle.velocity); particle.velocity = particle.velocity + 0.5*(N.xy*vdotN + N.xy*abs(vdotN)); particle.velocity = particle.velocity + 0.*particle.mass.x*N.xy*step(abs(N.z), border_h)*exp(-N.z); if (N.z < 0.) { particle.velocity = vec2(0.); } //velocity limit let v: f32 = length(particle.velocity); if (v > 1.0) { particle.velocity = particle.velocity / v; } // particle.velocity = particle.velocity / (v > 1.) ? v : 1.; return particle; } // // /* // // vec3 distribution(vec2 x, vec2 p, float K) // // { // // vec4 aabb0 = vec4(p - 0.5, p + 0.5); // // vec4 aabb1 = vec4(x - K*0.5, x + K*0.5); // // vec4 aabbX = vec4(max(aabb0.xy, aabb1.xy), min(aabb0.zw, aabb1.zw)); // // vec2 center = 0.5*(aabbX.xy + aabbX.zw); //center of mass // // vec2 size = max(aabbX.zw - aabbX.xy, 0.); //only positive // // float m = size.x*size.y/(K*K); //relative amount // // //if any of the dimensions are 0 then the mass is 0 // // return vec3(center, m); // // }*/ [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_a, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_a, location, vec4(0.094)); if (uni.iTime > 1.0) { textureStore(buffer_a, location, vec4(0.95)); } } ================================================ FILE: assets/shaders/liquid/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: i32; iSampleRate: i32; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; iResolution: vec2; iMouse: vec2; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_b, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_b, location, vec4(0.85)); // if (uni.iTime > 1.0) { // textureStore(buffer_b, location, vec4(0.95)); // } } ================================================ FILE: assets/shaders/liquid/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_c, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_c, location, vec4(0.95)); // if (uni.iTime > 1.0) { // textureStore(buffer_c, location, vec4(0.95)); // } } ================================================ FILE: assets/shaders/liquid/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let color = vec4(0.60); textureStore(buffer_d, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_d, location, vec4(0.7)); if (uni.iTime > 1.0) { storageBarrier(); textureStore(buffer_d, location, vec4(0.95)); } // storageBarrier(); } ================================================ FILE: assets/shaders/liquid/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; fn hash(value: u32) -> u32 { var state = value; state = state ^ 2747636419u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; return state; } fn randomFloat(value: u32) -> f32 { return f32(hash(value)) / 4294967295.0; } [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let randomNumber = randomFloat(invocation_id.y * num_workgroups.x + invocation_id.x); let alive = randomNumber > 0.9; let color = vec4(f32(alive)); textureStore(texture, location, color); } // fn get(location: vec2, offset_x: i32, offset_y: i32) -> i32 { // let value: vec4 = textureLoad(texture, location + vec2(offset_x, offset_y)); // return i32(value.x); // } // fn count_alive(location: vec2) -> i32 { // return get(location, -1, -1) + // get(location, -1, 0) + // get(location, -1, 1) + // get(location, 0, -1) + // get(location, 0, 1) + // get(location, 1, -1) + // get(location, 1, 0) + // get(location, 1, 1); // } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let n_alive = count_alive(location); // let color = vec4(f32(n_alive) / 8.0); // var alive: bool; // if (n_alive == 3) { // alive = true; // } else if (n_alive == 2) { // let currently_alive = get(location, 0, 0); // alive = bool(currently_alive); // } else { // alive = false; // } var alive = true; // let value: vec4 = textureLoad(buffer_a, vec2(0,1)); // if (value.x > 0.51) { // alive = false; // } // let value: vec4 = textureLoad(buffer_b, vec2(0,1)); // if (value.x > 0.74) { // alive = false; // } // let value: vec4 = textureLoad(buffer_c, vec2(0,1)); // if (value.x > 0.61) { // alive = false; // } let value: vec4 = textureLoad(buffer_a, vec2(0,1)); if (value.x > 0.79) { alive = false; } // if (ga > 2) { // alive = true; // } // if (uni.iTime > 1.0) { // alive = false; // } // alive = false; storageBarrier(); textureStore(texture, location, vec4(f32(alive))); } ================================================ FILE: assets/shaders/liquid_toy/buffer_a.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; let speed: f32 = 0.01; let scale: f32 = 0.1; let falloff: f32 = 3.; let fade: f32 = 0.4; let strength: f32 = 1.; let range: f32 = 5.; fn random3(c: vec3) -> vec3 { var j: f32 = 4096. * sin(dot(c, vec3(17., 59.4, 15.))); var r: vec3; r.z = fract(512. * j); j = j * (0.125); r.x = fract(512. * j); j = j * (0.125); r.y = fract(512. * j); return r - 0.5; } let F3: f32 = 0.3333333; let G3: f32 = 0.1666667; fn simplex3d(p: vec3) -> f32 { let s: vec3 = floor(p + dot(p, vec3(F3))); var x: vec3 = p - s + dot(s, vec3(G3)); let e: vec3 = step(vec3(0.), x - x.yzx); let i1: vec3 = e * (1. - e.zxy); let i2: vec3 = 1. - e.zxy * (1. - e); let x1: vec3 = x - i1 + G3; let x2: vec3 = x - i2 + 2. * G3; let x3: vec3 = x - 1. + 3. * G3; var w: vec4; var d: vec4; w.x = dot(x, x); w.y = dot(x1, x1); w.z = dot(x2, x2); w.w = dot(x3, x3); w = max(0.6 - w, vec4(0.)); d.x = dot(random3(s), x); d.y = dot(random3(s + i1), x1); d.z = dot(random3(s + i2), x2); d.w = dot(random3(s + 1.), x3); w = w * (w); w = w * (w); d = d * (w); return dot(d, vec4(52.)); } let rot1: mat3x3 = mat3x3( vec3(-0.37, 0.36, 0.85), vec3(-0.14, -0.93, 0.34), vec3(0.92, 0.01, 0.4)); let rot2: mat3x3 = mat3x3( vec3(-0.55, -0.39, 0.74), vec3(0.33, -0.91, -0.24), vec3(0.77, 0.12, 0.63)); let rot3: mat3x3 = mat3x3( vec3(-0.71, 0.52, -0.47), vec3(-0.08, -0.72, -0.68), vec3(-0.7, -0.45, 0.56)); fn simplex3d_fractal(m: vec3) -> f32 { return 0.5333333 * simplex3d(m * rot1) + 0.2666667 * simplex3d(2. * m * rot2) + 0.1333333 * simplex3d(4. * m * rot3) + 0.0666667 * simplex3d(8. * m); } fn dummy(p3: vec3) -> vec3 { var value: f32 = simplex3d(p3 * 16.); value = 0.5 + 0.5 * value; return vec3(value); } fn fbm(p: vec3) -> vec3 { var result: vec3 = vec3(0.); var amplitude: f32 = 0.5; for (var index: f32 = 0.; index < 3.; index = index + 1.) { let what: vec3 = dummy(p / amplitude); result = result + (what * amplitude); amplitude = amplitude / (falloff); } return result; } fn sample_texture(ch: texture_storage_2d, U01: vec2) -> vec4 { let U = U01 * uni.iResolution; let f = vec2(floor(U)); let c = vec2(ceil(U)); let fr = fract(U); let upleft = vec2( f.x, c.y ); let upright = vec2( c.x , c.y ); let downleft = vec2( f.x, f.y ); let downright = vec2( c.x , f.y ); let interpolated_2d = ( (1. - fr.x) * (1. - fr.y) * textureLoad(ch, downleft) + (1. - fr.x) * fr.y * textureLoad(ch, upleft) + fr.x * fr.y * textureLoad(ch, upright) + fr.x * (1. - fr.y) * textureLoad(ch, downright) ); return interpolated_2d; } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var fragColor: vec4; var fragCoord = vec2(f32(location.x), f32(location.y) ); var uv: vec2 = (fragCoord.xy - uni.iResolution.xy / 2.) / uni.iResolution.y; var spice: vec3 = fbm(vec3(uv * scale, uni.iTime * speed)); let t: f32 = uni.iTime * 2.; let mouse: vec2 = (uni.iMouse.xy - uni.iResolution.xy / 2.) / uni.iResolution.y; if (uni.iMouse.z > 0.5) { uv = uv - (mouse); } else { uv = uv - (vec2(cos(t), sin(t)) * 0.3); } var paint: f32 = smoothstep(0.1, 0., length(uv)); var offset: vec2 = vec2(0.); uv = fragCoord.xy / uni.iResolution.xy; let data: vec4 = sample_texture(buffer_a, uv); let unit: vec3 = vec3(range / uni.iResolution.xy, 0.); let normal: vec3 = normalize(vec3( sample_texture(buffer_a, uv - unit.xz).r - sample_texture(buffer_a, uv + unit.xz).r, sample_texture(buffer_a, uv - unit.zy).r - sample_texture(buffer_a, uv + unit.zy).r, data.x * data.x) + 0.001); offset = offset - (normal.xy); spice.x = spice.x * (6.28 * 2.); spice.x = spice.x + (uni.iTime); offset = offset + (vec2(cos(spice.x), sin(spice.x))); let frame: vec4 = sample_texture(buffer_a, uv + strength * offset / uni.iResolution.xy); paint = max(paint, frame.x - uni.iTimeDelta * fade); fragColor = vec4(clamp(paint, 0., 1.)); textureStore(buffer_a, location, fragColor); } ================================================ FILE: assets/shaders/liquid_toy/buffer_b.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/liquid_toy/buffer_c.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/liquid_toy/buffer_d.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/liquid_toy/image.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @group(0) @binding(5) var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; @group(0) @binding(6) var font_texture: texture_2d; @group(0) @binding(7) var font_texture_sampler: sampler; @group(0) @binding(8) var rgba_noise_256_texture: texture_2d; @group(0) @binding(9) var rgba_noise_256_texture_sampler: sampler; @group(0) @binding(10) var blue_noise_texture: texture_2d; @group(0) @binding(11) var blue_noise_texture_sampler: sampler; // displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a // here fn sample_texture(ch: texture_storage_2d, U01: vec2) -> vec4 { let U = U01 * uni.iResolution; let f = vec2(floor(U)); let c = vec2(ceil(U)); let fr = fract(U); let upleft = vec2( f.x, c.y ); let upright = vec2( c.x , c.y ); let downleft = vec2( f.x, f.y ); let downright = vec2( c.x , f.y ); let interpolated_2d = ( (1. - fr.x) * (1. - fr.y) * textureLoad(ch, downleft) + (1. - fr.x) * fr.y * textureLoad(ch, upleft) + fr.x * fr.y * textureLoad(ch, upright) + fr.x * (1. - fr.y) * textureLoad(ch, downright) ); return interpolated_2d; } fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var fragColor: vec4; var fragCoord = vec2(f32(location.x), f32(location.y) ); var uv: vec2 = fragCoord.xy / uni.iResolution.xy; // let dither: vec3 = textureSample(blue_noise_texture, // blue_noise_texture_sampler, fragCoord.xy / 1024.).rgb; // let dither: vec3 = textureSample(rgba_noise_256_texture, // rgba_noise_256_texture_sampler, fragCoord.xy / 256.).rgb; let dither: vec3 = textureSampleGrad(blue_noise_texture, blue_noise_texture_sampler, fragCoord.xy / 1024., vec2(0.), vec2(0.)).rbg; let data: vec4 = sample_texture(buffer_a, uv); let gray: f32 = data.x; let range: f32 = 3.; let unit: vec3 = vec3(range / uni.iResolution.xy, 0.); let normal: vec3 = normalize(vec3(sample_texture(buffer_a, uv + unit.xz).r - sample_texture(buffer_a, uv - unit.xz).r, sample_texture(buffer_a, uv - unit.zy).r - sample_texture(buffer_a, uv + unit.zy).r, gray * gray * gray)); var color: vec3 = vec3(0.3) * (1. - abs(dot(normal, vec3(0., 0., 1.)))); let dir: vec3 = normalize(vec3(0., 1., 2.)); let specular: f32 = pow(dot(normal, dir) * 0.5 + 0.5, 20.); color = color + (vec3(0.5) * smoothstep(0.2, 1., specular)); let tint: vec3 = 0.5 + 0.5 * cos(vec3(1., 2., 3.) * 1. + dot(normal, dir) * 4. - uv.y * 3. - 3.); color = color + (tint * smoothstep(0.15, 0., gray)); color = color - (dither.x * 0.1); var background: vec3 = vec3(1.); background = background * (smoothstep(1.5, -0.5, length(uv - 0.5))); color = mix(background, clamp(color, vec3(0.), vec3(1.)), smoothstep(0.01, 0.1, gray)); if (uni.iMouse.z > 0.5 && uni.iMouse.x / uni.iResolution.x < 0.1) { if (uv.x < 0.33) { color = vec3(gray); } else { if (uv.x < 0.66) { color = normal * 0.5 + 0.5; } else { color = vec3(tint); } } } fragColor = vec4(color, 1.); textureStore(texture, y_inverted_location, toLinear(fragColor)); } ================================================ FILE: assets/shaders/love_and_domination/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; let s2 = 30.; let BLUR_DEPTH = 25.; let SPEED = 2.; let MOUSE_SIZE = 60.; let texture_const = 255.; var R: vec2; fn A(location: vec2) -> vec4 { return textureLoad(buffer_a, vec2(location)) * texture_const; } // fn B(location: vec2)-> vec4 { // return textureLoad(buffer_b, vec2(location)); // } fn C(location: vec2) -> vec4 { return textureLoad(buffer_c, vec2(location)) * texture_const; } fn X(U: vec2, Q2: vec4, u: vec2) -> vec4 { var Q = Q2; let p: vec4 = A(U + u); if (length(p.xy - U) < length(Q.xy - U)) { Q = p; } return Q; } fn mod2(x: f32, d: f32) -> f32 { let y: f32 = (x / d - floor(x / d)) * d; return y; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // fn mainImage( Q: vec4, U: vec2) -> () { var U = vec2(f32(location.x), f32(location.y)); R = uni.iResolution.xy; var Q: vec4 = A(U); Q = X(U, Q, vec2(1., 0.)); Q = X(U, Q, vec2(0., 1.)); Q = X(U, Q, vec2(0., -1.)); Q = X(U, Q, vec2(-1., 0.)); Q = X(U, Q, vec2(1., 1.)); Q = X(U, Q, vec2(-1., 1.)); Q = X(U, Q, vec2(1., -1.)); Q = X(U, Q, vec2(-1., -1.)); let n: vec4 = C(U + vec2(0., 1.)); let e: vec4 = C(U + vec2(1., 0.)); let s: vec4 = C(U + vec2(0., -1.)); let w: vec4 = C(U + vec2(-1., 0.)); let dx: vec3 = e.xyz - w.xyz; let dy: vec3 = n.xyz - s.xyz; var v: vec2 = vec2(0.); if (Q.w == 0.) { v = vec2(dx.z - dx.y + 0.3 * dx.x, dy.z - dy.y + 0.3 * dy.x); } if (Q.w == 1.) { v = vec2(dx.x - dx.z + 0.1 * dx.y, dy.x - dy.z + 0.1 * dy.y); } if (Q.w == 2.) { v = vec2(dx.y - dx.x + 0.2 * dx.z, dy.y - dy.x + 0.2 * dy.z); } if (length(v) > 0.) { let qxy = Q.xy + (normalize(v) * min(1., SPEED * length(v))); Q.x = qxy.x ; Q.y = qxy.y ; } #ifdef INIT U = floor(U / 8.) * 8. + 5.; var Q = vec4(U, 1., floor( mod2(-U.x / R.x * 5., 3.))); #endif if (uni.iMouse.z > 0. && length(uni.iMouse.xy - Q.xy) < MOUSE_SIZE) { Q = vec4(-100., -100., 0., 0.); } textureStore(buffer_a, location, Q / texture_const ); // textureStore(buffer_a, location, vec4(0.2, 0.7, 0.9, 1.) / texture_const); } ================================================ FILE: assets/shaders/love_and_domination/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; let s2 = 30.; let BLUR_DEPTH = 25.; let SPEED = 2.; let MOUSE_SIZE = 60.; let texture_const = 255.; var R: vec2; fn A(location: vec2) -> vec4 { return textureLoad(buffer_a, vec2(location)) * texture_const; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let U = vec2(f32(location.x), f32(location.y)); // fn mainImage( Q: vec4, U: vec2) -> () { R = uni.iResolution.xy; var Q = vec4(0.); for (var i: f32 = -BLUR_DEPTH; i <= BLUR_DEPTH; i = i + 1.) { let a: vec4 = A(U + vec2(i, 0.)); let c: vec4 = a.z * smoothStep(1., 0.5, length(U + vec2(i, 0.) - a.xy)) * vec4(f32(a.w == 0.), f32(a.w == 1.), f32(a.w == 2.), 0.); Q = Q + (c * sqrt(s2) / s2 * exp(-i * i * 0.5 / s2)); } textureStore(buffer_b, location, Q / texture_const); // Q = textureLoad(buffer_a, vec2(location)); // textureStore(buffer_b, location, Q); } ================================================ FILE: assets/shaders/love_and_domination/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; let s2 = 30.; let BLUR_DEPTH = 25.; let SPEED = 2.; let MOUSE_SIZE = 60.; let texture_const = 255.; var R: vec2; // fn A(location: vec2) -> vec4 { // return textureLoad(buffer_a, vec2(location)) * texture_const; // } fn B(location: vec2)-> vec4 { return textureLoad(buffer_b, vec2(location)) * texture_const; } fn C(location: vec2) -> vec4 { return textureLoad(buffer_c, vec2(location)) * texture_const; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // } // fn mainImage( Q: vec4, U: vec2) -> () { let U = vec2(f32(location.x), f32(location.y)); R = uni.iResolution.xy; var Q = vec4(0.); for (var i: f32 = -BLUR_DEPTH; i <= BLUR_DEPTH; i = i + 1.) { let c: vec4 = B(U + vec2(0., i)); Q = Q + (2. * c * sqrt(s2) / s2 * exp(-i * i * 0.5 / s2)); } Q = mix(Q, C(U), 0.1); textureStore(buffer_c, location, Q / texture_const); // Q = textureLoad(buffer_b, vec2(location)); // textureStore(buffer_c, location, Q); } ================================================ FILE: assets/shaders/love_and_domination/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; let s2 = 30.; let BLUR_DEPTH = 25.; let SPEED = 2.; let MOUSE_SIZE = 60.; let texture_const = 255.; var R: vec2; fn A(location: vec2) -> vec4 { return textureLoad(buffer_a, vec2(location)) * texture_const; } // fn B(location: vec2)-> vec4 { // return textureLoad(buffer_b, vec2(location)) * texture_const; // } fn C(location: vec2) -> vec4 { return textureLoad(buffer_c, vec2(location)) * texture_const; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let U = vec2(f32(location.x), f32(location.y)); // } // fn mainImage( Q: vec4, U: vec2) -> () { R = uni.iResolution.xy; let c: vec4 = C(U); let n: vec4 = C(U + vec2(0., 1.)); let e: vec4 = C(U + vec2(1., 0.)); let s: vec4 = C(U + vec2(0., -1.)); let w: vec4 = C(U + vec2(-1., 0.)); let a: vec4 = A(U); let r: f32 = smoothStep(1., 0.5, length(U - a.xy)); let f: vec4 = r * f32(a.w == 0.) * vec4(0.8, 0.6, 0.3, 1.) + r * f32(a.w == 1.) * vec4(0.9, 0.2, 0.4, 1.) + r * f32(a.w == 2.) * vec4(0.2, 0.7, 0.9, 1.); var Q = 2. * f * (0.5 + 0.5 * (n - s + e - w)); textureStore(buffer_d, location, Q / texture_const); // Q = textureLoad(buffer_c, vec2(location)); // textureStore(buffer_d, location, Q); } ================================================ FILE: assets/shaders/love_and_domination/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // let color = vec4(f32(0)); // textureStore(texture, location, color); // } let s2 = 30.; let BLUR_DEPTH = 25.; let SPEED = 2.; let MOUSE_SIZE = 60.; let texture_const = 255.; var R: vec2; fn D(location: vec2) -> vec4 { // return texture(iChannel0, U / R); return textureLoad(buffer_d, vec2(location)) * texture_const; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let U = vec2(f32(location.x), f32(location.y)); // var O: vec4 = textureLoad(buffer_a, location); // textureStore(texture, location, O); // } // fn mainImage( Q: vec4, U: vec2) -> () { R = uni.iResolution.xy; let n: vec4 = D(U + vec2(0., 1.)); let e: vec4 = D(U + vec2(1., 0.)); let s: vec4 = D(U + vec2(0., -1.)); let w: vec4 = D(U + vec2(-1., 0.)); let dx: vec4 = e - w; let dy: vec4 = n - s; var Q = (D(U) + abs(dx) + abs(dy)) / 3.; textureStore(texture, location, Q); // Q = textureLoad(buffer_b, vec2(location)); // textureStore(texture, location, Q * texture_const ); } ================================================ FILE: assets/shaders/minimal/buffer_a.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let color = vec4(0.5); textureStore(buffer_a, location, color); } ================================================ FILE: assets/shaders/minimal/buffer_b.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/minimal/buffer_c.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/minimal/buffer_d.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/minimal/image.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @group(0) @binding(5) var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; @group(0) @binding(6) var font_texture: texture_2d; @group(0) @binding(7) var font_texture_sampler: sampler; @group(0) @binding(8) var rgba_noise_256_texture: texture_2d; @group(0) @binding(9) var rgba_noise_256_texture_sampler: sampler; @group(0) @binding(10) var blue_noise_texture: texture_2d; @group(0) @binding(11) var blue_noise_texture_sampler: sampler; // displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a // here @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var O: vec4 = textureLoad(buffer_a, location); textureStore(texture, location, O); } ================================================ FILE: assets/shaders/mip_fluid/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; let RECALCULATE_OFFSET: bool = true; let BLUR_TURBULENCE: bool = false; let BLUR_CONFINEMENT: bool = false; let BLUR_VELOCITY: bool = false; let USE_PRESSURE_ADVECTION: bool = false; let PREMULTIPLY_CURL: bool = true; let VIEW_VELOCITY: bool = true; let CENTER_PUMP: bool = false; fn normz(x: vec4) -> vec4 { return if (x.xyz == vec3(0.)) { vec4(0., 0., 0., x.w); } else { vec4(normalize(x.xyz), 0.); }; } fn normz(x: vec3) -> vec3 { return if (x == vec3(0.)) { vec3(0.); } else { normalize(x); }; } fn normz(x: vec2) -> vec2 { return if (x == vec2(0.)) { vec2(0.); } else { normalize(x); }; } fn softmax(a: f32, b: f32, k: f32) -> f32 { return log(exp(k * a) + exp(k * b)) / k; } fn softmin(a: f32, b: f32, k: f32) -> f32 { return -log(exp(-k * a) + exp(-k * b)) / k; } fn softmax(a: vec4, b: vec4, k: f32) -> vec4 { return log(exp(k * a) + exp(k * b)) / k; } fn softmin(a: vec4, b: vec4, k: f32) -> vec4 { return -log(exp(-k * a) + exp(-k * b)) / k; } fn softclamp(a: f32, b: f32, x: f32, k: f32) -> f32 { return (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.; } fn softclamp(a: vec4, b: vec4, x: vec4, k: f32) -> vec4 { return (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.; } fn softclamp(a: f32, b: f32, x: vec4, k: f32) -> vec4 { return (softmin(vec4(b), softmax(vec4(a), x, k), k) + softmax(vec4(a), softmin(vec4(b), x, k), k)) / 2.; } fn G1V(dnv: f32, k: f32) -> f32 { return 1. / (dnv * (1. - k) + k); } fn ggx(n: vec3, v: vec3, l: vec3, rough: f32, f0: f32) -> f32 { let alpha: f32 = rough * rough; let h: vec3 = normalize(v + l); let dnl: f32 = clamp(dot(n, l), 0., 1.); let dnv: f32 = clamp(dot(n, v), 0., 1.); let dnh: f32 = clamp(dot(n, h), 0., 1.); var dlh: f32 = clamp(dot(l, h), 0., 1.); var f: f32; let d: f32; let vis: f32; let asqr: f32 = alpha * alpha; let pi: f32 = 3.14159; let den: f32 = dnh * dnh * (asqr - 1.) + 1.; d = asqr / (pi * den * den); dlh = pow(1. - dlh, 5.); f = f0 + (1. - f0) * dlh; var k: f32 = alpha / 1.; vis = G1V(dnl, k) * G1V(dnv, k); let spec: f32 = dnl * d * f * vis; return spec; } fn light(uv: vec2, BUMP: f32, SRC_DIST: f32, dxy: vec2, uni.iTime: f32, avd: ptr>) -> vec3 { let sp: vec3 = vec3(uv - 0.5, 0.); let light: vec3 = vec3(cos(uni.iTime / 2.) * 0.5, sin(uni.iTime / 2.) * 0.5, -SRC_DIST); var ld: vec3 = light - sp; let lDist: f32 = max(length(ld), 0.001); ld = ld / (lDist); (*avd) = reflect(normalize(vec3(BUMP * dxy, -1.)), vec3(0., 1., 0.)); return ld; } fn hash1(n: u32) -> f32 { var n_var = n; n_var = n_var << 13u ^ n_var; n_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u; return f32(n_var & vec3(2147483600.)) / f32(2147483600.); } fn hash3(n: u32) -> vec3 { var n_var = n; n_var = n_var << 13u ^ n_var; n_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u; let k: vec3 = n_var * vec3(n_var, n_var * 16807u, n_var * 48271u); return vec3(k & vec3(2147483600.)) / f32(2147483600.); } fn rand4(fragCoord: vec2, uni.iResolution: vec2, uni.iFrame: i32) -> vec4 { let p: vec2 = vec2(fragCoord); let r: vec2 = vec2(uni.iResolution); let c: u32 = p.x + r.x * p.y + r.x * r.y * u32(uni.iFrame); return vec4(hash3(c), hash1(c + 75132900.)); } fn gaussian_turbulence(uv: vec2) -> vec2 { var texel: vec2 = 1. / uni.iResolution.xy; var t: vec4 = vec4(texel, -texel.y, 0.); var d: vec2 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2(fract(uv + (t.ww + 0.)))).xy; var d_n: vec2 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2(fract(uv + (t.wy + 0.)))).xy; var d_e: vec2 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2(fract(uv + (t.xw + 0.)))).xy; var d_s: vec2 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2(fract(uv + (t.wz + 0.)))).xy; var d_w: vec2 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2(fract(uv + (-t.xw + 0.)))).xy; var d_nw: vec2 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2(fract(uv + (-t.xz + 0.)))).xy; var d_sw: vec2 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2(fract(uv + (-t.xy + 0.)))).xy; var d_ne: vec2 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2(fract(uv + (t.xy + 0.)))).xy; var d_se: vec2 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2(fract(uv + (t.xz + 0.)))).xy; return 0.25 * d + 0.125 * (d_e + d_w + d_n + d_s) + 0.0625 * (d_ne + d_nw + d_se + d_sw); } fn gaussian_confinement(uv: vec2) -> vec2 { var texel: vec2 = 1. / uni.iResolution.xy; var t: vec4 = vec4(texel, -texel.y, 0.); var d: vec2 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2(fract(uv + (t.ww + 0.)))).xy; var d_n: vec2 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2(fract(uv + (t.wy + 0.)))).xy; var d_e: vec2 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2(fract(uv + (t.xw + 0.)))).xy; var d_s: vec2 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2(fract(uv + (t.wz + 0.)))).xy; var d_w: vec2 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2(fract(uv + (-t.xw + 0.)))).xy; var d_nw: vec2 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2(fract(uv + (-t.xz + 0.)))).xy; var d_sw: vec2 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2(fract(uv + (-t.xy + 0.)))).xy; var d_ne: vec2 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2(fract(uv + (t.xy + 0.)))).xy; var d_se: vec2 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2(fract(uv + (t.xz + 0.)))).xy; return 0.25 * d + 0.125 * (d_e + d_w + d_n + d_s) + 0.0625 * (d_ne + d_nw + d_se + d_sw); } fn diff(uv: vec2) -> vec2 { var texel: vec2 = 1. / uni.iResolution.xy; var t: vec4 = vec4(texel, -texel.y, 0.); var d: f32 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel1, vec2(fract(uv + t.ww))).x; var d_n: f32 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel1, vec2(fract(uv + t.wy))).x; var d_e: f32 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel1, vec2(fract(uv + t.xw))).x; var d_s: f32 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel1, vec2(fract(uv + t.wz))).x; var d_w: f32 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel1, vec2(fract(uv + -t.xw))).x; var d_nw: f32 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel1, vec2(fract(uv + -t.xz))).x; var d_sw: f32 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel1, vec2(fract(uv + -t.xy))).x; var d_ne: f32 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel1, vec2(fract(uv + t.xy))).x; var d_se: f32 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel1, vec2(fract(uv + t.xz))).x; return vec2(0.5 * (d_e - d_w) + 0.25 * (d_ne - d_nw + d_se - d_sw), 0.5 * (d_n - d_s) + 0.25 * (d_ne + d_nw - d_se - d_sw)); } fn gaussian_velocity(uv: vec2) -> vec4 { var texel: vec2 = 1. / uni.iResolution.xy; var t: vec4 = vec4(texel, -texel.y, 0.); var d: vec4 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (t.ww + 0.)))); var d_n: vec4 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (t.wy + 0.)))); var d_e: vec4 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (t.xw + 0.)))); var d_s: vec4 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (t.wz + 0.)))); var d_w: vec4 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (-t.xw + 0.)))); var d_nw: vec4 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (-t.xz + 0.)))); var d_sw: vec4 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (-t.xy + 0.)))); var d_ne: vec4 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (t.xy + 0.)))); var d_se: vec4 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (t.xz + 0.)))); return 0.25 * d + 0.125 * (d_e + d_w + d_n + d_s) + 0.0625 * (d_ne + d_nw + d_se + d_sw); } fn vector_laplacian(uv: vec2) -> vec2 { let _K0: f32 = -20. / 6.; let _K1: f32 = 4. / 6.; let _K2: f32 = 1. / 6.; let texel: vec2 = 1. / uni.iResolution.xy; let t: vec4 = vec4(texel, -texel.y, 0.); let d: vec4 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (t.ww + 0.)))); let d_n: vec4 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (t.wy + 0.)))); let d_e: vec4 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (t.xw + 0.)))); let d_s: vec4 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (t.wz + 0.)))); let d_w: vec4 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (-t.xw + 0.)))); let d_nw: vec4 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (-t.xz + 0.)))); let d_sw: vec4 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (-t.xy + 0.)))); let d_ne: vec4 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (t.xy + 0.)))); let d_se: vec4 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (t.xz + 0.)))); return (_K0 * d + _K1 * (d_e + d_w + d_n + d_s) + _K2 * (d_ne + d_nw + d_se + d_sw)).xy; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var fragColor: vec4; var fragCoord = vec2(f32(location.x), f32(location.y) ); let uv: vec2 = fragCoord / uni.iResolution.xy; let tx: vec2 = 1. / uni.iResolution.xy; var turb: vec2 = vec2(0.); var confine: vec2 = vec2(0.); var div: vec2 = vec2(0.); var delta_v: vec2 = vec2(0.); var offset: vec2 = vec2(0.); var lapl: vec2 = vec2(0.); var vel: vec4 = vec4(0.); var adv: vec4 = vec4(0.); let init: vec4 = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + +0.))); if (RECALCULATE_OFFSET) { for (var i: i32 = 0; i < 3; i = i + 1) { if (BLUR_TURBULENCE) { turb = gaussian_turbulence(uv + tx * offset); } else { turb = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2(fract(uv + (tx * offset + 0.)))).xy; } if (BLUR_CONFINEMENT) { confine = gaussian_confinement(uv + tx * offset); } else { confine = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2(fract(uv + (tx * offset + 0.)))).xy; } if (BLUR_VELOCITY) { vel = gaussian_velocity(uv + tx * offset); } else { vel = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (tx * offset + 0.)))); } offset = f32(i + 1.) / f32(3.) * -40. * (-0.05 * vel.xy + 1. * turb - 0.6 * confine + 0. * div); div = diff(uv + tx * 1. * offset); lapl = vector_laplacian(uv + tx * 1. * offset); adv = adv + (textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (tx * offset + 0.))))); delta_v = delta_v + (0.02 * lapl + 0. * turb + 0.01 * confine - 0.0001 * vel.xy - 0.1 * div); } adv = adv / (f32(3.)); delta_v = delta_v / (f32(3.)); } else { if (BLUR_TURBULENCE) { turb = gaussian_turbulence(uv); } else { turb = textureLoad_CONVERT_TO_i32(BUFFER_iChannel3, vec2(fract(uv + +0.))).xy; } if (BLUR_CONFINEMENT) { confine = gaussian_confinement(uv); } else { confine = textureLoad_CONVERT_TO_i32(BUFFER_iChannel2, vec2(fract(uv + +0.))).xy; } if (BLUR_VELOCITY) { vel = gaussian_velocity(uv); } else { vel = textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + +0.))); } offset = -40. * (-0.05 * vel.xy + 1. * turb - 0.6 * confine + 0. * div); div = diff(uv + tx * 1. * offset); lapl = vector_laplacian(uv + tx * 1. * offset); delta_v = delta_v + (0.02 * lapl + 0. * turb + 0.01 * confine - 0.0001 * vel.xy - 0.1 * div); for (var i: i32 = 0; i < 3; i = i + 1) { adv = adv + (textureLoad_CONVERT_TO_i32(BUFFER_iChannel0, vec2(fract(uv + (f32(i + 1.) / f32(3.) * tx * offset + 0.))))); } adv = adv / (f32(3.)); } let pq: vec2 = 2. * (uv * 2. - 1.) * vec2(1., tx.x / tx.y); if (CENTER_PUMP) { var pump: vec2 = sin(0.2 * uni.iTime) * 0.001 * pq.xy / (dot(pq, pq) + 0.01); } else { var pump: vec2 = vec2(0.); let uvy0: f32 = exp(-50. * pow(pq.y, 2.)); let uvx0: f32 = exp(-50. * pow(uv.x, 2.)); pump = pump + (-15. * vec2(max(0., cos(0.2 * uni.iTime)) * 0.001 * uvx0 * uvy0, 0.)); let uvy1: f32 = exp(-50. * pow(pq.y, 2.)); let uvx1: f32 = exp(-50. * pow(1. - uv.x, 2.)); pump = pump + (15. * vec2(max(0., cos(0.2 * uni.iTime + 3.1416)) * 0.001 * uvx1 * uvy1, 0.)); let uvy2: f32 = exp(-50. * pow(pq.x, 2.)); let uvx2: f32 = exp(-50. * pow(uv.y, 2.)); pump = pump + (-15. * vec2(0., max(0., sin(0.2 * uni.iTime)) * 0.001 * uvx2 * uvy2)); let uvy3: f32 = exp(-50. * pow(pq.x, 2.)); let uvx3: f32 = exp(-50. * pow(1. - uv.y, 2.)); pump = pump + (15. * vec2(0., max(0., sin(0.2 * uni.iTime + 3.1416)) * 0.001 * uvx3 * uvy3)); } fragColor = mix(adv + vec4(1. * (delta_v + pump), offset), init, 0.); if (uni.iMouse.z > 0.) { let mouseUV: vec4 = uni.iMouse / uni.iResolution.xyxy; let delta: vec2 = normz(mouseUV.zw - mouseUV.xy); let md: vec2 = (mouseUV.xy - uv) * vec2(1., tx.x / tx.y); let amp: f32 = exp(max(-12., -dot(md, md) / 0.001)); var fragColorxy = fragColor.xy; fragColorxy = fragColor.xy + (1. * 0.05 * clamp(amp * delta, -1., 1.)); fragColor.x = fragColorxy.x; fragColor.y = fragColorxy.y; } if (uni.iFrame == 0) { fragColor = 0.000001 * rand4(fragCoord, uni.iResolution.xy, uni.iFrame); } } ================================================ FILE: assets/shaders/mip_fluid/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; let RECALCULATE_OFFSET: bool = true; let BLUR_TURBULENCE: bool = false; let BLUR_CONFINEMENT: bool = false; let BLUR_VELOCITY: bool = false; let USE_PRESSURE_ADVECTION: bool = false; let PREMULTIPLY_CURL: bool = true; let VIEW_VELOCITY: bool = true; let CENTER_PUMP: bool = false; fn normz(x: vec4) -> vec4 { return if (x.xyz == vec3(0.)) { vec4(0., 0., 0., x.w); } else { vec4(normalize(x.xyz), 0.); }; } fn normz(x: vec3) -> vec3 { return if (x == vec3(0.)) { vec3(0.); } else { normalize(x); }; } fn normz(x: vec2) -> vec2 { return if (x == vec2(0.)) { vec2(0.); } else { normalize(x); }; } fn softmax(a: f32, b: f32, k: f32) -> f32 { return log(exp(k * a) + exp(k * b)) / k; } fn softmin(a: f32, b: f32, k: f32) -> f32 { return -log(exp(-k * a) + exp(-k * b)) / k; } fn softmax(a: vec4, b: vec4, k: f32) -> vec4 { return log(exp(k * a) + exp(k * b)) / k; } fn softmin(a: vec4, b: vec4, k: f32) -> vec4 { return -log(exp(-k * a) + exp(-k * b)) / k; } fn softclamp(a: f32, b: f32, x: f32, k: f32) -> f32 { return (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.; } fn softclamp(a: vec4, b: vec4, x: vec4, k: f32) -> vec4 { return (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.; } fn softclamp(a: f32, b: f32, x: vec4, k: f32) -> vec4 { return (softmin(vec4(b), softmax(vec4(a), x, k), k) + softmax(vec4(a), softmin(vec4(b), x, k), k)) / 2.; } fn G1V(dnv: f32, k: f32) -> f32 { return 1. / (dnv * (1. - k) + k); } fn ggx(n: vec3, v: vec3, l: vec3, rough: f32, f0: f32) -> f32 { let alpha: f32 = rough * rough; let h: vec3 = normalize(v + l); let dnl: f32 = clamp(dot(n, l), 0., 1.); let dnv: f32 = clamp(dot(n, v), 0., 1.); let dnh: f32 = clamp(dot(n, h), 0., 1.); var dlh: f32 = clamp(dot(l, h), 0., 1.); var f: f32; let d: f32; let vis: f32; let asqr: f32 = alpha * alpha; let pi: f32 = 3.14159; let den: f32 = dnh * dnh * (asqr - 1.) + 1.; d = asqr / (pi * den * den); dlh = pow(1. - dlh, 5.); f = f0 + (1. - f0) * dlh; var k: f32 = alpha / 1.; vis = G1V(dnl, k) * G1V(dnv, k); let spec: f32 = dnl * d * f * vis; return spec; } fn light(uv: vec2, BUMP: f32, SRC_DIST: f32, dxy: vec2, uni.iTime: f32, avd: ptr>) -> vec3 { let sp: vec3 = vec3(uv - 0.5, 0.); let light: vec3 = vec3(cos(uni.iTime / 2.) * 0.5, sin(uni.iTime / 2.) * 0.5, -SRC_DIST); var ld: vec3 = light - sp; let lDist: f32 = max(length(ld), 0.001); ld = ld / (lDist); (*avd) = reflect(normalize(vec3(BUMP * dxy, -1.)), vec3(0., 1., 0.)); return ld; } fn hash1(n: u32) -> f32 { var n_var = n; n_var = n_var << 13u ^ n_var; n_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u; return f32(n_var & vec3(2147483600.)) / f32(2147483600.); } fn hash3(n: u32) -> vec3 { var n_var = n; n_var = n_var << 13u ^ n_var; n_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u; let k: vec3 = n_var * vec3(n_var, n_var * 16807u, n_var * 48271u); return vec3(k & vec3(2147483600.)) / f32(2147483600.); } fn rand4(fragCoord: vec2, uni.iResolution: vec2, uni.iFrame: i32) -> vec4 { let p: vec2 = vec2(fragCoord); let r: vec2 = vec2(uni.iResolution); let c: u32 = p.x + r.x * p.y + r.x * r.y * u32(uni.iFrame); return vec4(hash3(c), hash1(c + 75132900.)); } fn tex(uv: vec2, mx: ptr>, my: ptr>, degree: i32) { let texel: vec2 = 1. / uni.iResolution.xy; let stride: f32 = f32(1 << degree); let mip: f32 = f32(degree); let t: vec4 = stride * vec4(texel, -texel.y, 0.); let d: vec2 = textureLod(iChannel0, fract(uv + t.ww), mip).xy; let d_n: vec2 = textureLod(iChannel0, fract(uv + t.wy), mip).xy; let d_e: vec2 = textureLod(iChannel0, fract(uv + t.xw), mip).xy; let d_s: vec2 = textureLod(iChannel0, fract(uv + t.wz), mip).xy; let d_w: vec2 = textureLod(iChannel0, fract(uv + -t.xw), mip).xy; let d_nw: vec2 = textureLod(iChannel0, fract(uv + -t.xz), mip).xy; let d_sw: vec2 = textureLod(iChannel0, fract(uv + -t.xy), mip).xy; let d_ne: vec2 = textureLod(iChannel0, fract(uv + t.xy), mip).xy; let d_se: vec2 = textureLod(iChannel0, fract(uv + t.xz), mip).xy; (*mx) = mat3x3(d_nw.x, d_n.x, d_ne.x, d_w.x, d.x, d_e.x, d_sw.x, d_s.x, d_se.x); (*my) = mat3x3(d_nw.y, d_n.y, d_ne.y, d_w.y, d.y, d_e.y, d_sw.y, d_s.y, d_se.y); } fn reduce(a: mat3x3, b: mat3x3) -> f32 { let p: mat3x3 = matrixCompMult(a, b); return arrayarray + arrayarray + arrayarray + arrayarray + arrayarray + arrayarray + arrayarray + arrayarray + arrayarray; } fn turbulence(fragCoord: vec2, turb: ptr>, curl: ptr) { let uv: vec2 = fragCoord.xy / uni.iResolution.xy; let turb_xx: mat3x3 = (2. - 0.9) * mat3x3(0.125, 0.25, 0.125, -0.25, -0.5, -0.25, 0.125, 0.25, 0.125); let turb_yy: mat3x3 = (2. - 0.9) * mat3x3(0.125, -0.25, 0.125, 0.25, -0.5, 0.25, 0.125, -0.25, 0.125); let turb_xy: mat3x3 = 0.9 * mat3x3(0.25, 0., -0.25, 0., 0., 0., -0.25, 0., 0.25); let norm: f32 = 8.8 / (4. + 8. * 0.6); let c0: f32 = 0.6; let curl_x: mat3x3 = mat3x3(c0, 1., c0, 0., 0., 0., -c0, -1., -c0); let curl_y: mat3x3 = mat3x3(c0, 0., -c0, 1., 0., -1., c0, 0., -c0); var mx: mat3x3; let my: mat3x3; var v: vec2 = vec2(0.); var turb_wc: f32 = 0.; var curl_wc: f32 = 0.; (*curl) = 0.; for (var i: i32 = 0; i < TURBULENCE_SCALES; i = i + 1) { tex(uv, mx, my, i); let turb_w: f32 = 1.; let curl_w: f32 = 1. / f32(i + 1.); v = v + (turb_w * vec2(reduce(turb_xx, mx) + reduce(turb_xy, my), reduce(turb_yy, my) + reduce(turb_xy, mx))); (*curl) = (*curl) + (curl_w * (reduce(curl_x, mx) + reduce(curl_y, my))); turb_wc = turb_wc + (turb_w); curl_wc = curl_wc + (curl_w); } (*turb) = f32(TURBULENCE_SCALES) * v / turb_wc; (*curl) = norm * (*curl) / curl_wc; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var fragColor: vec4; var fragCoord = vec2(f32(location.x), f32(location.y) ); var turb: vec2; var curl: f32; turbulence(fragCoord, turb, curl); fragColor = vec4(turb, 0., curl); if (uni.iFrame == 0) { fragColor = 0.000001 * rand4(fragCoord, uni.iResolution.xy, uni.iFrame); } } ================================================ FILE: assets/shaders/mip_fluid/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; let RECALCULATE_OFFSET: bool = true; let BLUR_TURBULENCE: bool = false; let BLUR_CONFINEMENT: bool = false; let BLUR_VELOCITY: bool = false; let USE_PRESSURE_ADVECTION: bool = false; let PREMULTIPLY_CURL: bool = true; let VIEW_VELOCITY: bool = true; let CENTER_PUMP: bool = false; fn normz(x: vec4) -> vec4 { return if (x.xyz == vec3(0.)) { vec4(0., 0., 0., x.w); } else { vec4(normalize(x.xyz), 0.); }; } fn normz(x: vec3) -> vec3 { return if (x == vec3(0.)) { vec3(0.); } else { normalize(x); }; } fn normz(x: vec2) -> vec2 { return if (x == vec2(0.)) { vec2(0.); } else { normalize(x); }; } fn softmax(a: f32, b: f32, k: f32) -> f32 { return log(exp(k * a) + exp(k * b)) / k; } fn softmin(a: f32, b: f32, k: f32) -> f32 { return -log(exp(-k * a) + exp(-k * b)) / k; } fn softmax(a: vec4, b: vec4, k: f32) -> vec4 { return log(exp(k * a) + exp(k * b)) / k; } fn softmin(a: vec4, b: vec4, k: f32) -> vec4 { return -log(exp(-k * a) + exp(-k * b)) / k; } fn softclamp(a: f32, b: f32, x: f32, k: f32) -> f32 { return (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.; } fn softclamp(a: vec4, b: vec4, x: vec4, k: f32) -> vec4 { return (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.; } fn softclamp(a: f32, b: f32, x: vec4, k: f32) -> vec4 { return (softmin(vec4(b), softmax(vec4(a), x, k), k) + softmax(vec4(a), softmin(vec4(b), x, k), k)) / 2.; } fn G1V(dnv: f32, k: f32) -> f32 { return 1. / (dnv * (1. - k) + k); } fn ggx(n: vec3, v: vec3, l: vec3, rough: f32, f0: f32) -> f32 { let alpha: f32 = rough * rough; let h: vec3 = normalize(v + l); let dnl: f32 = clamp(dot(n, l), 0., 1.); let dnv: f32 = clamp(dot(n, v), 0., 1.); let dnh: f32 = clamp(dot(n, h), 0., 1.); var dlh: f32 = clamp(dot(l, h), 0., 1.); var f: f32; let d: f32; let vis: f32; let asqr: f32 = alpha * alpha; let pi: f32 = 3.14159; let den: f32 = dnh * dnh * (asqr - 1.) + 1.; d = asqr / (pi * den * den); dlh = pow(1. - dlh, 5.); f = f0 + (1. - f0) * dlh; var k: f32 = alpha / 1.; vis = G1V(dnl, k) * G1V(dnv, k); let spec: f32 = dnl * d * f * vis; return spec; } fn light(uv: vec2, BUMP: f32, SRC_DIST: f32, dxy: vec2, uni.iTime: f32, avd: ptr>) -> vec3 { let sp: vec3 = vec3(uv - 0.5, 0.); let light: vec3 = vec3(cos(uni.iTime / 2.) * 0.5, sin(uni.iTime / 2.) * 0.5, -SRC_DIST); var ld: vec3 = light - sp; let lDist: f32 = max(length(ld), 0.001); ld = ld / (lDist); (*avd) = reflect(normalize(vec3(BUMP * dxy, -1.)), vec3(0., 1., 0.)); return ld; } fn hash1(n: u32) -> f32 { var n_var = n; n_var = n_var << 13u ^ n_var; n_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u; return f32(n_var & vec3(2147483600.)) / f32(2147483600.); } fn hash3(n: u32) -> vec3 { var n_var = n; n_var = n_var << 13u ^ n_var; n_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u; let k: vec3 = n_var * vec3(n_var, n_var * 16807u, n_var * 48271u); return vec3(k & vec3(2147483600.)) / f32(2147483600.); } fn rand4(fragCoord: vec2, uni.iResolution: vec2, uni.iFrame: i32) -> vec4 { let p: vec2 = vec2(fragCoord); let r: vec2 = vec2(uni.iResolution); let c: u32 = p.x + r.x * p.y + r.x * r.y * u32(uni.iFrame); return vec4(hash3(c), hash1(c + 75132900.)); } fn tex(uv: vec2, mc: ptr>, curl: ptr, degree: i32) { let texel: vec2 = 1. / uni.iResolution.xy; let stride: f32 = f32(1 << degree); let mip: f32 = f32(degree); let t: vec4 = stride * vec4(texel, -texel.y, 0.); let d: f32 = abs(textureLod(iChannel0, fract(uv + t.ww), mip).w); let d_n: f32 = abs(textureLod(iChannel0, fract(uv + t.wy), mip).w); let d_e: f32 = abs(textureLod(iChannel0, fract(uv + t.xw), mip).w); let d_s: f32 = abs(textureLod(iChannel0, fract(uv + t.wz), mip).w); let d_w: f32 = abs(textureLod(iChannel0, fract(uv + -t.xw), mip).w); let d_nw: f32 = abs(textureLod(iChannel0, fract(uv + -t.xz), mip).w); let d_sw: f32 = abs(textureLod(iChannel0, fract(uv + -t.xy), mip).w); let d_ne: f32 = abs(textureLod(iChannel0, fract(uv + t.xy), mip).w); let d_se: f32 = abs(textureLod(iChannel0, fract(uv + t.xz), mip).w); (*mc) = mat3x3(d_nw, d_n, d_ne, d_w, d, d_e, d_sw, d_s, d_se); (*curl) = textureLod(iChannel0, fract(uv + +0.), mip).w; } fn reduce(a: mat3x3, b: mat3x3) -> f32 { let p: mat3x3 = matrixCompMult(a, b); return arrayarray + arrayarray + arrayarray + arrayarray + arrayarray + arrayarray + arrayarray + arrayarray + arrayarray; } fn confinement(fragCoord: vec2) -> vec2 { let uv: vec2 = fragCoord.xy / uni.iResolution.xy; let k0: f32 = 0.25; let k1: f32 = 1. - 2. * 0.25; let conf_x: mat3x3 = mat3x3(-k0, -k1, -k0, 0., 0., 0., k0, k1, k0); let conf_y: mat3x3 = mat3x3(-k0, 0., k0, -k1, 0., k1, -k0, 0., k0); var mc: mat3x3; var v: vec2 = vec2(0.); var curl: f32; var cacc: f32 = 0.; var nacc: vec2 = vec2(0.); var wc: f32 = 0.; for (var i: i32 = 0; i < VORTICITY_SCALES; i = i + 1) { tex(uv, mc, curl, i); let w: f32 = 1.; let n: vec2 = w * normz(vec2(reduce(conf_x, mc), reduce(conf_y, mc))); v = v + (curl * n); cacc = cacc + (curl); nacc = nacc + (n); wc = wc + (w); } if (PREMULTIPLY_CURL) { return v / wc; } else { return nacc * cacc / wc; } } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var fragColor: vec4; var fragCoord = vec2(f32(location.x), f32(location.y) ); fragColor = vec4(confinement(fragCoord), 0., 0.); if (uni.iFrame == 0) { fragColor = 0.000001 * rand4(fragCoord, uni.iResolution.xy, uni.iFrame); } } ================================================ FILE: assets/shaders/mip_fluid/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; let RECALCULATE_OFFSET: bool = true; let BLUR_TURBULENCE: bool = false; let BLUR_CONFINEMENT: bool = false; let BLUR_VELOCITY: bool = false; let USE_PRESSURE_ADVECTION: bool = false; let PREMULTIPLY_CURL: bool = true; let VIEW_VELOCITY: bool = true; let CENTER_PUMP: bool = false; fn normz(x: vec4) -> vec4 { return if (x.xyz == vec3(0.)) { vec4(0., 0., 0., x.w); } else { vec4(normalize(x.xyz), 0.); }; } fn normz(x: vec3) -> vec3 { return if (x == vec3(0.)) { vec3(0.); } else { normalize(x); }; } fn normz(x: vec2) -> vec2 { return if (x == vec2(0.)) { vec2(0.); } else { normalize(x); }; } fn softmax(a: f32, b: f32, k: f32) -> f32 { return log(exp(k * a) + exp(k * b)) / k; } fn softmin(a: f32, b: f32, k: f32) -> f32 { return -log(exp(-k * a) + exp(-k * b)) / k; } fn softmax(a: vec4, b: vec4, k: f32) -> vec4 { return log(exp(k * a) + exp(k * b)) / k; } fn softmin(a: vec4, b: vec4, k: f32) -> vec4 { return -log(exp(-k * a) + exp(-k * b)) / k; } fn softclamp(a: f32, b: f32, x: f32, k: f32) -> f32 { return (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.; } fn softclamp(a: vec4, b: vec4, x: vec4, k: f32) -> vec4 { return (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.; } fn softclamp(a: f32, b: f32, x: vec4, k: f32) -> vec4 { return (softmin(vec4(b), softmax(vec4(a), x, k), k) + softmax(vec4(a), softmin(vec4(b), x, k), k)) / 2.; } fn G1V(dnv: f32, k: f32) -> f32 { return 1. / (dnv * (1. - k) + k); } fn ggx(n: vec3, v: vec3, l: vec3, rough: f32, f0: f32) -> f32 { let alpha: f32 = rough * rough; let h: vec3 = normalize(v + l); let dnl: f32 = clamp(dot(n, l), 0., 1.); let dnv: f32 = clamp(dot(n, v), 0., 1.); let dnh: f32 = clamp(dot(n, h), 0., 1.); var dlh: f32 = clamp(dot(l, h), 0., 1.); var f: f32; let d: f32; let vis: f32; let asqr: f32 = alpha * alpha; let pi: f32 = 3.14159; let den: f32 = dnh * dnh * (asqr - 1.) + 1.; d = asqr / (pi * den * den); dlh = pow(1. - dlh, 5.); f = f0 + (1. - f0) * dlh; var k: f32 = alpha / 1.; vis = G1V(dnl, k) * G1V(dnv, k); let spec: f32 = dnl * d * f * vis; return spec; } fn light(uv: vec2, BUMP: f32, SRC_DIST: f32, dxy: vec2, uni.iTime: f32, avd: ptr>) -> vec3 { let sp: vec3 = vec3(uv - 0.5, 0.); let light: vec3 = vec3(cos(uni.iTime / 2.) * 0.5, sin(uni.iTime / 2.) * 0.5, -SRC_DIST); var ld: vec3 = light - sp; let lDist: f32 = max(length(ld), 0.001); ld = ld / (lDist); (*avd) = reflect(normalize(vec3(BUMP * dxy, -1.)), vec3(0., 1., 0.)); return ld; } fn hash1(n: u32) -> f32 { var n_var = n; n_var = n_var << 13u ^ n_var; n_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u; return f32(n_var & vec3(2147483600.)) / f32(2147483600.); } fn hash3(n: u32) -> vec3 { var n_var = n; n_var = n_var << 13u ^ n_var; n_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u; let k: vec3 = n_var * vec3(n_var, n_var * 16807u, n_var * 48271u); return vec3(k & vec3(2147483600.)) / f32(2147483600.); } fn rand4(fragCoord: vec2, uni.iResolution: vec2, uni.iFrame: i32) -> vec4 { let p: vec2 = vec2(fragCoord); let r: vec2 = vec2(uni.iResolution); let c: u32 = p.x + r.x * p.y + r.x * r.y * u32(uni.iFrame); return vec4(hash3(c), hash1(c + 75132900.)); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/mip_fluid/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; [[group(0), binding(6)]] var font_texture: texture_2d; [[group(0), binding(7)]] var font_texture_sampler: sampler; [[group(0), binding(8)]] var rgba_noise_256_texture: texture_2d; [[group(0), binding(9)]] var rgba_noise_256_texture_sampler: sampler; // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // let color = vec4(f32(0)); // textureStore(texture, location, color); // } // Why are the characters so pixelated? // One possible reason is that we are in a compute shader and the textures are not // filtered. let backColorDebug: vec3 = vec3(0.2, 0.2, 0.2); var uv_debug: vec2 ; var tp_debug: vec2 ; var align_debug: vec4; // north, east, south, west var font_size_debug: f32; var dotColor_debug: vec3 = vec3(0.5, 0.5, 0.); var drawColorDebug: vec3 = vec3(1., 1., 0.); var vColor: vec3 = backColorDebug; var aspect_debug: f32 = 1.; var pixelPosDebug: vec2 = vec2(0., 0.); let FONT_SPACE_DEBUG: f32 = 0.5; let headColorDebug: vec3 = vec3(0.9, 0.6, 0.2); let mpColorDebug: vec3 = vec3(0.99, 0.99, 0.); let mxColorDebug: vec3 = vec3(1., 0., 0.); let myColorDebug: vec3 = vec3(0., 1., 0.); let font_png_size_debug: vec2 = vec2(1023.0, 1023.0); fn char(ch: i32) -> f32 { let fr = fract(floor(vec2(f32(ch), 15.999 - f32(ch) / 16.)) / 16.); let q = clamp(tp_debug, vec2(0.), vec2(1.)) / 16. + fr ; let inverted_q = vec2(q.x, 1. - q.y); // // There is aliasing on the characters // let f = textureSampleGrad(font_texture, // font_texture_sampler, // inverted_q, // vec2(1.0, 0.0), // vec2(0.0, 1.0)); // using textureLoad without sampler let q1 = vec2(font_png_size_debug * q ); let y_inverted_q1 = vec2(q1.x, i32(font_png_size_debug.y) - q1.y); var f: vec4 = textureLoad(font_texture, y_inverted_q1 , 0); // smoothing out the aliasing let dx = vec2(1, 0); let dy = vec2(0, 1); let fx1: vec4 = textureLoad(font_texture, y_inverted_q1 + dx, 0); let fx2: vec4 = textureLoad(font_texture, y_inverted_q1 - dx, 0); let fy1: vec4 = textureLoad(font_texture, y_inverted_q1 + dy, 0); let fy2: vec4 = textureLoad(font_texture, y_inverted_q1 - dy, 0); let rp = 0.25; f = f * rp + (1.0 - rp) * (fx1 + fx2 + fy1 + fy2) / 4.0 ; return f.x * (f.y + 0.3) * (f.z + 0.3) * 2.; } fn SetTextPosition(x: f32, y: f32) { tp_debug = 10. * uv_debug; tp_debug.x = tp_debug.x + 17. - x; tp_debug.y = tp_debug.y - 9.4 + y; } fn SetTextPositionAbs(x: f32, y: f32) { tp_debug.x = 10. * uv_debug.x - x; tp_debug.y = 10. * uv_debug.y - y; } fn drawFract(value: ptr, digits: ptr) -> f32 { var c: f32 = 0.; *value = fract(*value) * 10.; for (var ni: i32 = 1; ni < 60; ni = ni + 1) { c = c + (char(48 + i32(*value))); tp_debug.x = tp_debug.x - (0.5); *digits = *digits - (1); *value = fract(*value) * 10.; if (*digits <= 0 || *value == 0.) { break; } } tp_debug.x = tp_debug.x - (0.5 * f32(*digits)); return c; } fn maxInt(a: i32, b: i32) -> i32 { var ret: i32; if (a > b) { ret = a; } else { ret = b; }; return ret; } fn drawInt(value: ptr, minDigits: ptr) -> f32 { var c: f32 = 0.; if (*value < 0) { *value = -*value; if (*minDigits < 1) { *minDigits = 1; } else { *minDigits = *minDigits - 1; } c = c + (char(45)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); } var fn2: i32 = *value; var digits: i32 = 1; for (var ni: i32 = 0; ni < 10; ni = ni + 1) { fn2 = fn2 / (10); if (fn2 == 0) { break; } digits = digits + 1; } digits = maxInt(*minDigits, digits); tp_debug.x = tp_debug.x - (0.5 * f32(digits)); for (var ni: i32 = 1; ni < 11; ni = ni + 1) { tp_debug.x = tp_debug.x + (0.5); c = c + (char(48 + *value % 10)); *value = *value / (10); if (ni >= digits) { break; } } tp_debug.x = tp_debug.x - (0.5 * f32(digits)); return c; } fn drawIntBackwards(value: ptr, minDigits: ptr) -> f32 { var c: f32 = 0.; let original_value: i32 = *value; if (*value < 0) { *value = -*value; if (*minDigits < 1) { *minDigits = 1; } else { *minDigits = *minDigits - 1; } // tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); // c = c + (char(45)); } var fn2: i32 = *value; var digits: i32 = 1; for (var ni: i32 = 0; ni < 10; ni = ni + 1) { fn2 = fn2 / (10); if (fn2 == 0) { break; } digits = digits + 1; } digits = maxInt(*minDigits, digits); // tp_debug.x = tp_debug.x - (0.5 * f32(digits)); for (var ni: i32 = digits - 1; ni < 11; ni = ni - 1) { tp_debug.x = tp_debug.x + (0.5); c = c + (char(48 + *value % 10)); *value = *value / (10); if (ni == 0) { break; } } if (original_value < 0) { tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); c = c + (char(45)); } // tp_debug.x = tp_debug.x + (0.5 * f32(digits)); return c; } // fn drawFloat(value: ptr, prec: ptr, maxDigits: i32) -> f32 { fn drawFloat(val: f32, prec: ptr, maxDigits: i32) -> f32 { // in case of 0.099999..., round up to 0.1000000 var value = round(val * pow(10., f32(maxDigits))) / pow(10., f32(maxDigits)); let tp_debugx: f32 = tp_debug.x - 0.5 * f32(maxDigits); var c: f32 = 0.; if (value < 0.) { c = char(45); value = -value; } tp_debug.x = tp_debug.x - (0.5); var ival = i32(value); var one: i32 = 1; c = c + (drawInt(&ival, &one)); c = c + (char(46)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); var frac_val = fract(value); c = c + (drawFract(&frac_val, prec)); tp_debug.x = min(tp_debug.x, tp_debugx); return c; } fn drawFloat_f32(value: f32) -> f32 { var two: i32 = 2; return drawFloat(value, &two, 5); } fn drawFloat_f32_prec(value: f32, prec: ptr) -> f32 { return drawFloat(value, prec, 2); } fn drawInt_i32_back(value: ptr) -> f32 { var one: i32 = 1; return drawIntBackwards(value, &one); } fn drawInt_i32(value: ptr) -> f32 { var one: i32 = 1; return drawInt(value, &one); } fn SetColor(red: f32, green: f32, blue: f32) { drawColorDebug = vec3(red, green, blue); } fn WriteFloat(fValue: f32, maxDigits: i32, decimalPlaces: ptr) { // vColor = mix(vColor, drawColorDebug, drawFloat_f32_prec(fValue, decimalPlaces)); vColor = mix(vColor, drawColorDebug, drawFloat(fValue, decimalPlaces, maxDigits)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); ; } fn WriteFloatBox( fValue: f32, maxDigits: i32, decimalPlaces: i32, alpha: f32 ) { var decs = decimalPlaces; vColor = mix(vColor, drawColorDebug, drawFloat(fValue, &decs, maxDigits) * alpha); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); ; } fn WriteInteger(iValue: ptr) { vColor = mix(vColor, drawColorDebug, drawInt_i32(iValue)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); } fn WriteIntegerBack(iValue: ptr) { vColor = mix(vColor, drawColorDebug, drawInt_i32_back(iValue)); tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); } fn WriteFPS() { var fps: f32 = f32(uni.iSampleRate); SetColor(0.8, 0.6, 0.3); var max_digits_one = 1; WriteFloat(fps, 5, &max_digits_one); var c: f32 = 0.; c = c + (char(102)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(112)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(115)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); // let c2 = smoothStep(0.0, 1.0, c ); vColor = mix(vColor, drawColorDebug, c); } fn WriteMousePos(mPos: vec2, y_pos: f32) { let digits: i32 = 3; let radius: f32 = uni.iResolution.x / 400.; if (uni.iMouse.z > 0.) { dotColor_debug = mpColorDebug; } let r: f32 = length(abs(mPos.xy) - pixelPosDebug) - radius; // vColor = vColor + (mix(vec3(0.), dotColor_debug, 1. - clamp(r, 0., 1.))); var max_digits_three: i32 = 3; var mposxi: i32 = i32(mPos.x); var mposyi: i32 = i32(mPos.y); var mposx: f32 = (mPos.x); var mposy: f32 = (mPos.y); let x_pos = align_debug.y - 1. * FONT_SPACE_DEBUG; SetTextPositionAbs( x_pos, y_pos, ); drawColorDebug = myColorDebug; WriteIntegerBack(&mposyi); SetTextPositionAbs( x_pos - 7. * FONT_SPACE_DEBUG, y_pos, ); drawColorDebug = mxColorDebug; WriteIntegerBack(&mposxi); } fn sdRoundedBox(p: vec2, b: vec2, r: vec4) -> f32 { var x = r.x; var y = r.y; x = select(r.z, r.x, p.x > 0.); y = select(r.w, r.y, p.x > 0.); x = select(y, x, p.y > 0.); let q = abs(p) - b + x; return min(max(q.x, q.y), 0.) + length(max(q, vec2(0.))) - x; } fn WriteRGBAValues( location: vec2, value: vec4, screen_poz: vec2, alpha: f32, ) { let poz = screen_poz / uni.iResolution * 20. * vec2(aspect_debug, 1.0); let window_ajusted = uni.iResolution / vec2(960., 600.); let box_pos = vec2(align_debug.w, align_debug.x - FONT_SPACE_DEBUG ) / 10.; // let box_pos = mp; // // box location follows mouse position // let box_location = vec2( // uni.iMouse.x + 100. * window_ajusted.x / ( aspect_debug / 1.6 ) , // uni.iMouse.y - 48. * window_ajusted.y // ); let box_location = vec2( 100. * window_ajusted.x / ( aspect_debug / 1.6 ) , uni.iResolution.y - 60. * window_ajusted.y, ); let inverted_screen_poz = vec2(screen_poz.x, -screen_poz.y) ; // / vec2(aspect_debug, 1.) ; let d_box = sdRoundedBox( vec2(location) - box_location - inverted_screen_poz, vec2(73. / ( aspect_debug / 1.6 ), 75.) * window_ajusted, vec4(5.,5.,5.,5.) * 5.0 ); // let alpha = 0.225; let decimal_places = 3; SetColor(1., 1., 1.); var c: f32 = 0.; let lspace = 0.8; let bg_color = vec3(.8, .7, .9); vColor = mix( vColor, bg_color, (1.0 - step(0.0, d_box)) * alpha ); // red SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1.) - 0.0 + poz.y ) ; c = c + (char(114)); // r tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.r, 3, decimal_places, alpha ); // green SetTextPosition( 10. * ((box_pos.x +1. + lspace)) + poz.x, 10. * (-box_pos.y +1. ) + 1.0 + poz.y, ) ; c = c + (char(103)); // g tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.g, 3, decimal_places, alpha ); // blue SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1. ) + 2.0 + poz.y, ) ; c = c + (char(98)); // b tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.b, 4, decimal_places, alpha ); // alpha SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1. ) + 3.0 + poz.y, ) ; c = c + (char(97)); // a tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.a, 4, decimal_places, alpha ); vColor = mix(vColor, drawColorDebug, c * alpha); } fn sdSegment(p: vec2, a: vec2, b: vec2) -> f32 { let pa = p - a; let ba = b - a; let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.); return length(pa - ba * h); } fn ring(pos: vec2, radius: f32, thick: f32) -> f32 { return mix(1., 0., smoothStep(thick, thick + 0.01, abs(length(uv_debug - pos) - radius))); } fn sdCircle(p: vec2, c: vec2, r: f32) -> f32 { let d = length(p - c); return d - r; } fn draw_ring(location: vec2) { let mouse_click_poz = vec2(abs(uni.iMouse.z) , abs(uni.iMouse.w)); let alpha = 0.75; let ring_dist = sdCircle(vec2(location) , mouse_click_poz, 2.3); let d = smoothStep(0.5, 1.5, abs(ring_dist - 1.)); vColor = mix(vColor, headColorDebug, (1. - d) * alpha ); } fn draw_crossair(location: vec2) { let start = 5.0; let end = 20.; let segment1 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(start, 0.), vec2(end, 0.) ); let segment2 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(-start, 0.), vec2(-end, 0.) ); let segment3 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(0., start), vec2(0., end) ); let segment4 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(0., -start), vec2(0., -end) ); var alpha = 0.75; if (uni.iMouse.z > 0.) { alpha = 1.0; } let d = smoothStep(0.5, 1.5, segment1); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothStep(0.5, 1.5, segment2); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothStep(0.5, 1.5, segment3); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothStep(0.5, 1.5, segment4); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); } fn show_debug_info(location: vec2, color: vec3) -> vec4 { var fragCoord = vec2(f32(location.x), f32(location.y) ); vColor = color; aspect_debug = uni.iResolution.x / uni.iResolution.y; let ratio: vec2 = vec2(aspect_debug, 1.); pixelPosDebug = fragCoord.xy; // mousePosDebug = uni.iMouse.xy; uv_debug = (2. * fragCoord.xy / uni.iResolution.xy - 1.) * ratio; align_debug = 10. * vec4( 1., // North aspect_debug, // East -1., // South -aspect_debug, // West ); WriteMousePos(uni.iMouse.zw, align_debug.z + 2.0 * FONT_SPACE_DEBUG); // Click position WriteMousePos(uni.iMouse.xy, align_debug.z + 0.2 * FONT_SPACE_DEBUG); // Current mouse position var c: f32 = 0.; SetTextPositionAbs( align_debug.y - FONT_SPACE_DEBUG, align_debug.x - 2. * FONT_SPACE_DEBUG, ); SetColor(0.8, 0.8, 0.8); var resx = i32(uni.iResolution.x); var resy = i32(uni.iResolution.y); WriteIntegerBack(&resx); c = c + (char(28)); tp_debug.x = tp_debug.x + 0. * (FONT_SPACE_DEBUG); WriteIntegerBack(&resy); SetTextPositionAbs( align_debug.w - 1. * FONT_SPACE_DEBUG, align_debug.z - 0. * FONT_SPACE_DEBUG, ); WriteFPS(); SetColor(0.9, 0.7, 0.8); let fragColor = vec4(vColor, 1.); let poz = vec2(0., uni.iResolution.y / 2.); // // RGBA probe labels follow mouse // let poz = vec2(uni.iMouse.x , uni.iResolution.y - uni.iMouse.y); let inverted_y_mouse_location = vec2(vec2(uni.iMouse.x, uni.iResolution.y - uni.iMouse.y)); let value: vec4 = textureLoad(texture, inverted_y_mouse_location); WriteRGBAValues(location, value, poz, 0.85); let inverted_y_mouseclick_location = vec2(vec2(abs(uni.iMouse.z), uni.iResolution.y - abs(uni.iMouse.w))); let value2: vec4 = textureLoad(texture, inverted_y_mouseclick_location); WriteRGBAValues(location, value2, vec2(0.), 0.65); draw_crossair(location); draw_ring(location); let fragColor = vec4(vColor, 1.); return fragColor; } let RECALCULATE_OFFSET: bool = true; let BLUR_TURBULENCE: bool = false; let BLUR_CONFINEMENT: bool = false; let BLUR_VELOCITY: bool = false; let USE_PRESSURE_ADVECTION: bool = false; let PREMULTIPLY_CURL: bool = true; let VIEW_VELOCITY: bool = true; let CENTER_PUMP: bool = false; fn normz(x: vec4) -> vec4 { return if (x.xyz == vec3(0.)) { vec4(0., 0., 0., x.w); } else { vec4(normalize(x.xyz), 0.); }; } fn normz(x: vec3) -> vec3 { return if (x == vec3(0.)) { vec3(0.); } else { normalize(x); }; } fn normz(x: vec2) -> vec2 { return if (x == vec2(0.)) { vec2(0.); } else { normalize(x); }; } fn softmax(a: f32, b: f32, k: f32) -> f32 { return log(exp(k * a) + exp(k * b)) / k; } fn softmin(a: f32, b: f32, k: f32) -> f32 { return -log(exp(-k * a) + exp(-k * b)) / k; } fn softmax(a: vec4, b: vec4, k: f32) -> vec4 { return log(exp(k * a) + exp(k * b)) / k; } fn softmin(a: vec4, b: vec4, k: f32) -> vec4 { return -log(exp(-k * a) + exp(-k * b)) / k; } fn softclamp(a: f32, b: f32, x: f32, k: f32) -> f32 { return (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.; } fn softclamp(a: vec4, b: vec4, x: vec4, k: f32) -> vec4 { return (softmin(b, softmax(a, x, k), k) + softmax(a, softmin(b, x, k), k)) / 2.; } fn softclamp(a: f32, b: f32, x: vec4, k: f32) -> vec4 { return (softmin(vec4(b), softmax(vec4(a), x, k), k) + softmax(vec4(a), softmin(vec4(b), x, k), k)) / 2.; } fn G1V(dnv: f32, k: f32) -> f32 { return 1. / (dnv * (1. - k) + k); } fn ggx(n: vec3, v: vec3, l: vec3, rough: f32, f0: f32) -> f32 { let alpha: f32 = rough * rough; let h: vec3 = normalize(v + l); let dnl: f32 = clamp(dot(n, l), 0., 1.); let dnv: f32 = clamp(dot(n, v), 0., 1.); let dnh: f32 = clamp(dot(n, h), 0., 1.); var dlh: f32 = clamp(dot(l, h), 0., 1.); var f: f32; let d: f32; let vis: f32; let asqr: f32 = alpha * alpha; let pi: f32 = 3.14159; let den: f32 = dnh * dnh * (asqr - 1.) + 1.; d = asqr / (pi * den * den); dlh = pow(1. - dlh, 5.); f = f0 + (1. - f0) * dlh; var k: f32 = alpha / 1.; vis = G1V(dnl, k) * G1V(dnv, k); let spec: f32 = dnl * d * f * vis; return spec; } fn light(uv: vec2, BUMP: f32, SRC_DIST: f32, dxy: vec2, uni.iTime: f32, avd: ptr>) -> vec3 { let sp: vec3 = vec3(uv - 0.5, 0.); let light: vec3 = vec3(cos(uni.iTime / 2.) * 0.5, sin(uni.iTime / 2.) * 0.5, -SRC_DIST); var ld: vec3 = light - sp; let lDist: f32 = max(length(ld), 0.001); ld = ld / (lDist); (*avd) = reflect(normalize(vec3(BUMP * dxy, -1.)), vec3(0., 1., 0.)); return ld; } fn hash1(n: u32) -> f32 { var n_var = n; n_var = n_var << 13u ^ n_var; n_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u; return f32(n_var & vec3(2147483600.)) / f32(2147483600.); } fn hash3(n: u32) -> vec3 { var n_var = n; n_var = n_var << 13u ^ n_var; n_var = n_var * (n_var * n_var * 15731u + 789221u) + 1376312589u; let k: vec3 = n_var * vec3(n_var, n_var * 16807u, n_var * 48271u); return vec3(k & vec3(2147483600.)) / f32(2147483600.); } fn rand4(fragCoord: vec2, uni.iResolution: vec2, uni.iFrame: i32) -> vec4 { let p: vec2 = vec2(fragCoord); let r: vec2 = vec2(uni.iResolution); let c: u32 = p.x + r.x * p.y + r.x * r.y * u32(uni.iFrame); return vec4(hash3(c), hash1(c + 75132900.)); } // displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a // here [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var O: vec4 = textureLoad(buffer_a, location); textureStore(texture, location, O); } ================================================ FILE: assets/shaders/mixing_liquid/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // struct Particle { // a: vec4; // b: vec4; // }; // fn dum(x: Particle) { // let x2 = Particle(x.a, x.b); // let bah = x.a + 1.0; // return; // } // fn miam() -> Particle { // var out: Particle; // out.a = vec4(0.0); // out.b = vec4(1.0); // return out; // } // let ch0: texture_storage_2d = buffer_a; // let ch1: texture_storage_2d = buffer_a; // let ch2: texture_storage_2d = buffer_a; // let ch3: texture_storage_2d = buffer_a; // #define Bf(p) p // #define Bi(p) ivec2(p) // #define texel(a, p) texelFetch(a, Bi(p), 0) // #define pixel(a, p) texture(a, (p)/R) let PI = 3.14159265; let dt = 1.5; let border_h = 5.; var R: vec2 ; var Mouse: vec4 ; var time: f32; let mass = 1.; let fluid_rho = 0.5; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn border(p: vec2) -> f32 { let bound: f32 = -sdBox(p - R * 0.5, R * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time) * (p - R * vec2(0.5, 0.6)), R * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R * vec2(0.5, 0.7), R * vec2(1.5, 0.5)); return max(drain, min(bound, box)); } let h: f32 = 1.; fn bN(p: vec2) -> vec3 { let dx: vec3 = vec3(-h, 0.0, h); let idx: vec4 = vec4(-1. / h, 0., 1. / h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx); return vec3(normalize(r.xy), r.z + 0.0001); } fn pack(xIn: vec2) -> u32 { var x = xIn; let x = 65534. * clamp(0.5 * x + 0.5, vec2(0.000000001), vec2(0.999999999)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw); return P; } fn saveParticle(P: particle, pos: vec2) -> vec4 { var P2: particle = P; P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); return vec4(encode(P2.X), encode(P2.V), P2.M); } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } let dif: f32 = 1.12; fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } // don't forget to use a return value when using Reintegration fn Reintegration(ch: texture_storage_2d, pos: vec2) -> particle { //basically integral over all updated neighbor distributions //that fall inside of this pixel //this makes the tracking conservative for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(i)); // let data: vec4 = texel(ch, tpos); // let data: vec4 = texelFetch(ch, ivec2(tpos), 0); let data: vec4 = textureLoad(ch, vec2(tpos)); var P0: particle = getParticle(data, tpos); P0.X = P0.X + (P0.V * dt);//integrate position let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x); let D: vec3 = distribution(P0.X, pos, difR); //the deposited mass into this cell let m: f32 = P0.M.x * D.z; var P1: particle; // TODO: change the input particle directly using (*P).X = ... //add weighted by mass P1.X = P1.X + (D.xy * m); P1.V = P1.V + (P0.V * m); P1.M.y = P1.M.y + (P0.M.y * m); //add mass P1.M.x = P1.M.x + (m); } } //normalization if (P1.M.x != 0.) { P1.X = P1.X / (P1.M.x); P1.V = P1.V / (P1.M.x); P1.M.y = P1.M.y / (P1.M.x); } return P1; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let color = vec4(0.5); // textureStore(buffer_a, location, color); // } // fn mainImage( U: vec4, pos: vec2) -> () { let pos: vec2 = vec2(location); R = uni.iResolution.xy; time = uni.iTime; Mouse = uni.iMouse; let p: vec2 = location; // let data: vec4 = texel(ch0, pos); // buffer_b is set as the channel 0 in Buffer A of the paint // streams inside shadertoy // let data: vec4 = textureLoad(buffer_b, location); var P: particle = Reintegration(buffer_b, pos); // if (uni.iFrame < 4.0) { # ifdef INIT let rand: vec3 = hash32(pos); if (rand.z < 0.) { P.X = pos; P.V = 0.5 * (rand.xy - 0.5) + vec2(0., 0.); P.M = vec2(mass, 0.); } else { P.X = pos; P.V = vec2(0.); P.M = vec2(0.000001); } # endif // } textureStore(buffer_a, location, saveParticle(P, pos)); } ================================================ FILE: assets/shaders/mixing_liquid/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // struct Particle { // a: vec4; // b: vec4; // }; // fn dum(x: Particle) { // let x2 = Particle(x.a, x.b); // let bah = x.a + 1.0; // return; // } // fn miam() -> Particle { // var out: Particle; // out.a = vec4(0.0); // out.b = vec4(1.0); // return out; // } // let ch0: texture_storage_2d = buffer_a; // let ch1: texture_storage_2d = buffer_a; // let ch2: texture_storage_2d = buffer_a; // let ch3: texture_storage_2d = buffer_a; // #define Bf(p) p // #define Bi(p) ivec2(p) // #define texel(a, p) texelFetch(a, Bi(p), 0) // #define pixel(a, p) texture(a, (p)/R) let PI = 3.14159265; let dt = 1.5; let border_h = 5.; var R: vec2 ; var Mouse: vec4 ; var time: f32; let mass = 1.; let fluid_rho = 0.5; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn border(p: vec2) -> f32 { let bound: f32 = -sdBox(p - R * 0.5, R * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time) * (p - R * vec2(0.5, 0.6)), R * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R * vec2(0.5, 0.7), R * vec2(1.5, 0.5)); return max(drain, min(bound, box)); } let h: f32 = 1.; fn bN(p: vec2) -> vec3 { let dx: vec3 = vec3(-h, 0.0, h); let idx: vec4 = vec4(-1. / h, 0., 1. / h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx); return vec3(normalize(r.xy), r.z + 0.0001); } fn pack(xIn: vec2) -> u32 { var x = xIn; let x = 65534. * clamp(0.5 * x + 0.5, vec2(0.000000001), vec2(0.999999999)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw); return P; } fn saveParticle(P: particle, pos: vec2) -> vec4 { var P2: particle = P; P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); return vec4(encode(P2.X), encode(P2.V), P2.M); } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } let dif: f32 = 1.12; fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } fn Simulation(ch: texture_storage_2d, P: particle, pos: vec2) -> particle { var F: vec2 = vec2(0.); var avgV: vec3 = vec3(0.); for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(i)); // let data: vec4 = texel(ch, tpos); // let data: vec4 = texelFetch(ch, ivec2(tpos), 0); let data: vec4 = textureLoad(ch, vec2(tpos)); let P0: particle = getParticle(data, tpos); let dx: vec2 = P0.X - P.X; let avgP: f32 = 0.5 * P0.M.x * (Pf(P.M) + Pf(P0.M)); F = F - (0.5 * G(1. * dx) * avgP * dx); avgV = avgV + (P0.M.x * G(1. * dx) * vec3(P0.V, 1.)); } } avgV.y = avgV.y / (avgV.z); avgV.x = avgV.x / (avgV.z); //viscosity F = F + (0. * P.M.x * (avgV.xy - P.V)); //gravity F = F + (P.M.x * vec2(0., -0.0004)); if (Mouse.z > 0.) { let dm: vec2 = (Mouse.xy - Mouse.zw) / 10.; let d: f32 = distance(Mouse.xy, P.X) / 20.; F = F + (0.001 * dm * exp(-d * d)); } var P1: particle = P; //integrate P1.V = P1.V + (F * dt / P1.M.x); //border let N: vec3 = bN(P1.X); let vdotN: f32 = step(N.z, border_h) * dot(-N.xy, P1.V); P1.V = P1.V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN))); P1.V = P1.V + (0. * P1.M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z)); if (N.z < 0.) { P1.V = vec2(0.); } //velocity limit let v: f32 = length(P1.V); var vv: f32; if (v > 1.) { vv = v; } else { vv = 1.; }; P1.V = P1.V / vv; return P1; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { // } // fn mainImage( U: vec4, pos: vec2) -> () { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let pos: vec2 = vec2(location); R = uni.iResolution.xy; time = uni.iTime; Mouse = uni.iMouse; let p: vec2 = location; // let data: vec4 = texel(buffer_a, pos); let data: vec4 = textureLoad(buffer_a, location); var P: particle = getParticle(data, pos); if (P.M.x != 0.) { P = Simulation(buffer_a, P, pos); } if (length(P.X - R * vec2(0.8, 0.9)) < 10.) { P.X = pos; P.V = 0.5 * Dir(-PI * 0.25 - PI * 0.5 + 0.3 * sin(0.4 * time)); P.M = mix(P.M, vec2(fluid_rho, 1.), 0.4); } if (length(P.X - R * vec2(0.2, 0.9)) < 10.) { P.X = pos; P.V = 0.5 * Dir(-PI * 0.25 + 0.3 * sin(0.3 * time)); P.M = mix(P.M, vec2(fluid_rho, 0.), 0.4); } // U = saveParticle(P, pos); textureStore(buffer_b, location, saveParticle(P, pos)); } ================================================ FILE: assets/shaders/mixing_liquid/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // struct Particle { // a: vec4; // b: vec4; // }; // fn dum(x: Particle) { // let x2 = Particle(x.a, x.b); // let bah = x.a + 1.0; // return; // } // fn miam() -> Particle { // var out: Particle; // out.a = vec4(0.0); // out.b = vec4(1.0); // return out; // } // let ch0: texture_storage_2d = buffer_a; // let ch1: texture_storage_2d = buffer_a; // let ch2: texture_storage_2d = buffer_a; // let ch3: texture_storage_2d = buffer_a; // #define Bf(p) p // #define Bi(p) ivec2(p) // #define texel(a, p) texelFetch(a, Bi(p), 0) // #define pixel(a, p) texture(a, (p)/R) let PI = 3.14159265; let dt = 1.5; let border_h = 5.; var R: vec2 ; var Mouse: vec4 ; var time: f32; let mass = 1.; let fluid_rho = 0.5; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn border(p: vec2) -> f32 { let bound: f32 = -sdBox(p - R * 0.5, R * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time) * (p - R * vec2(0.5, 0.6)), R * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R * vec2(0.5, 0.7), R * vec2(1.5, 0.5)); return max(drain, min(bound, box)); } let h: f32 = 1.; fn bN(p: vec2) -> vec3 { let dx: vec3 = vec3(-h, 0.0, h); let idx: vec4 = vec4(-1. / h, 0., 1. / h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx); return vec3(normalize(r.xy), r.z + 0.0001); } fn pack(xIn: vec2) -> u32 { var x = xIn; let x = 65534. * clamp(0.5 * x + 0.5, vec2(0.000000001), vec2(0.999999999)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw); return P; } fn saveParticle(P: particle, pos: vec2) -> vec4 { var P2: particle = P; P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); return vec4(encode(P2.X), encode(P2.V), P2.M); } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } let dif: f32 = 1.12; fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { // fn mainImage( fragColor: vec4, pos: vec2) -> () { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); R = uni.iResolution.xy; time = uni.iTime; Mouse = uni.iMouse; let pos = vec2(location); let p: vec2 = vec2(pos); let data: vec4 = textureLoad(buffer_a, location); var P: particle = getParticle(data, pos); // let data: vec4 = texel(ch0, pos); // let P: particle = getParticle(data, pos); var rho: vec4 = vec4(0.); for (var i: i32 = -1; i <= 1; i = i + 1) { for (var j: i32 = -1; j <= 1; j = j + 1) { let ij: vec2 = vec2(i, j); // let data: vec4 = texel(ch0, pos + ij); let data: vec4 = textureLoad(buffer_a, location + ij); var P0: particle = getParticle(data, pos + vec2(ij)); let x0: vec2 = P0.X; rho = rho + (1. * vec4(P.V, P.M) * G((pos - x0) / 0.75)); } } textureStore(buffer_c, location, rho); } ================================================ FILE: assets/shaders/mixing_liquid/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // struct Particle { // a: vec4; // b: vec4; // }; // fn dum(x: Particle) { // let x2 = Particle(x.a, x.b); // let bah = x.a + 1.0; // return; // } // fn miam() -> Particle { // var out: Particle; // out.a = vec4(0.0); // out.b = vec4(1.0); // return out; // } // let ch0: texture_storage_2d = buffer_a; // let ch1: texture_storage_2d = buffer_a; // let ch2: texture_storage_2d = buffer_a; // let ch3: texture_storage_2d = buffer_a; // #define Bf(p) p // #define Bi(p) ivec2(p) // #define texel(a, p) texelFetch(a, Bi(p), 0) // #define pixel(a, p) texture(a, (p)/R) let PI = 3.14159265; let dt = 1.5; let border_h = 5.; var R: vec2 ; var Mouse: vec4 ; var time: f32; let mass = 1.; let fluid_rho = 0.5; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn border(p: vec2) -> f32 { let bound: f32 = -sdBox(p - R * 0.5, R * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time) * (p - R * vec2(0.5, 0.6)), R * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R * vec2(0.5, 0.7), R * vec2(1.5, 0.5)); return max(drain, min(bound, box)); } let h: f32 = 1.; fn bN(p: vec2) -> vec3 { let dx: vec3 = vec3(-h, 0.0, h); let idx: vec4 = vec4(-1. / h, 0., 1. / h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx); return vec3(normalize(r.xy), r.z + 0.0001); } fn pack(xIn: vec2) -> u32 { var x = xIn; let x = 65534. * clamp(0.5 * x + 0.5, vec2(0.000000001), vec2(0.999999999)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw); return P; } fn saveParticle(P: particle, pos: vec2) -> vec4 { var P2: particle = P; P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); return vec4(encode(P2.X), encode(P2.V), P2.M); } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } let dif: f32 = 1.12; fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/mixing_liquid/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; [[group(0), binding(6)]] var font_texture: texture_2d; [[group(0), binding(7)]] var font_texture_sampler: sampler; [[group(0), binding(8)]] var rgba_noise_256_texture: texture_2d; [[group(0), binding(9)]] var rgba_noise_256_texture_sampler: sampler; // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // let color = vec4(f32(0)); // textureStore(texture, location, color); // } // Why are the characters so pixelated? // One possible reason is that we are in a compute shader and the textures are not // filtered. let backColorDebug: vec3 = vec3(0.2, 0.2, 0.2); var uv_debug: vec2 ; var tp_debug: vec2 ; var align_debug: vec4; // north, east, south, west var font_size_debug: f32; var dotColor_debug: vec3 = vec3(0.5, 0.5, 0.); var drawColorDebug: vec3 = vec3(1., 1., 0.); var vColor: vec3 = backColorDebug; var aspect_debug: f32 = 1.; var pixelPosDebug: vec2 = vec2(0., 0.); let FONT_SPACE_DEBUG: f32 = 0.5; let headColorDebug: vec3 = vec3(0.9, 0.6, 0.2); let mpColorDebug: vec3 = vec3(0.99, 0.99, 0.); let mxColorDebug: vec3 = vec3(1., 0., 0.); let myColorDebug: vec3 = vec3(0., 1., 0.); let font_png_size_debug: vec2 = vec2(1023.0, 1023.0); fn char(ch: i32) -> f32 { let fr = fract(floor(vec2(f32(ch), 15.999 - f32(ch) / 16.)) / 16.); let q = clamp(tp_debug, vec2(0.), vec2(1.)) / 16. + fr ; let inverted_q = vec2(q.x, 1. - q.y); // // There is aliasing on the characters // let f = textureSampleGrad(font_texture, // font_texture_sampler, // inverted_q, // vec2(1.0, 0.0), // vec2(0.0, 1.0)); // using textureLoad without sampler let q1 = vec2(font_png_size_debug * q ); let y_inverted_q1 = vec2(q1.x, i32(font_png_size_debug.y) - q1.y); var f: vec4 = textureLoad(font_texture, y_inverted_q1 , 0); // smoothing out the aliasing let dx = vec2(1, 0); let dy = vec2(0, 1); let fx1: vec4 = textureLoad(font_texture, y_inverted_q1 + dx, 0); let fx2: vec4 = textureLoad(font_texture, y_inverted_q1 - dx, 0); let fy1: vec4 = textureLoad(font_texture, y_inverted_q1 + dy, 0); let fy2: vec4 = textureLoad(font_texture, y_inverted_q1 - dy, 0); let rp = 0.25; f = f * rp + (1.0 - rp) * (fx1 + fx2 + fy1 + fy2) / 4.0 ; return f.x * (f.y + 0.3) * (f.z + 0.3) * 2.; } fn SetTextPosition(x: f32, y: f32) { tp_debug = 10. * uv_debug; tp_debug.x = tp_debug.x + 17. - x; tp_debug.y = tp_debug.y - 9.4 + y; } fn SetTextPositionAbs(x: f32, y: f32) { tp_debug.x = 10. * uv_debug.x - x; tp_debug.y = 10. * uv_debug.y - y; } fn drawFract(value: ptr, digits: ptr) -> f32 { var c: f32 = 0.; *value = fract(*value) * 10.; for (var ni: i32 = 1; ni < 60; ni = ni + 1) { c = c + (char(48 + i32(*value))); tp_debug.x = tp_debug.x - (0.5); *digits = *digits - (1); *value = fract(*value) * 10.; if (*digits <= 0 || *value == 0.) { break; } } tp_debug.x = tp_debug.x - (0.5 * f32(*digits)); return c; } fn maxInt(a: i32, b: i32) -> i32 { var ret: i32; if (a > b) { ret = a; } else { ret = b; }; return ret; } fn drawInt(value: ptr, minDigits: ptr) -> f32 { var c: f32 = 0.; if (*value < 0) { *value = -*value; if (*minDigits < 1) { *minDigits = 1; } else { *minDigits = *minDigits - 1; } c = c + (char(45)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); } var fn2: i32 = *value; var digits: i32 = 1; for (var ni: i32 = 0; ni < 10; ni = ni + 1) { fn2 = fn2 / (10); if (fn2 == 0) { break; } digits = digits + 1; } digits = maxInt(*minDigits, digits); tp_debug.x = tp_debug.x - (0.5 * f32(digits)); for (var ni: i32 = 1; ni < 11; ni = ni + 1) { tp_debug.x = tp_debug.x + (0.5); c = c + (char(48 + *value % 10)); *value = *value / (10); if (ni >= digits) { break; } } tp_debug.x = tp_debug.x - (0.5 * f32(digits)); return c; } fn drawIntBackwards(value: ptr, minDigits: ptr) -> f32 { var c: f32 = 0.; let original_value: i32 = *value; if (*value < 0) { *value = -*value; if (*minDigits < 1) { *minDigits = 1; } else { *minDigits = *minDigits - 1; } // tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); // c = c + (char(45)); } var fn2: i32 = *value; var digits: i32 = 1; for (var ni: i32 = 0; ni < 10; ni = ni + 1) { fn2 = fn2 / (10); if (fn2 == 0) { break; } digits = digits + 1; } digits = maxInt(*minDigits, digits); // tp_debug.x = tp_debug.x - (0.5 * f32(digits)); for (var ni: i32 = digits - 1; ni < 11; ni = ni - 1) { tp_debug.x = tp_debug.x + (0.5); c = c + (char(48 + *value % 10)); *value = *value / (10); if (ni == 0) { break; } } if (original_value < 0) { tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); c = c + (char(45)); } // tp_debug.x = tp_debug.x + (0.5 * f32(digits)); return c; } // fn drawFloat(value: ptr, prec: ptr, maxDigits: i32) -> f32 { fn drawFloat(val: f32, prec: ptr, maxDigits: i32) -> f32 { // in case of 0.099999..., round up to 0.1000000 var value = round(val * pow(10., f32(maxDigits))) / pow(10., f32(maxDigits)); let tp_debugx: f32 = tp_debug.x - 0.5 * f32(maxDigits); var c: f32 = 0.; if (value < 0.) { c = char(45); value = -value; } tp_debug.x = tp_debug.x - (0.5); var ival = i32(value); var one: i32 = 1; c = c + (drawInt(&ival, &one)); c = c + (char(46)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); var frac_val = fract(value); c = c + (drawFract(&frac_val, prec)); tp_debug.x = min(tp_debug.x, tp_debugx); return c; } fn drawFloat_f32(value: f32) -> f32 { var two: i32 = 2; return drawFloat(value, &two, 5); } fn drawFloat_f32_prec(value: f32, prec: ptr) -> f32 { return drawFloat(value, prec, 2); } fn drawInt_i32_back(value: ptr) -> f32 { var one: i32 = 1; return drawIntBackwards(value, &one); } fn drawInt_i32(value: ptr) -> f32 { var one: i32 = 1; return drawInt(value, &one); } fn SetColor(red: f32, green: f32, blue: f32) { drawColorDebug = vec3(red, green, blue); } fn WriteFloat(fValue: f32, maxDigits: i32, decimalPlaces: ptr) { // vColor = mix(vColor, drawColorDebug, drawFloat_f32_prec(fValue, decimalPlaces)); vColor = mix(vColor, drawColorDebug, drawFloat(fValue, decimalPlaces, maxDigits)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); ; } fn WriteFloatBox( fValue: f32, maxDigits: i32, decimalPlaces: i32, alpha: f32 ) { var decs = decimalPlaces; vColor = mix(vColor, drawColorDebug, drawFloat(fValue, &decs, maxDigits) * alpha); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); ; } fn WriteInteger(iValue: ptr) { vColor = mix(vColor, drawColorDebug, drawInt_i32(iValue)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); } fn WriteIntegerBack(iValue: ptr) { vColor = mix(vColor, drawColorDebug, drawInt_i32_back(iValue)); tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); } fn WriteFPS() { var fps: f32 = f32(uni.iSampleRate); SetColor(0.8, 0.6, 0.3); var max_digits_one = 1; WriteFloat(fps, 5, &max_digits_one); var c: f32 = 0.; c = c + (char(102)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(112)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(115)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); // let c2 = smoothStep(0.0, 1.0, c ); vColor = mix(vColor, drawColorDebug, c); } fn WriteMousePos(mPos: vec2, y_pos: f32) { let digits: i32 = 3; let radius: f32 = uni.iResolution.x / 400.; if (uni.iMouse.z > 0.) { dotColor_debug = mpColorDebug; } let r: f32 = length(abs(mPos.xy) - pixelPosDebug) - radius; // vColor = vColor + (mix(vec3(0.), dotColor_debug, 1. - clamp(r, 0., 1.))); var max_digits_three: i32 = 3; var mposxi: i32 = i32(mPos.x); var mposyi: i32 = i32(mPos.y); var mposx: f32 = (mPos.x); var mposy: f32 = (mPos.y); let x_pos = align_debug.y - 1. * FONT_SPACE_DEBUG; SetTextPositionAbs( x_pos, y_pos, ); drawColorDebug = myColorDebug; WriteIntegerBack(&mposyi); SetTextPositionAbs( x_pos - 7. * FONT_SPACE_DEBUG, y_pos, ); drawColorDebug = mxColorDebug; WriteIntegerBack(&mposxi); } fn sdRoundedBox(p: vec2, b: vec2, r: vec4) -> f32 { var x = r.x; var y = r.y; x = select(r.z, r.x, p.x > 0.); y = select(r.w, r.y, p.x > 0.); x = select(y, x, p.y > 0.); let q = abs(p) - b + x; return min(max(q.x, q.y), 0.) + length(max(q, vec2(0.))) - x; } fn WriteRGBAValues( location: vec2, value: vec4, screen_poz: vec2, alpha: f32, ) { let poz = screen_poz / uni.iResolution * 20. * vec2(aspect_debug, 1.0); let window_ajusted = uni.iResolution / vec2(960., 600.); let box_pos = vec2(align_debug.w, align_debug.x - FONT_SPACE_DEBUG ) / 10.; // let box_pos = mp; // // box location follows mouse position // let box_location = vec2( // uni.iMouse.x + 100. * window_ajusted.x / ( aspect_debug / 1.6 ) , // uni.iMouse.y - 48. * window_ajusted.y // ); let box_location = vec2( 100. * window_ajusted.x / ( aspect_debug / 1.6 ) , uni.iResolution.y - 60. * window_ajusted.y, ); let inverted_screen_poz = vec2(screen_poz.x, -screen_poz.y) ; // / vec2(aspect_debug, 1.) ; let d_box = sdRoundedBox( vec2(location) - box_location - inverted_screen_poz, vec2(73. / ( aspect_debug / 1.6 ), 75.) * window_ajusted, vec4(5.,5.,5.,5.) * 5.0 ); // let alpha = 0.225; let decimal_places = 3; SetColor(1., 1., 1.); var c: f32 = 0.; let lspace = 0.8; let bg_color = vec3(.8, .7, .9); vColor = mix( vColor, bg_color, (1.0 - step(0.0, d_box)) * alpha ); // red SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1.) - 0.0 + poz.y ) ; c = c + (char(114)); // r tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.r, 3, decimal_places, alpha ); // green SetTextPosition( 10. * ((box_pos.x +1. + lspace)) + poz.x, 10. * (-box_pos.y +1. ) + 1.0 + poz.y, ) ; c = c + (char(103)); // g tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.g, 3, decimal_places, alpha ); // blue SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1. ) + 2.0 + poz.y, ) ; c = c + (char(98)); // b tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.b, 4, decimal_places, alpha ); // alpha SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1. ) + 3.0 + poz.y, ) ; c = c + (char(97)); // a tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.a, 4, decimal_places, alpha ); vColor = mix(vColor, drawColorDebug, c * alpha); } fn sdSegment(p: vec2, a: vec2, b: vec2) -> f32 { let pa = p - a; let ba = b - a; let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.); return length(pa - ba * h); } fn ring(pos: vec2, radius: f32, thick: f32) -> f32 { return mix(1., 0., smoothStep(thick, thick + 0.01, abs(length(uv_debug - pos) - radius))); } fn sdCircle(p: vec2, c: vec2, r: f32) -> f32 { let d = length(p - c); return d - r; } fn draw_ring(location: vec2) { let mouse_click_poz = vec2(abs(uni.iMouse.z) , abs(uni.iMouse.w)); let alpha = 0.75; let ring_dist = sdCircle(vec2(location) , mouse_click_poz, 2.3); let d = smoothStep(0.5, 1.5, abs(ring_dist - 1.)); vColor = mix(vColor, headColorDebug, (1. - d) * alpha ); } fn draw_crossair(location: vec2) { let start = 5.0; let end = 20.; let segment1 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(start, 0.), vec2(end, 0.) ); let segment2 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(-start, 0.), vec2(-end, 0.) ); let segment3 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(0., start), vec2(0., end) ); let segment4 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(0., -start), vec2(0., -end) ); var alpha = 0.75; if (uni.iMouse.z > 0.) { alpha = 1.0; } let d = smoothStep(0.5, 1.5, segment1); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothStep(0.5, 1.5, segment2); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothStep(0.5, 1.5, segment3); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothStep(0.5, 1.5, segment4); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); } fn show_debug_info(location: vec2, color: vec3) -> vec4 { var fragCoord = vec2(f32(location.x), f32(location.y) ); vColor = color; aspect_debug = uni.iResolution.x / uni.iResolution.y; let ratio: vec2 = vec2(aspect_debug, 1.); pixelPosDebug = fragCoord.xy; // mousePosDebug = uni.iMouse.xy; uv_debug = (2. * fragCoord.xy / uni.iResolution.xy - 1.) * ratio; align_debug = 10. * vec4( 1., // North aspect_debug, // East -1., // South -aspect_debug, // West ); WriteMousePos(uni.iMouse.zw, align_debug.z + 2.0 * FONT_SPACE_DEBUG); // Click position WriteMousePos(uni.iMouse.xy, align_debug.z + 0.2 * FONT_SPACE_DEBUG); // Current mouse position var c: f32 = 0.; SetTextPositionAbs( align_debug.y - FONT_SPACE_DEBUG, align_debug.x - 2. * FONT_SPACE_DEBUG, ); SetColor(0.8, 0.8, 0.8); var resx = i32(uni.iResolution.x); var resy = i32(uni.iResolution.y); WriteIntegerBack(&resx); c = c + (char(28)); tp_debug.x = tp_debug.x + 0. * (FONT_SPACE_DEBUG); WriteIntegerBack(&resy); SetTextPositionAbs( align_debug.w - 1. * FONT_SPACE_DEBUG, align_debug.z - 0. * FONT_SPACE_DEBUG, ); WriteFPS(); SetColor(0.9, 0.7, 0.8); let fragColor = vec4(vColor, 1.); let poz = vec2(0., uni.iResolution.y / 2.); // // RGBA probe labels follow mouse // let poz = vec2(uni.iMouse.x , uni.iResolution.y - uni.iMouse.y); let inverted_y_mouse_location = vec2(vec2(uni.iMouse.x, uni.iResolution.y - uni.iMouse.y)); let value: vec4 = textureLoad(texture, inverted_y_mouse_location); WriteRGBAValues(location, value, poz, 0.85); let inverted_y_mouseclick_location = vec2(vec2(abs(uni.iMouse.z), uni.iResolution.y - abs(uni.iMouse.w))); let value2: vec4 = textureLoad(texture, inverted_y_mouseclick_location); WriteRGBAValues(location, value2, vec2(0.), 0.65); draw_crossair(location); draw_ring(location); let fragColor = vec4(vColor, 1.); return fragColor; } // struct Particle { // a: vec4; // b: vec4; // }; // fn dum(x: Particle) { // let x2 = Particle(x.a, x.b); // let bah = x.a + 1.0; // return; // } // fn miam() -> Particle { // var out: Particle; // out.a = vec4(0.0); // out.b = vec4(1.0); // return out; // } // let ch0: texture_storage_2d = buffer_a; // let ch1: texture_storage_2d = buffer_a; // let ch2: texture_storage_2d = buffer_a; // let ch3: texture_storage_2d = buffer_a; // #define Bf(p) p // #define Bi(p) ivec2(p) // #define texel(a, p) texelFetch(a, Bi(p), 0) // #define pixel(a, p) texture(a, (p)/R) let PI = 3.14159265; let dt = 1.5; let border_h = 5.; var R: vec2 ; var Mouse: vec4 ; var time: f32; let mass = 1.; let fluid_rho = 0.5; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn border(p: vec2) -> f32 { let bound: f32 = -sdBox(p - R * 0.5, R * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time) * (p - R * vec2(0.5, 0.6)), R * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R * vec2(0.5, 0.7), R * vec2(1.5, 0.5)); return max(drain, min(bound, box)); } let h: f32 = 1.; fn bN(p: vec2) -> vec3 { let dx: vec3 = vec3(-h, 0.0, h); let idx: vec4 = vec4(-1. / h, 0., 1. / h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx); return vec3(normalize(r.xy), r.z + 0.0001); } fn pack(xIn: vec2) -> u32 { var x = xIn; let x = 65534. * clamp(0.5 * x + 0.5, vec2(0.000000001), vec2(0.999999999)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw); return P; } fn saveParticle(P: particle, pos: vec2) -> vec4 { var P2: particle = P; P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); return vec4(encode(P2.X), encode(P2.V), P2.M); } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } let dif: f32 = 1.12; fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } fn mixN(a: vec3, b: vec3, k: f32) -> vec3 { return sqrt(mix(a * a, b * b, clamp(k, 0., 1.))); } fn V(p: vec2) -> vec4 { // return pixel(ch1, p); return textureLoad(buffer_c, vec2(p)); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); R = uni.iResolution.xy; time = uni.iTime; Mouse = uni.iMouse; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); // var O: vec4 = textureLoad(buffer_a, location); // textureStore(texture, location, O); // } // fn mainImage( col: vec4, pos: vec2) -> () { // let p: vec2 = vec2(pos); // let data: vec4 = texel(ch0, pos); let p: vec2 = location; let data: vec4 = textureLoad(buffer_a, location); let pos = vec2(location); var P: particle = getParticle(data, pos); let Nb: vec3 = bN(P.X); let bord: f32 = smoothStep(2. * border_h, border_h * 0.5, border(pos)); let rho: vec4 = V(pos); let dx: vec3 = vec3(-2., 0., 2.); let grad: vec4 = -0.5 * vec4(V(pos + dx.zy).zw - V(pos + dx.xy).zw, V(pos + dx.yz).zw - V(pos + dx.yx).zw); let N: vec2 = pow(length(grad.xz), 0.2) * normalize(grad.xz + 0.00001); let specular: f32 = pow(max(dot(N, Dir(1.4)), 0.), 3.5); let specularb: f32 = G(0.4 * (Nb.zz - border_h)) * pow(max(dot(Nb.xy, Dir(1.4)), 0.), 3.); let a: f32 = pow(smoothStep(fluid_rho * 0., fluid_rho * 2., rho.z), 0.1); let b: f32 = exp(-1.7 * smoothStep(fluid_rho * 1., fluid_rho * 7.5, rho.z)); let col0: vec3 = vec3(1., 0.5, 0.); let col1: vec3 = vec3(0.1, 0.4, 1.); let fcol: vec3 = mixN(col0, col1, tanh(3. * (rho.w - 0.7)) * 0.5 + 0.5); // var col: vec4; var col: vec3 = vec3(3.); col = mixN(col.xyz, fcol.xyz * (1.5 * b + specular * 5.), a); col = mixN(col, 0. * vec3(0.5, 0.5, 1.), bord); col = tanh(col); let col4 = vec4(col, 3.0); textureStore(texture, y_inverted_location, col4); } ================================================ FILE: assets/shaders/molecular_dynamics/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // #define T(p) texelFetch(iChannel0, ivec2(mod(p,R)), 0) // #define P(p) texture(iChannel0, mod(p,R)/R) // #define C(p) texture(iChannel1, mod(p,R)/R) // #define GS(x) exp(-dot(x,x)) // #define GS0(x) exp(-length(x)) // #define CI(x) smoothstep(1.0, 0.9, length(x)) // #define Dir(ang) vec2(cos(ang), sin(ang)) // #define Rot(ang) mat2(cos(ang), sin(ang), -sin(ang), cos(ang)) // #define PACK(X) ( uint(round(65534.0*clamp(0.5*X.x+0.5, 0., 1.))) + \ // 65535u*uint(round(65534.0*clamp(0.5*X.y+0.5, 0., 1.))) ) // #define UNPACK(X) (clamp(vec2(X%65535u, X/65535u)/65534.0, 0.,1.)*2.0 - 1.0) // #define DECODE(X) UNPACK(floatBitsToUint(X)) // #define ENCODE(X) uintBitsToFloat(PACK(X)) let PI = 3.14159265; let dt = 0.4; // let R = uni.iResolution.xy; let cooling = 1.5; fn GS(x1: vec2) -> f32 { return exp(-dot(x1, x1)); } fn MF(dx: vec2) -> f32 { return -GS(0.75 * dx) + 0.15 * GS(0.4 * dx); } fn Ha(x: vec2) -> f32 { var x2: f32; if (x.x >= 0.) { x2 = 1.; } else { x2 = 0.0; } if (x.y >= 0.) { x2 = x2; } else { x2 = 0.0; } // return (x.x >= 0. ? 1. : 0.) * (x.y >= 0. ? 1. : 0.); return x2; } fn Hb(x: vec2) -> f32 { // return (x.x > 0. ? 1. : 0.) * (x.y > 0. ? 1. : 0.); var x2: f32; if (x.x > 0.) { x2 = 1.; } else { x2 = 0.0; } if (x.y > 0.) { x2 = x2; } else { x2 = 0.0; } return x2; } fn unpack(X: u32) -> vec2 { return (clamp( vec2(f32(X % 65535u), f32(X / 65535u)) / 65534.0, vec2(0.), vec2(1.) ) * 2.0 - 1.0 ) ; } fn pack(v: vec2) -> u32 { return ( u32(round(65534.0*clamp(0.5*v.x+0.5, 0., 1.))) + 65535u*u32(round(65534.0*clamp(0.5*v.y+0.5, 0., 1.))) ) ; } fn PD(x: vec2, pos: vec2) -> vec3 { return vec3(x, 1.) * Ha(x - (pos - 0.5)) * Hb(pos + 0.5 - x); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let R = uni.iResolution.xy; let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let color = vec4(0.5); // textureStore(buffer_a, location, color); // } // fn mainImage( U: vec4, pos: vec2) { let pos = location; let p: vec2 = vec2(pos); var X: vec2 = vec2(0.); var V: vec2 = vec2(0.); var M: f32 = 0.; for (var i: i32 = -1; i <= 1; i = i + 1) { for (var j: i32 = -1; j <= 1; j = j + 1) { let tpos: vec2 = pos + vec2(i, j); // let data: vec4 = T(tpos); let data: vec4 = textureLoad(buffer_b, tpos % vec2( R)); var X0: vec2 = unpack(u32(data.x)) + vec2(tpos); var V0: vec2 = unpack(u32(data.y)); // var X0: vec2 = DECODE(data.x) + tpos; // let V0: vec2 = DECODE(data.y); let M0: i32 = i32(data.z); let M0H: i32 = M0 / 2; X0 = X0 + (V0 * dt); var m: vec3; if (M0 >= 2) { m = f32(M0H) * PD(X0 + vec2(0.5, 0.), vec3(pos)) + f32(M0 - M0H) * PD(X0 - vec2(0.5, 0.), vec3(pos)) ; } else { m = f32(M0) * PD(X0, vec3(pos)); } X = X + (m.xy); V = V + (V0 * m.z); M = M + (m.z); } } if (M != 0.) { X = X / (M); V = V / (M); } #ifdef INIT X = vec2(pos); V = vec2(0.); M = Ha(vec2(pos) - (R * 0.5 - R.x * 0.1)) * Hb(R * 0.5 + R.x * 0.1 - vec2(pos)); #endif X = X - vec2(pos); let eX = f32(pack(X)); let eV = f32(pack(V)); let U = vec4(eX, eV, M, 0.); textureStore(buffer_a, location, U); } ================================================ FILE: assets/shaders/molecular_dynamics/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // #define T(p) texelFetch(iChannel0, ivec2(mod(p,R)), 0) // #define P(p) texture(iChannel0, mod(p,R)/R) // #define C(p) texture(iChannel1, mod(p,R)/R) // #define GS(x) exp(-dot(x,x)) // #define GS0(x) exp(-length(x)) // #define CI(x) smoothstep(1.0, 0.9, length(x)) // #define Dir(ang) vec2(cos(ang), sin(ang)) // #define Rot(ang) mat2(cos(ang), sin(ang), -sin(ang), cos(ang)) // #define PACK(X) ( uint(round(65534.0*clamp(0.5*X.x+0.5, 0., 1.))) + \ // 65535u*uint(round(65534.0*clamp(0.5*X.y+0.5, 0., 1.))) ) // #define UNPACK(X) (clamp(vec2(X%65535u, X/65535u)/65534.0, 0.,1.)*2.0 - 1.0) // #define DECODE(X) UNPACK(floatBitsToUint(X)) // #define ENCODE(X) uintBitsToFloat(PACK(X)) let PI = 3.14159265; let dt = 0.4; // let R = uni.iResolution.xy; let cooling = 1.5; fn GS(x1: vec2) -> f32 { return exp(-dot(x1, x1)); } fn MF(dx: vec2) -> f32 { return -GS(0.75 * dx) + 0.15 * GS(0.4 * dx); } fn Ha(x: vec2) -> f32 { var x2: f32; if (x.x >= 0.) { x2 = 1.; } else { x2 = 0.0; } if (x.y >= 0.) { x2 = x2; } else { x2 = 0.0; } // return (x.x >= 0. ? 1. : 0.) * (x.y >= 0. ? 1. : 0.); return x2; } fn Hb(x: vec2) -> f32 { // return (x.x > 0. ? 1. : 0.) * (x.y > 0. ? 1. : 0.); var x2: f32; if (x.x > 0.) { x2 = 1.; } else { x2 = 0.0; } if (x.y > 0.) { x2 = x2; } else { x2 = 0.0; } return x2; } fn unpack(X: u32) -> vec2 { return (clamp( vec2(f32(X % 65535u), f32(X / 65535u)) / 65534.0, vec2(0.), vec2(1.) ) * 2.0 - 1.0 ) ; } fn pack(v: vec2) -> u32 { return ( u32(round(65534.0*clamp(0.5*v.x+0.5, 0., 1.))) + 65535u*u32(round(65534.0*clamp(0.5*v.y+0.5, 0., 1.))) ) ; } fn sdBox( p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn border(p: vec2, R: vec2) -> f32 { let bound: f32 = -sdBox(p - R * 0.5, R * vec2(0.49, 0.49)); let box: f32 = sdBox(p - R * vec2(0.5, 0.6), R * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R * vec2(0.5, 0.7), R * vec2(0., 0.)); return bound; } let h = 1.; fn bN(p: vec2, R: vec2) -> vec3 { let dx: vec3 = vec3(-h, 0., h); let idx: vec4 = vec4(-1. / h, 0., 1. / h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy, R) + idx.xyw * border(p + dx.xy, R) + idx.yzw * border(p + dx.yz, R) + idx.yxw * border(p + dx.yx, R); return vec3(normalize(r.xy), r.z + 0.0001); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { // } // fn mainImage( U: vec4, pos: vec2) { let R = uni.iResolution.xy; let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let pos = location; let p: vec2 = vec2(pos); let data: vec4 = textureLoad(buffer_a, pos % vec2( R)); // let data: vec4 = textureLoad(buffer_a, pos ); // var X: vec2 = DECODE(data.x) + pos; // var V: vec2 = DECODE(data.y); var X: vec2 = unpack(u32(data.x)) + vec2(pos); var V: vec2 = unpack(u32(data.y)); let M: f32 = data.z; if (M != 0.) { var Fa: vec2 = vec2(0.); for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(i, j); // let data: vec4 = T(tpos); let data: vec4 = textureLoad(buffer_a, (tpos % vec2( R))); // let data: vec4 = textureLoad(buffer_a, (tpos )); // texelFetch(iChannel0, ivec2(mod(p,R)), 0) // let X0: vec2 = DECODE(data.x) + tpos; // let V0: vec2 = DECODE(data.y); var X0: vec2 = unpack(u32(data.x)) + vec2(tpos); var V0: vec2 = unpack(u32(data.y)); let M0: f32 = data.z; let dx: vec2 = X0 - X; Fa = Fa + (M0 * MF(dx) * dx); } } var F: vec2 = vec2(0.); if (uni.iMouse.z > 0.) { let dx: vec2 = vec2(pos) - uni.iMouse.xy; F = F - (0.003 * dx * GS(dx / 30.)); } F = F + (0.001 * vec2(0., -1.0)); V = V + ((F + Fa) * dt / M); X = X + (cooling * Fa * dt / M); let BORD: vec3 = bN(X, R); V = V + (0.5 * smoothStep(0., 5., -BORD.z) * BORD.xy); let v: f32 = length(V); var denom: f32 = 1.0; if (v > 1.) { denom = 1. * v; } V = V / denom; // V = V / (v > 1. ? 1. * v : 1.); } X = X - vec2(pos); // U = vec4(ENCODE(X), ENCODE(V), M, 0.); let eX = f32(pack(X)); let eV = f32(pack(V)); let U = vec4(eX, eV, M, 0.); textureStore(buffer_b, location, U); } ================================================ FILE: assets/shaders/molecular_dynamics/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // #define T(p) texelFetch(iChannel0, ivec2(mod(p,R)), 0) // #define P(p) texture(iChannel0, mod(p,R)/R) // #define C(p) texture(iChannel1, mod(p,R)/R) // #define GS(x) exp(-dot(x,x)) // #define GS0(x) exp(-length(x)) // #define CI(x) smoothstep(1.0, 0.9, length(x)) // #define Dir(ang) vec2(cos(ang), sin(ang)) // #define Rot(ang) mat2(cos(ang), sin(ang), -sin(ang), cos(ang)) // #define PACK(X) ( uint(round(65534.0*clamp(0.5*X.x+0.5, 0., 1.))) + \ // 65535u*uint(round(65534.0*clamp(0.5*X.y+0.5, 0., 1.))) ) // #define UNPACK(X) (clamp(vec2(X%65535u, X/65535u)/65534.0, 0.,1.)*2.0 - 1.0) // #define DECODE(X) UNPACK(floatBitsToUint(X)) // #define ENCODE(X) uintBitsToFloat(PACK(X)) let PI = 3.14159265; let dt = 0.4; // let R = uni.iResolution.xy; let cooling = 1.5; fn GS(x1: vec2) -> f32 { return exp(-dot(x1, x1)); } fn MF(dx: vec2) -> f32 { return -GS(0.75 * dx) + 0.15 * GS(0.4 * dx); } fn Ha(x: vec2) -> f32 { var x2: f32; if (x.x >= 0.) { x2 = 1.; } else { x2 = 0.0; } if (x.y >= 0.) { x2 = x2; } else { x2 = 0.0; } // return (x.x >= 0. ? 1. : 0.) * (x.y >= 0. ? 1. : 0.); return x2; } fn Hb(x: vec2) -> f32 { // return (x.x > 0. ? 1. : 0.) * (x.y > 0. ? 1. : 0.); var x2: f32; if (x.x > 0.) { x2 = 1.; } else { x2 = 0.0; } if (x.y > 0.) { x2 = x2; } else { x2 = 0.0; } return x2; } fn unpack(X: u32) -> vec2 { return (clamp( vec2(f32(X % 65535u), f32(X / 65535u)) / 65534.0, vec2(0.), vec2(1.) ) * 2.0 - 1.0 ) ; } fn pack(v: vec2) -> u32 { return ( u32(round(65534.0*clamp(0.5*v.x+0.5, 0., 1.))) + 65535u*u32(round(65534.0*clamp(0.5*v.y+0.5, 0., 1.))) ) ; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/molecular_dynamics/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // #define T(p) texelFetch(iChannel0, ivec2(mod(p,R)), 0) // #define P(p) texture(iChannel0, mod(p,R)/R) // #define C(p) texture(iChannel1, mod(p,R)/R) // #define GS(x) exp(-dot(x,x)) // #define GS0(x) exp(-length(x)) // #define CI(x) smoothstep(1.0, 0.9, length(x)) // #define Dir(ang) vec2(cos(ang), sin(ang)) // #define Rot(ang) mat2(cos(ang), sin(ang), -sin(ang), cos(ang)) // #define PACK(X) ( uint(round(65534.0*clamp(0.5*X.x+0.5, 0., 1.))) + \ // 65535u*uint(round(65534.0*clamp(0.5*X.y+0.5, 0., 1.))) ) // #define UNPACK(X) (clamp(vec2(X%65535u, X/65535u)/65534.0, 0.,1.)*2.0 - 1.0) // #define DECODE(X) UNPACK(floatBitsToUint(X)) // #define ENCODE(X) uintBitsToFloat(PACK(X)) let PI = 3.14159265; let dt = 0.4; // let R = uni.iResolution.xy; let cooling = 1.5; fn GS(x1: vec2) -> f32 { return exp(-dot(x1, x1)); } fn MF(dx: vec2) -> f32 { return -GS(0.75 * dx) + 0.15 * GS(0.4 * dx); } fn Ha(x: vec2) -> f32 { var x2: f32; if (x.x >= 0.) { x2 = 1.; } else { x2 = 0.0; } if (x.y >= 0.) { x2 = x2; } else { x2 = 0.0; } // return (x.x >= 0. ? 1. : 0.) * (x.y >= 0. ? 1. : 0.); return x2; } fn Hb(x: vec2) -> f32 { // return (x.x > 0. ? 1. : 0.) * (x.y > 0. ? 1. : 0.); var x2: f32; if (x.x > 0.) { x2 = 1.; } else { x2 = 0.0; } if (x.y > 0.) { x2 = x2; } else { x2 = 0.0; } return x2; } fn unpack(X: u32) -> vec2 { return (clamp( vec2(f32(X % 65535u), f32(X / 65535u)) / 65534.0, vec2(0.), vec2(1.) ) * 2.0 - 1.0 ) ; } fn pack(v: vec2) -> u32 { return ( u32(round(65534.0*clamp(0.5*v.x+0.5, 0., 1.))) + 65535u*u32(round(65534.0*clamp(0.5*v.y+0.5, 0., 1.))) ) ; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/molecular_dynamics/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // [[group(0), binding(1)]] // var buffer_a: texture_storage_2d; // [[group(0), binding(2)]] // var buffer_b: texture_storage_2d; // [[group(0), binding(3)]] // var buffer_c: texture_storage_2d; // [[group(0), binding(4)]] // var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; [[group(0), binding(6)]] var font_texture: texture_2d; [[group(0), binding(7)]] var font_texture_sampler: sampler; [[group(0), binding(8)]] var rgba_noise_256_texture: texture_2d; [[group(0), binding(9)]] var rgba_noise_256_texture_sampler: sampler; // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // let color = vec4(f32(0)); // textureStore(texture, location, color); // } // #define T(p) texelFetch(iChannel0, ivec2(mod(p,R)), 0) // #define P(p) texture(iChannel0, mod(p,R)/R) // #define C(p) texture(iChannel1, mod(p,R)/R) // #define GS(x) exp(-dot(x,x)) // #define GS0(x) exp(-length(x)) // #define CI(x) smoothstep(1.0, 0.9, length(x)) // #define Dir(ang) vec2(cos(ang), sin(ang)) // #define Rot(ang) mat2(cos(ang), sin(ang), -sin(ang), cos(ang)) // #define PACK(X) ( uint(round(65534.0*clamp(0.5*X.x+0.5, 0., 1.))) + \ // 65535u*uint(round(65534.0*clamp(0.5*X.y+0.5, 0., 1.))) ) // #define UNPACK(X) (clamp(vec2(X%65535u, X/65535u)/65534.0, 0.,1.)*2.0 - 1.0) // #define DECODE(X) UNPACK(floatBitsToUint(X)) // #define ENCODE(X) uintBitsToFloat(PACK(X)) let PI = 3.14159265; let dt = 0.4; // let R = uni.iResolution.xy; let cooling = 1.5; fn GS(x1: vec2) -> f32 { return exp(-dot(x1, x1)); } fn MF(dx: vec2) -> f32 { return -GS(0.75 * dx) + 0.15 * GS(0.4 * dx); } fn Ha(x: vec2) -> f32 { var x2: f32; if (x.x >= 0.) { x2 = 1.; } else { x2 = 0.0; } if (x.y >= 0.) { x2 = x2; } else { x2 = 0.0; } // return (x.x >= 0. ? 1. : 0.) * (x.y >= 0. ? 1. : 0.); return x2; } fn Hb(x: vec2) -> f32 { // return (x.x > 0. ? 1. : 0.) * (x.y > 0. ? 1. : 0.); var x2: f32; if (x.x > 0.) { x2 = 1.; } else { x2 = 0.0; } if (x.y > 0.) { x2 = x2; } else { x2 = 0.0; } return x2; } fn unpack(X: u32) -> vec2 { return (clamp( vec2(f32(X % 65535u), f32(X / 65535u)) / 65534.0, vec2(0.), vec2(1.) ) * 2.0 - 1.0 ) ; } fn pack(v: vec2) -> u32 { return ( u32(round(65534.0*clamp(0.5*v.x+0.5, 0., 1.))) + 65535u*u32(round(65534.0*clamp(0.5*v.y+0.5, 0., 1.))) ) ; } // displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a // here // fn hsv2rgb( c: vec3) -> vec3 { // var rgb: vec3 = clamp(abs(mod(c.x * 6. + vec3(0., 4., 2.), 6.) - 3.) - 1., 0., 1.); // rgb = rgb * rgb * (3. - 2. * rgb); // return c.z * mix(vec3(1.), rgb, c.y); // } fn hsv2rgb( c: vec3) -> vec3 { var fractional: vec3 = vec3( 0.0); let m = modf(c.x * 6. + vec3(0., 4., 2.) / 6., &fractional); // let v = vec3(0., 4., 2.); // let fractional: vec3 = vec3(vec3( (c.x * 6. + v) / 6.0)) ; // let whatever = modf(uv + 1.0, &tempo); // var temp2 = 0.; // let frac = modf(tempo / 2.0, &temp2); let af: vec3 = abs(fractional - 3.) - 1.; var rgb: vec3 = clamp(af, vec3(0.), vec3(1.)); rgb = rgb * rgb * (3. - 2. * rgb); return c.z * mix(vec3(1.), rgb, c.y); } let radius = 1.0; let zoom = 0.3; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let R = uni.iResolution.xy; // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let pos = location; // var O: vec4 = textureLoad(buffer_a, location); // textureStore(texture, location, O); // } // fn mainImage( col: vec4, pos: vec2) -> () { var rho: f32 = 0.001; var vel: vec2 = vec2(0., 0.); for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(i, j); // let data: vec4 = texelFetch(buffer_b, ivec2(mod(tpos,R)), 0) let data: vec4 = textureLoad(buffer_b, (tpos % vec2( R))); var X0: vec2 = unpack(u32(data.x)) + vec2(tpos); var V0: vec2 = unpack(u32(data.y)); let M0: f32 = data.z; let dx: vec2 = X0 - vec2(pos); let K: f32 = GS ((dx / radius)) / (radius * radius); rho = rho + (M0 * K); vel = vel + (M0 * K * V0); } } vel = vel / (rho); let vc: vec3 = hsv2rgb( vec3( 6. * atan2(vel.x, vel.y) / (2. * PI), 1., rho * length(vel.xy) ) ); let col: vec3 = cos(0.9 * vec3(3., 2., 1.) * rho) + 0. * vc; let U = vec4(col, 1.); textureStore(texture, y_inverted_location, U); } ================================================ FILE: assets/shaders/paint/buffer_a.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; fn hue(v: f32) -> vec4 { return (vec4(.6) + vec4(.6) * cos(vec4(6.3 * v) + vec4(0.0, 23.0, 21.0, 0.0))); } fn smoothit(v: f32) -> f32 { return smoothstep(1.5, 0., v); } fn sdSegment(p: vec2, a: vec2, b: vec2) -> f32 { let pa = p - a; let ba = b - a; let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.); return length(pa - ba * h); } fn sdRhombus(p: vec2, b: vec2) -> f32 { let q = abs(p); let qb = dot(q, vec2(b.x, -b.y)); let bb = dot(b, vec2(b.x, -b.y)); let h = clamp((-2. * qb + bb) / dot(b, b), -1., 1.); let d = length(q - 0.5 * b * vec2(1. - h, 1. + h)); return d * sign(q.x * b.y + q.y * b.x - b.x * b.y); } fn sdTriangleIsosceles(p: vec2, c: vec2) -> f32 { let q = vec2(abs(p.x), p.y); let a = q - c * clamp(dot(q, c) / dot(c, c), 0., 1.); let b = q - c * vec2(clamp(q.x / c.x, 0., 1.), 1.); let s = -sign(c.y); let d = min(vec2(dot(a, a), s * (q.x * c.y - q.y * c.x)), vec2(dot(b, b), s * (q.y - c.y))); return -sqrt(d.x) * sign(d.y); } fn sdStar(p: vec2, r: f32, n: u32, m: f32) -> f32 { let an = 3.141593 / f32(n); let en = 3.141593 / m; let acs = vec2(cos(an), sin(an)); let ecs = vec2(cos(en), sin(en)); let bn = (atan2(abs(p.x), p.y) % (2. * an)) - an; var q: vec2 = length(p) * vec2(cos(bn), abs(sin(bn))); q = q - r * acs; q = q + ecs * clamp(-dot(q, ecs), 0., r * acs.y / ecs.y); return length(q) * sign(q.x); } fn sdHeart(p: vec2) -> f32 { let q = vec2(abs(p.x), p.y); let w = q - vec2(0.25, 0.75); if (q.x + q.y > 1.0) { return sqrt(dot(w, w)) - sqrt(2.) / 4.; } let u = q - vec2(0., 1.0); let v = q - 0.5 * max(q.x + q.y, 0.); return sqrt(min(dot(u, u), dot(v, v))) * sign(q.x - q.y); } fn sdMoon(p: vec2, d: f32, ra: f32, rb: f32) -> f32 { let q = vec2(p.x, abs(p.y)); let a = (ra * ra - rb * rb + d * d) / (2. * d); let b = sqrt(max(ra * ra - a * a, 0.)); if (d * (q.x * b - q.y * a) > d * d * max(b - q.y, 0.)) { return length(q - vec2(a, b)); } return max((length(q) - ra), -(length(q - vec2(d, 0.)) - rb)); } fn sdCross(p: vec2, b: vec2) -> f32 { var q: vec2 = abs(p); q = select(q.xy, q.yx, q.y > q.x); let t = q - b; let k = max(t.y, t.x); let w = select(vec2(b.y - q.x, -k), t, k > 0.); return sign(k) * length(max(w, vec2(0.))); } fn sdRoundedX(p: vec2, w: f32, r: f32) -> f32 { let q = abs(p); return length(q - min(q.x + q.y, w) * 0.5) - r; } fn sdCircle(p: vec2, c: vec2, r: f32) -> f32 { let d = length(p - c); return d - r; } // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // # ifdef INIT // if (location.x == 0 && location.y == 0 ) { // textureStore(buffer_a, location, hue(4.0 / 8.0)); // } else { // // set brush color to black // let black = vec4(0.0, 0.0, 0.0, 1.0); // textureStore(buffer_a, location, black); // } // # endif // } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); // on the very first frame, INIT is defined. Otherwise, it is not. #ifdef INIT if (location.x == 0 && location.y == 0) { textureStore(buffer_a, location, hue(4.0 / 8.0)); } else { // set brush color to black let black = vec4(0.0, 0.0, 0.0, 1.0); textureStore(buffer_a, location, black); } #endif // } let U: vec2 = vec2(location) / R; let M: vec2 = vec2(uni.iMouse.x, uni.iMouse.y) / R ; var O: vec4 = textureLoad(buffer_a, location); if (location.x == 0 && location.y == 0) { if (M.x < 0.1 && uni.iMouse.w > 0.0) { // just pressed left mouse button let y: f32 = floor(9. * M.y); O = hue(y / 8.); textureStore(buffer_a, location, O); } return; } // display palette on left if (U.x < 0.1) { let y: f32 = floor(9. * U.y); O = hue(y / 8.); O.w = 1.; textureStore(buffer_a, location, O); return; } let brush_color = textureLoad(buffer_a, vec2(0, 0)); // apply paint if (uni.iMouse.z > 1.0) { let mouse_pix = vec2(uni.iMouse.x, uni.iMouse.y); let brush_sdf = sdCircle(vec2(location), mouse_pix, 10.0); let brush_d = smoothstep(0.0, 5.0, brush_sdf); let brush_intensity = 0.1; O = mix(O, brush_color, (1.0 - brush_d) * brush_intensity); } let inverted_y = vec2(location.x, location.y); textureStore(buffer_a, location, O); } ================================================ FILE: assets/shaders/paint/buffer_b.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/paint/buffer_c.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/paint/buffer_d.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/paint/common.wgsl ================================================ // unused #define_import_path bevy_shadertoy_wgsl::assets::shaders::common struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; ================================================ FILE: assets/shaders/paint/image.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @group(0) @binding(5) var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; @group(0) @binding(6) var font_texture: texture_2d; @group(0) @binding(7) var font_texture_sampler: sampler; @group(0) @binding(8) var rgba_noise_256_texture: texture_2d; @group(0) @binding(9) var rgba_noise_256_texture_sampler: sampler; @group(0) @binding(10) var blue_noise_texture: texture_2d; @group(0) @binding(11) var blue_noise_texture_sampler: sampler; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location2 = vec2(i32(R.x) - i32(invocation_id.x), i32(invocation_id.y)); var alive = true; var q: f32; if (true) { q = 1.; } else { q = 4.; }; var O: vec4 = mix(textureLoad(buffer_a, location),vec4(0.5), 0.1); // var O: vec4 = vec4(0.5); textureStore(texture, y_inverted_location, O); } ================================================ FILE: assets/shaders/paint2/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; type float2 = vec2; type float4 = vec4; fn hue(v: f32) -> vec4 { return (vec4(.6) + vec4(.6) * cos( vec4(6.3 * v) + vec4(0.0,23.0,21.0,0.0 ) )); } fn smoothit(v: f32) -> f32{ return smoothStep( 1.5, 0., v ); } fn sdSegment(p: vec2, a: vec2, b: vec2) -> f32 { let pa = p - a; let ba = b - a; let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.); return length(pa - ba * h); } fn sdRhombus(p: vec2, b: vec2) -> f32 { let q = abs(p); let qb = dot(q, vec2(b.x, -b.y)); let bb = dot(b, vec2(b.x, -b.y)); let h = clamp((-2. * qb + bb) / dot(b, b), -1., 1.); let d = length(q - 0.5 * b * vec2(1. - h, 1. + h)); return d * sign(q.x * b.y + q.y * b.x - b.x * b.y); } fn sdTriangleIsosceles(p: vec2, c: vec2) -> f32 { let q = vec2(abs(p.x), p.y); let a = q - c * clamp(dot(q, c) / dot(c, c), 0., 1.); let b = q - c * vec2(clamp(q.x / c.x, 0., 1.), 1.); let s = -sign(c.y); let d = min(vec2(dot(a, a), s * (q.x * c.y - q.y * c.x)), vec2(dot(b, b), s * (q.y - c.y))); return -sqrt(d.x) * sign(d.y); } fn sdStar(p: vec2, r: f32, n: u32, m: f32) ->f32 { let an = 3.141593 / f32(n); let en = 3.141593 / m; let acs = vec2(cos(an), sin(an)); let ecs = vec2(cos(en), sin(en)); let bn = (atan2(abs(p.x), p.y) % (2. * an)) - an; var q: vec2 = length(p) * vec2(cos(bn), abs(sin(bn))); q = q - r * acs; q = q + ecs * clamp(-dot(q, ecs), 0., r * acs.y / ecs.y); return length(q) * sign(q.x); } fn sdHeart(p: vec2) -> f32 { let q = vec2(abs(p.x), p.y); let w = q - vec2(0.25, 0.75); if (q.x + q.y > 1.0) { return sqrt(dot(w, w)) - sqrt(2.) / 4.; } let u = q - vec2(0., 1.0); let v = q - 0.5 * max(q.x + q.y, 0.); return sqrt(min(dot(u, u), dot(v, v))) * sign(q.x - q.y); } fn sdMoon(p: vec2, d: f32, ra: f32, rb: f32) -> f32 { let q = vec2(p.x, abs(p.y)); let a = (ra * ra - rb * rb + d * d) / (2. * d); let b = sqrt(max(ra * ra - a * a, 0.)); if (d * (q.x * b - q.y * a) > d * d * max(b - q.y, 0.)) { return length(q-vec2(a, b)); } return max((length(q) - ra), -(length(q - vec2(d, 0.)) - rb)); } fn sdCross(p: vec2, b: vec2) -> f32 { var q: vec2 = abs(p); q = select(q.xy, q.yx, q.y > q.x); let t = q - b; let k = max(t.y, t.x); let w = select(vec2(b.y - q.x, -k), t, k > 0.); return sign(k) * length(max(w, vec2(0.))); } fn sdRoundedX(p: vec2, w: f32, r: f32) -> f32 { let q = abs(p); return length(q - min(q.x + q.y, w) * 0.5) - r; } fn sdCircle(p: vec2, c: vec2, r: f32) -> f32 { let d = length(p - c); return d - r; } // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // # ifdef INIT // if (location.x == 0 && location.y == 0 ) { // textureStore(buffer_a, location, hue(4.0 / 8.0)); // } else { // // set brush color to black // let black = vec4(0.0, 0.0, 0.0, 1.0); // textureStore(buffer_a, location, black); // } // # endif // } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // the first three frames are not directed inside the update function. // The first time this function is called is on frame 4. if (i32(uni.iFrame) == 3) { // # ifdef INIT if (location.x == 0 && location.y == 0 ) { textureStore(buffer_a, location, hue(4.0 / 8.0)); } else { // set brush color to black let black = vec4(0.0, 0.0, 0.0, 1.0); textureStore(buffer_a, location, black); } // # endif } let R: float2 = uni.iResolution.xy; let U: vec2 = vec2(location) / R; let M: float2 = vec2(uni.iMouse.x, 1.0-uni.iMouse.y); var O: float4 = textureLoad(buffer_a, location); if (location.x == 0 && location.y == 0 ) { if ( uni.iMouse.x < 0.1 && uni.iMouse.w == 1.0) { // just pressed left mouse button let y: f32 = floor(9.*M.y); O = hue( y/8. ); textureStore(buffer_a, location, O); } return; } // display palette on left if ( U.x < 0.1 ) { let y: f32 = floor(9.*U.y); O = hue( y/8. ); O.w = 1.; textureStore(buffer_a, location, O); return; } // let brush_color = float4(1., 0., 0., 1.); let brush_color = textureLoad(buffer_a, vec2(0,0)); // apply paint if (uni.iMouse.z == 1.0) { let mouse_pix = vec2(uni.iMouse.x * R.x, (1.0 - uni.iMouse.y) * R.y ); let brush_sdf = sdCircle(vec2(location), mouse_pix, 10.0); let brush_d = smoothStep(0.0, 5.0, brush_sdf); O = mix(O, brush_color, (1.0-brush_d) * 0.01); } textureStore(buffer_a, location, O); } ================================================ FILE: assets/shaders/paint2/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/paint2/buffer_c.wgsl ================================================ [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/paint2/buffer_d.wgsl ================================================ [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/paint2/common.wgsl ================================================ // unused #define_import_path bevy_shadertoy_wgsl::assets::shaders::common struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; ================================================ FILE: assets/shaders/paint2/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // let color = vec4(f32(0)); // textureStore(texture, location, color); // } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var alive = true; var O: vec4 = textureLoad(buffer_a, location); textureStore(texture, location, O); } ================================================ FILE: assets/shaders/paint2/image2.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: i32; iSampleRate: i32; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; iResolution: vec2; iMouse: vec2; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(f32(0)); textureStore(texture, location, color); } fn hash(value: u32) -> u32 { var state = value; state = state ^ 2747636419u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; return state; } fn randomFloat(value: u32) -> f32 { return f32(hash(value)) / 4294967295.0; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var alive = true; var O: vec4 = textureLoad(buffer_a, location); // let color = vec4(O.x, 0.1, 0.12, 1.0); // storageBarrier(); // textureStore(texture, location, vec4(color)); textureStore(texture, location, O); } ================================================ FILE: assets/shaders/paint_streams/buffer_a.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; let PI = 3.14159265; let dt = 2.5; let border_h = 5.; let h = 1.; let mass = 1.; let fluid_rho = 0.5; // let dif = 1.12; var R: vec2; var Mouse: vec4; var time: f32; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; // return length(max(d, 0.)) + min(max(d.x, d.y), 0.); return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } // uint pack(vec2 x) // { // x = 65534.0*clamp(0.5*x+0.5, 0., 1.); // return uint(round(x.x)) + 65535u*uint(round(x.y)); // } // fn unpack(a: u32) -> vec2 { // var x: vec2 = vec2(f32(a) % 65535., f32(a) / 65535.); // return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; // } // vec2 unpack(uint a) // { // vec2 x = vec2(a % 65535u, a / 65535u); // return clamp(x/65534.0, 0.,1.)*2.0 - 1.0; // } // fn decode(x: f32) -> vec2 { // var X: u32 = floatBitsToUint(x); // return unpack(X); // } // fn encode(x: vec2) -> f32 { // var X: u32 = pack(x); // return uintBitsToFloat(X); // } // fn decode(&self, place: u8, precis: u8) -> f32 { // let value_u32 = self >> (place - precis); // let mut mask = u32::MAX; // if precis < 32 { // mask = (1 << (precis)) - 1; // } // // println!("mask: {:#0b}", value_u32); // let masked_value_u32 = value_u32 & mask; // let value_f32 = masked_value_u32 as f32 / ((1u32 << (precis - 1u8)) as f32); // value_f32 // } fn pack(xIn: vec2) -> u32 { var x = xIn; let x = 65534. * clamp(0.5 * x + 0.5, vec2(0.00), vec2(1.0)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } fn decode2(input: u32, place: u32, precis: u32) -> f32 { let value_u32 = input >> (place - precis); var mask: u32 = 4294967295u; if (precis < 32u) { mask = (1u << precis) - 1u; } let masked_value_u32 = value_u32 & mask; let max_val = 1u << (precis - 1u); let value_f32 = f32(masked_value_u32) / f32(max_val) ; return value_f32; } fn decode1uToVec2(q: f32) -> vec2 { let uq = u32(q); let x = decode2(uq, 32u, 16u); let y = decode2(uq, 16u, 16u); return vec2(x, y) * 2. - 1.; } fn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 { var input = input2; // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ; let value_f32_normalized = value * f32((1u << (precis - 1u))); let delta_bits = u32(place - precis); let value_u32 = u32(value_f32_normalized) << delta_bits; var mask: u32 = 0u; if (precis < 32u) { mask = 4294967295u - (((1u << precis) - 1u) << (place - precis)); } let input = (input2 & mask) | value_u32; return input; } fn encodeVec2To1u(value: vec2) -> u32 { var input: u32 = 0u; let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0)); let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0)); input = encode2(x, input, 32u, 16u); input = encode2(y, input, 16u, 16u); return input; } struct particle { X: vec2, V: vec2, M: vec2, }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle; P.X = decode1uToVec2(data.x) + pos; P.V = decode1uToVec2(data.y); P.M = data.zw; return P; } fn saveParticle(PIn: particle, pos: vec2) -> vec4 { var P: particle = PIn; P.X = clamp(P.X - pos, vec2(-0.5), vec2(0.5)); return vec4( f32(encodeVec2To1u(P.X)), f32(encodeVec2To1u(P.V)), P.M ); } // fn getParticle(data: vec4, pos: vec2) -> particle { // var P: particle = particle( // decode(data.x) + pos, // decode(data.y), // data.zw // ); // return P; // } // fn saveParticle(P: particle, pos: vec2) -> vec4 { // var P2: particle = particle(P.X, P.V, P.M); // P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); // return vec4(encode(P2.X), encode(P2.V), P2.M); // } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(0.1031, 0.103, 0.0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } // struct particle { // X: vec2, // V: vec2, // M: vec2, // }; // fn fromLinear(linearRGB: vec4) -> vec4 { // let cutoff: vec4 = vec4(linearRGB < vec4(0.0031308)); // let higher: vec4 = vec4(1.055) * pow(linearRGB, vec4(1.0 / 2.4)) - vec4(0.055); // let lower: vec4 = linearRGB * vec4(12.92); // return mix(higher, lower, cutoff); // } // Converts a color from sRGB gamma to linear light gamma fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } fn Reintegration(ch: texture_storage_2d, pos: vec2) -> particle { var P: particle = particle(vec2(0.0), vec2(0.0), vec2(0.0)); for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(j)); let data: vec4 = textureLoad(ch, vec2(tpos)); var P0: particle = getParticle(data, tpos); P0.X = P0.X + (P0.V * dt); //integrate position let difR: f32 = 0.9 + 0.21 * smoothstep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x); let D: vec3 = distribution(P0.X, pos, difR); let m: f32 = P0.M.x * D.z; P.X = P.X + (D.xy * m); P.V = P.V + (P0.V * m); P.M.y = P.M.y + (P0.M.y * m); P.M.x = P.M.x + (m); } } if (P.M.x > 0.0000001) { P.X = P.X / (P.M.x); P.V = P.V / (P.M.x); P.M.y = P.M.y / (P.M.x); } return P; } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; // let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var U: vec4; var pos = vec2(f32(location.x), f32(location.y)); // R = uni.iResolution.xy; // time = uni.iTime; // Mouse = uni.iMouse; // let p: vec2 = vec2(pos); // let data: vec4 = texel(ch0, pos); // var P: particle; var P: particle = Reintegration(buffer_b, pos); // if (uni.iFrame < 1) { #ifdef INIT let rand: vec3 = hash32(pos); if (rand.z < 0.) { P.X = pos; P.V = 0.5 * (rand.xy - 0.5) + vec2(0., 0.); P.M = vec2(mass, 0.); } else { P.X = pos; P.V = vec2(0.); P.M = vec2(0.000001); } #endif // } U = saveParticle(P, pos); // U = clamp(U, vec4(0.), vec4(1.)); textureStore(buffer_a, location, U); } ================================================ FILE: assets/shaders/paint_streams/buffer_b.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; let PI = 3.14159265; let dt = 2.5; let border_h = 5.; let h = 1.; let mass = 1.; let fluid_rho = 0.5; // let dif = 1.12; var R: vec2; var Mouse: vec4; var time: f32; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; // return length(max(d, 0.)) + min(max(d.x, d.y), 0.); return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } // uint pack(vec2 x) // { // x = 65534.0*clamp(0.5*x+0.5, 0., 1.); // return uint(round(x.x)) + 65535u*uint(round(x.y)); // } // fn unpack(a: u32) -> vec2 { // var x: vec2 = vec2(f32(a) % 65535., f32(a) / 65535.); // return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; // } // vec2 unpack(uint a) // { // vec2 x = vec2(a % 65535u, a / 65535u); // return clamp(x/65534.0, 0.,1.)*2.0 - 1.0; // } // fn decode(x: f32) -> vec2 { // var X: u32 = floatBitsToUint(x); // return unpack(X); // } // fn encode(x: vec2) -> f32 { // var X: u32 = pack(x); // return uintBitsToFloat(X); // } // fn decode(&self, place: u8, precis: u8) -> f32 { // let value_u32 = self >> (place - precis); // let mut mask = u32::MAX; // if precis < 32 { // mask = (1 << (precis)) - 1; // } // // println!("mask: {:#0b}", value_u32); // let masked_value_u32 = value_u32 & mask; // let value_f32 = masked_value_u32 as f32 / ((1u32 << (precis - 1u8)) as f32); // value_f32 // } fn pack(xIn: vec2) -> u32 { var x = xIn; let x = 65534. * clamp(0.5 * x + 0.5, vec2(0.00), vec2(1.0)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } fn decode2(input: u32, place: u32, precis: u32) -> f32 { let value_u32 = input >> (place - precis); var mask: u32 = 4294967295u; if (precis < 32u) { mask = (1u << precis) - 1u; } let masked_value_u32 = value_u32 & mask; let max_val = 1u << (precis - 1u); let value_f32 = f32(masked_value_u32) / f32(max_val) ; return value_f32; } fn decode1uToVec2(q: f32) -> vec2 { let uq = u32(q); let x = decode2(uq, 32u, 16u); let y = decode2(uq, 16u, 16u); return vec2(x, y) * 2. - 1.; } fn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 { var input = input2; // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ; let value_f32_normalized = value * f32((1u << (precis - 1u))); let delta_bits = u32(place - precis); let value_u32 = u32(value_f32_normalized) << delta_bits; var mask: u32 = 0u; if (precis < 32u) { mask = 4294967295u - (((1u << precis) - 1u) << (place - precis)); } let input = (input2 & mask) | value_u32; return input; } fn encodeVec2To1u(value: vec2) -> u32 { var input: u32 = 0u; let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0)); let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0)); input = encode2(x, input, 32u, 16u); input = encode2(y, input, 16u, 16u); return input; } struct particle { X: vec2, V: vec2, M: vec2, }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle; P.X = decode1uToVec2(data.x) + pos; P.V = decode1uToVec2(data.y); P.M = data.zw; return P; } fn saveParticle(PIn: particle, pos: vec2) -> vec4 { var P: particle = PIn; P.X = clamp(P.X - pos, vec2(-0.5), vec2(0.5)); return vec4( f32(encodeVec2To1u(P.X)), f32(encodeVec2To1u(P.V)), P.M ); } // fn getParticle(data: vec4, pos: vec2) -> particle { // var P: particle = particle( // decode(data.x) + pos, // decode(data.y), // data.zw // ); // return P; // } // fn saveParticle(P: particle, pos: vec2) -> vec4 { // var P2: particle = particle(P.X, P.V, P.M); // P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); // return vec4(encode(P2.X), encode(P2.V), P2.M); // } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(0.1031, 0.103, 0.0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } // struct particle { // X: vec2, // V: vec2, // M: vec2, // }; // fn fromLinear(linearRGB: vec4) -> vec4 { // let cutoff: vec4 = vec4(linearRGB < vec4(0.0031308)); // let higher: vec4 = vec4(1.055) * pow(linearRGB, vec4(1.0 / 2.4)) - vec4(0.055); // let lower: vec4 = linearRGB * vec4(12.92); // return mix(higher, lower, cutoff); // } // Converts a color from sRGB gamma to linear light gamma fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } fn border(p: vec2, R2: vec2) -> f32 { let bound: f32 = -sdBox(p - R2 * 0.5, R2 * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time) * (p - R2 * vec2(0.5, 0.6)), R2 * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R2 * vec2(0.5, 0.7), R2 * vec2(1.5, 0.5)); return max(drain, min(bound, box)); } fn bN(p: vec2, R2: vec2) -> vec3 { let dx: vec3 = vec3(-h, 0., h); let idx: vec4 = vec4(-1. / h, 0., 1. / h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy, R2) + idx.xyw * border(p + dx.xy, R2) + idx.yzw * border(p + dx.yz, R2) + idx.yxw * border(p + dx.yx, R2); return vec3(normalize(r.xy), r.z + 1.0e-4); } fn Simulation( ch: texture_storage_2d, P: ptr, pos: vec2) { var F: vec2 = vec2(0.); var avgV: vec3 = vec3(0.,); // var P = *PIn; for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(j)); // let data: vec4 = texelFetch(ch, Bi(tpos), 0.); let data: vec4 = textureLoad(ch, vec2(tpos)) ; var P0: particle = getParticle(data, tpos); let dx: vec2 = P0.X - (*P).X; let avgP: f32 = 0.5 * P0.M.x * (Pf((*P).M) + Pf(P0.M)); F = F - (0.5 * G(1. * dx) * avgP * dx); avgV = avgV + (P0.M.x * G(1. * dx) * vec3(P0.V.x, P0.V.y, 1.)); } } var avgVxy = avgV.xy; avgVxy = avgV.xy / (avgV.z); avgV.x = avgVxy.x; avgV.y = avgVxy.y; F = F + (0. * (*P).M.x * (avgV.xy - (*P).V)); F = F + ((*P).M.x * vec2(0., -0.0004)); if (Mouse.z > 0.) { let dm: vec2 = (Mouse.xy - Mouse.zw ) / 10.; let d: f32 = distance(Mouse.xy, (*P).X) / 20.; F = F + (0.001 * dm * exp(-d * d)); // let Part = particle(vec2(0.), vec2(0.), vec2(0.)); // return Part; } (*P).V = (*P).V + (F * dt / (*P).M.x); let N: vec3 = bN((*P).X, R); let vdotN: f32 = step(N.z, border_h) * dot(-N.xy, (*P).V); (*P).V = (*P).V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN))); (*P).V = (*P).V + (0. * (*P).M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z)); if (N.z < 0.) { (*P).V = vec2(0.); } let v: f32 = length((*P).V); var dum: f32; if (v > 1.) { dum = v; } else { dum = 1.; } (*P).V = (*P).V / dum; // return P; } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { R = uni.iResolution.xy; // let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var U: vec4; var pos = vec2(f32(location.x), f32(location.y)); // R = uni.iResolution.xy; time = uni.iTime; Mouse = uni.iMouse; let p: vec2 = vec2(pos); // let data: vec4 = texel(ch0, pos); let data: vec4 = textureLoad(buffer_a, location); var P: particle = getParticle(data, pos); if (P.M.x != 0.) { Simulation(buffer_a, &P, pos); } let timeMult = 1.0; if (length(P.X - R * vec2(0.55, 0.9)) < 20.) { P.X = pos; P.V = 0.5 * Dir(-PI * 0.75 + 0.3 * sin(0.4 * 2.0 * timeMult)); P.M = mix(P.M, vec2(fluid_rho, 1.), 0.4); } if (length(P.X - R * vec2(0.45, 0.9)) < 20.) { // P.X = pos; // P.V = 0.5 * Dir(-PI * 0.25 + 0.3 * sin(0.3 * timeMult)); // P.M = mix(P.M, vec2(fluid_rho, 0.), 0.4); P.X = pos; P.V = 0.5 * Dir(PI * 0.25 - PI * 0.5 + 0.3 * sin(0.4 * 2.0 * timeMult)); P.M = mix(P.M, vec2(fluid_rho, 0.5), 0.4); } U = saveParticle(P, pos); // U = clamp(U, vec4(-1000000.), vec4(100000.)); // U.y = clamp(U.y, -1000000., 100000.); textureStore(buffer_b, location, U); // let b = vec4(.5, 0.2, 0.1, 1.0) * -10000.0; // textureStore(buffer_b, location, b); } ================================================ FILE: assets/shaders/paint_streams/buffer_c.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; let PI = 3.14159265; let dt = 2.5; let border_h = 5.; let h = 1.; let mass = 1.; let fluid_rho = 0.5; // let dif = 1.12; var R: vec2; var Mouse: vec4; var time: f32; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; // return length(max(d, 0.)) + min(max(d.x, d.y), 0.); return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } // uint pack(vec2 x) // { // x = 65534.0*clamp(0.5*x+0.5, 0., 1.); // return uint(round(x.x)) + 65535u*uint(round(x.y)); // } // fn unpack(a: u32) -> vec2 { // var x: vec2 = vec2(f32(a) % 65535., f32(a) / 65535.); // return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; // } // vec2 unpack(uint a) // { // vec2 x = vec2(a % 65535u, a / 65535u); // return clamp(x/65534.0, 0.,1.)*2.0 - 1.0; // } // fn decode(x: f32) -> vec2 { // var X: u32 = floatBitsToUint(x); // return unpack(X); // } // fn encode(x: vec2) -> f32 { // var X: u32 = pack(x); // return uintBitsToFloat(X); // } // fn decode(&self, place: u8, precis: u8) -> f32 { // let value_u32 = self >> (place - precis); // let mut mask = u32::MAX; // if precis < 32 { // mask = (1 << (precis)) - 1; // } // // println!("mask: {:#0b}", value_u32); // let masked_value_u32 = value_u32 & mask; // let value_f32 = masked_value_u32 as f32 / ((1u32 << (precis - 1u8)) as f32); // value_f32 // } fn pack(xIn: vec2) -> u32 { var x = xIn; let x = 65534. * clamp(0.5 * x + 0.5, vec2(0.00), vec2(1.0)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } fn decode2(input: u32, place: u32, precis: u32) -> f32 { let value_u32 = input >> (place - precis); var mask: u32 = 4294967295u; if (precis < 32u) { mask = (1u << precis) - 1u; } let masked_value_u32 = value_u32 & mask; let max_val = 1u << (precis - 1u); let value_f32 = f32(masked_value_u32) / f32(max_val) ; return value_f32; } fn decode1uToVec2(q: f32) -> vec2 { let uq = u32(q); let x = decode2(uq, 32u, 16u); let y = decode2(uq, 16u, 16u); return vec2(x, y) * 2. - 1.; } fn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 { var input = input2; // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ; let value_f32_normalized = value * f32((1u << (precis - 1u))); let delta_bits = u32(place - precis); let value_u32 = u32(value_f32_normalized) << delta_bits; var mask: u32 = 0u; if (precis < 32u) { mask = 4294967295u - (((1u << precis) - 1u) << (place - precis)); } let input = (input2 & mask) | value_u32; return input; } fn encodeVec2To1u(value: vec2) -> u32 { var input: u32 = 0u; let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0)); let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0)); input = encode2(x, input, 32u, 16u); input = encode2(y, input, 16u, 16u); return input; } struct particle { X: vec2, V: vec2, M: vec2, }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle; P.X = decode1uToVec2(data.x) + pos; P.V = decode1uToVec2(data.y); P.M = data.zw; return P; } fn saveParticle(PIn: particle, pos: vec2) -> vec4 { var P: particle = PIn; P.X = clamp(P.X - pos, vec2(-0.5), vec2(0.5)); return vec4( f32(encodeVec2To1u(P.X)), f32(encodeVec2To1u(P.V)), P.M ); } // fn getParticle(data: vec4, pos: vec2) -> particle { // var P: particle = particle( // decode(data.x) + pos, // decode(data.y), // data.zw // ); // return P; // } // fn saveParticle(P: particle, pos: vec2) -> vec4 { // var P2: particle = particle(P.X, P.V, P.M); // P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); // return vec4(encode(P2.X), encode(P2.V), P2.M); // } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(0.1031, 0.103, 0.0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } // struct particle { // X: vec2, // V: vec2, // M: vec2, // }; // fn fromLinear(linearRGB: vec4) -> vec4 { // let cutoff: vec4 = vec4(linearRGB < vec4(0.0031308)); // let higher: vec4 = vec4(1.055) * pow(linearRGB, vec4(1.0 / 2.4)) - vec4(0.055); // let lower: vec4 = linearRGB * vec4(12.92); // return mix(higher, lower, cutoff); // } // Converts a color from sRGB gamma to linear light gamma fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { R = uni.iResolution.xy; let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var fragColor: vec4; var pos = vec2(f32(location.x), f32(location.y)); // R = uni.iResolution.xy; time = uni.iTime; let p: vec2 = vec2(pos); // let data: vec4 = texel(ch0, pos); let data: vec4 = textureLoad(buffer_a, location); var P: particle = getParticle(data, pos); var rho: vec4 = vec4(0.); for (var i: i32 = -1; i <= 1; i = i + 1) { for (var j: i32 = -1; j <= 1; j = j + 1) { let ij: vec2 = vec2(i, j); // let data: vec4 = texel(ch0, pos + ij); let data: vec4 = textureLoad(buffer_a, location + ij); var P0: particle = getParticle(data, pos + vec2(ij)); let x0: vec2 = P0.X; rho = rho + (1. * vec4(P.V, P.M) * G((pos - x0) / 0.75)); } } // fragColor = rho;d // rho = clamp(rho, vec4(0.), vec4(1.)); textureStore(buffer_c, location, rho); } ================================================ FILE: assets/shaders/paint_streams/buffer_d.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; let PI = 3.14159265; let dt = 2.5; let border_h = 5.; let h = 1.; let mass = 1.; let fluid_rho = 0.5; // let dif = 1.12; var R: vec2; var Mouse: vec4; var time: f32; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; // return length(max(d, 0.)) + min(max(d.x, d.y), 0.); return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } // uint pack(vec2 x) // { // x = 65534.0*clamp(0.5*x+0.5, 0., 1.); // return uint(round(x.x)) + 65535u*uint(round(x.y)); // } // fn unpack(a: u32) -> vec2 { // var x: vec2 = vec2(f32(a) % 65535., f32(a) / 65535.); // return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; // } // vec2 unpack(uint a) // { // vec2 x = vec2(a % 65535u, a / 65535u); // return clamp(x/65534.0, 0.,1.)*2.0 - 1.0; // } // fn decode(x: f32) -> vec2 { // var X: u32 = floatBitsToUint(x); // return unpack(X); // } // fn encode(x: vec2) -> f32 { // var X: u32 = pack(x); // return uintBitsToFloat(X); // } // fn decode(&self, place: u8, precis: u8) -> f32 { // let value_u32 = self >> (place - precis); // let mut mask = u32::MAX; // if precis < 32 { // mask = (1 << (precis)) - 1; // } // // println!("mask: {:#0b}", value_u32); // let masked_value_u32 = value_u32 & mask; // let value_f32 = masked_value_u32 as f32 / ((1u32 << (precis - 1u8)) as f32); // value_f32 // } fn pack(xIn: vec2) -> u32 { var x = xIn; let x = 65534. * clamp(0.5 * x + 0.5, vec2(0.00), vec2(1.0)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } fn decode2(input: u32, place: u32, precis: u32) -> f32 { let value_u32 = input >> (place - precis); var mask: u32 = 4294967295u; if (precis < 32u) { mask = (1u << precis) - 1u; } let masked_value_u32 = value_u32 & mask; let max_val = 1u << (precis - 1u); let value_f32 = f32(masked_value_u32) / f32(max_val) ; return value_f32; } fn decode1uToVec2(q: f32) -> vec2 { let uq = u32(q); let x = decode2(uq, 32u, 16u); let y = decode2(uq, 16u, 16u); return vec2(x, y) * 2. - 1.; } fn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 { var input = input2; // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ; let value_f32_normalized = value * f32((1u << (precis - 1u))); let delta_bits = u32(place - precis); let value_u32 = u32(value_f32_normalized) << delta_bits; var mask: u32 = 0u; if (precis < 32u) { mask = 4294967295u - (((1u << precis) - 1u) << (place - precis)); } let input = (input2 & mask) | value_u32; return input; } fn encodeVec2To1u(value: vec2) -> u32 { var input: u32 = 0u; let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0)); let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0)); input = encode2(x, input, 32u, 16u); input = encode2(y, input, 16u, 16u); return input; } struct particle { X: vec2, V: vec2, M: vec2, }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle; P.X = decode1uToVec2(data.x) + pos; P.V = decode1uToVec2(data.y); P.M = data.zw; return P; } fn saveParticle(PIn: particle, pos: vec2) -> vec4 { var P: particle = PIn; P.X = clamp(P.X - pos, vec2(-0.5), vec2(0.5)); return vec4( f32(encodeVec2To1u(P.X)), f32(encodeVec2To1u(P.V)), P.M ); } // fn getParticle(data: vec4, pos: vec2) -> particle { // var P: particle = particle( // decode(data.x) + pos, // decode(data.y), // data.zw // ); // return P; // } // fn saveParticle(P: particle, pos: vec2) -> vec4 { // var P2: particle = particle(P.X, P.V, P.M); // P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); // return vec4(encode(P2.X), encode(P2.V), P2.M); // } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(0.1031, 0.103, 0.0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } // struct particle { // X: vec2, // V: vec2, // M: vec2, // }; // fn fromLinear(linearRGB: vec4) -> vec4 { // let cutoff: vec4 = vec4(linearRGB < vec4(0.0031308)); // let higher: vec4 = vec4(1.055) * pow(linearRGB, vec4(1.0 / 2.4)) - vec4(0.055); // let lower: vec4 = linearRGB * vec4(12.92); // return mix(higher, lower, cutoff); // } // Converts a color from sRGB gamma to linear light gamma fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/paint_streams/image.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @group(0) @binding(5) var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; @group(0) @binding(6) var font_texture: texture_2d; @group(0) @binding(7) var font_texture_sampler: sampler; @group(0) @binding(8) var rgba_noise_256_texture: texture_2d; @group(0) @binding(9) var rgba_noise_256_texture_sampler: sampler; @group(0) @binding(10) var blue_noise_texture: texture_2d; @group(0) @binding(11) var blue_noise_texture_sampler: sampler; // Why are the charaacters so pixelated? // One possible reason is that we are in a compute shader and the textures are not // filtered. let backColorDebug: vec3 = vec3(0.2, 0.2, 0.2); var uv_debug: vec2 ; var tp_debug: vec2 ; var align_debug: vec4; // north, east, south, west var font_size_debug: f32; var dotColor_debug: vec3 = vec3(0.5, 0.5, 0.); var drawColorDebug: vec3 = vec3(1., 1., 0.); var vColor: vec3 = backColorDebug; var aspect_debug: f32 = 1.; var pixelPosDebug: vec2 = vec2(0., 0.); let FONT_SPACE_DEBUG: f32 = 0.5; let headColorDebug: vec3 = vec3(0.9, 0.6, 0.2); let mpColorDebug: vec3 = vec3(0.99, 0.99, 0.); let mxColorDebug: vec3 = vec3(1., 0., 0.); let myColorDebug: vec3 = vec3(0., 1., 0.); let font_png_size_debug: vec2 = vec2(1023.0, 1023.0); fn chara(ch: i32) -> f32 { let fr = fract(floor(vec2(f32(ch), 15.999 - f32(ch) / 16.)) / 16.); let q = clamp(tp_debug, vec2(0.), vec2(1.)) / 16. + fr ; let inverted_q = vec2(q.x, 1. - q.y); // // There is aliasing on the charaacters // let f = textureSampleGrad(font_texture, // font_texture_sampler, // inverted_q, // vec2(1.0, 0.0), // vec2(0.0, 1.0)); // using textureLoad without sampler let q1 = vec2(font_png_size_debug * q ); let y_inverted_q1 = vec2(q1.x, i32(font_png_size_debug.y) - q1.y); var f: vec4 = textureLoad(font_texture, y_inverted_q1 , 0); // smoothing out the aliasing let dx = vec2(1, 0); let dy = vec2(0, 1); let fx1: vec4 = textureLoad(font_texture, y_inverted_q1 + dx, 0); let fx2: vec4 = textureLoad(font_texture, y_inverted_q1 - dx, 0); let fy1: vec4 = textureLoad(font_texture, y_inverted_q1 + dy, 0); let fy2: vec4 = textureLoad(font_texture, y_inverted_q1 - dy, 0); let rp = 0.25; f = f * rp + (1.0 - rp) * (fx1 + fx2 + fy1 + fy2) / 4.0 ; return f.x * (f.y + 0.3) * (f.z + 0.3) * 2.; } fn SetTextPosition(x: f32, y: f32) { tp_debug = 10. * uv_debug; tp_debug.x = tp_debug.x + 17. - x; tp_debug.y = tp_debug.y - 9.4 + y; } fn SetTextPositionAbs(x: f32, y: f32) { tp_debug.x = 10. * uv_debug.x - x; tp_debug.y = 10. * uv_debug.y - y; } fn drawFract(value: ptr, digits: ptr) -> f32 { var c: f32 = 0.; *value = fract(*value) * 10.; for (var ni: i32 = 1; ni < 60; ni = ni + 1) { c = c + (chara(48 + i32(*value))); tp_debug.x = tp_debug.x - (0.5); *digits = *digits - (1); *value = fract(*value) * 10.; if (*digits <= 0 || *value == 0.) { break; } } tp_debug.x = tp_debug.x - (0.5 * f32(*digits)); return c; } fn maxInt(a: i32, b: i32) -> i32 { var ret: i32; if (a > b) { ret = a; } else { ret = b; }; return ret; } fn drawInt(value: ptr, minDigits: ptr) -> f32 { var c: f32 = 0.; if (*value < 0) { *value = -*value; if (*minDigits < 1) { *minDigits = 1; } else { *minDigits = *minDigits - 1; } c = c + (chara(45)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); } var fn2: i32 = *value; var digits: i32 = 1; for (var ni: i32 = 0; ni < 10; ni = ni + 1) { fn2 = fn2 / (10); if (fn2 == 0) { break; } digits = digits + 1; } digits = maxInt(*minDigits, digits); tp_debug.x = tp_debug.x - (0.5 * f32(digits)); for (var ni: i32 = 1; ni < 11; ni = ni + 1) { tp_debug.x = tp_debug.x + (0.5); c = c + (chara(48 + *value % 10)); *value = *value / (10); if (ni >= digits) { break; } } tp_debug.x = tp_debug.x - (0.5 * f32(digits)); return c; } fn drawIntBackwards(value: ptr, minDigits: ptr) -> f32 { var c: f32 = 0.; let original_value: i32 = *value; if (*value < 0) { *value = -*value; if (*minDigits < 1) { *minDigits = 1; } else { *minDigits = *minDigits - 1; } // tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); // c = c + (chara(45)); } var fn2: i32 = *value; var digits: i32 = 1; for (var ni: i32 = 0; ni < 10; ni = ni + 1) { fn2 = fn2 / (10); if (fn2 == 0) { break; } digits = digits + 1; } digits = maxInt(*minDigits, digits); // tp_debug.x = tp_debug.x - (0.5 * f32(digits)); for (var ni: i32 = digits - 1; ni < 11; ni = ni - 1) { tp_debug.x = tp_debug.x + (0.5); c = c + (chara(48 + *value % 10)); *value = *value / (10); if (ni == 0) { break; } } if (original_value < 0) { tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); c = c + (chara(45)); } // tp_debug.x = tp_debug.x + (0.5 * f32(digits)); return c; } // fn drawFloat(value: ptr, prec: ptr, maxDigits: i32) -> f32 { fn drawFloat(val: f32, prec: ptr, maxDigits: i32) -> f32 { // in case of 0.099999..., round up to 0.1000000 var value = round(val * pow(10., f32(maxDigits))) / pow(10., f32(maxDigits)); let tp_debugx: f32 = tp_debug.x - 0.5 * f32(maxDigits); var c: f32 = 0.; if (value < 0.) { c = chara(45); value = -value; } tp_debug.x = tp_debug.x - (0.5); var ival = i32(value); var one: i32 = 1; c = c + (drawInt(&ival, &one)); c = c + (chara(46)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); var frac_val = fract(value); c = c + (drawFract(&frac_val, prec)); tp_debug.x = min(tp_debug.x, tp_debugx); return c; } fn drawFloat_f32(value: f32) -> f32 { var two: i32 = 2; return drawFloat(value, &two, 5); } fn drawFloat_f32_prec(value: f32, prec: ptr) -> f32 { return drawFloat(value, prec, 2); } fn drawInt_i32_back(value: ptr) -> f32 { var one: i32 = 1; return drawIntBackwards(value, &one); } fn drawInt_i32(value: ptr) -> f32 { var one: i32 = 1; return drawInt(value, &one); } fn SetColor(red: f32, green: f32, blue: f32) { drawColorDebug = vec3(red, green, blue); } fn WriteFloat(fValue: f32, maxDigits: i32, decimalPlaces: ptr) { // vColor = mix(vColor, drawColorDebug, drawFloat_f32_prec(fValue, decimalPlaces)); vColor = mix(vColor, drawColorDebug, drawFloat(fValue, decimalPlaces, maxDigits)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); ; } fn WriteFloatBox( fValue: f32, maxDigits: i32, decimalPlaces: i32, alpha: f32 ) { var decs = decimalPlaces; vColor = mix(vColor, drawColorDebug, drawFloat(fValue, &decs, maxDigits) * alpha); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); ; } fn WriteInteger(iValue: ptr) { vColor = mix(vColor, drawColorDebug, drawInt_i32(iValue)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); } fn WriteIntegerBack(iValue: ptr) { vColor = mix(vColor, drawColorDebug, drawInt_i32_back(iValue)); tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); } fn WriteFPS() { var fps: f32 = f32(uni.iSampleRate); SetColor(0.8, 0.6, 0.3); var max_digits_one = 1; WriteFloat(fps, 5, &max_digits_one); var c: f32 = 0.; c = c + (chara(102)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (chara(112)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (chara(115)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); // let c2 = smoothstep(0.0, 1.0, c ); vColor = mix(vColor, drawColorDebug, c); } fn WriteMousePos(mPos: vec2, y_pos: f32) { let digits: i32 = 3; let radius: f32 = uni.iResolution.x / 400.; if (uni.iMouse.z > 0.) { dotColor_debug = mpColorDebug; } let r: f32 = length(abs(mPos.xy) - pixelPosDebug) - radius; // vColor = vColor + (mix(vec3(0.), dotColor_debug, 1. - clamp(r, 0., 1.))); var max_digits_three: i32 = 3; var mposxi: i32 = i32(mPos.x); var mposyi: i32 = i32(mPos.y); var mposx: f32 = (mPos.x); var mposy: f32 = (mPos.y); let x_pos = align_debug.y - 1. * FONT_SPACE_DEBUG; SetTextPositionAbs( x_pos, y_pos, ); drawColorDebug = myColorDebug; WriteIntegerBack(&mposyi); SetTextPositionAbs( x_pos - 7. * FONT_SPACE_DEBUG, y_pos, ); drawColorDebug = mxColorDebug; WriteIntegerBack(&mposxi); } fn sdRoundedBox(p: vec2, b: vec2, r: vec4) -> f32 { var x = r.x; var y = r.y; x = select(r.z, r.x, p.x > 0.); y = select(r.w, r.y, p.x > 0.); x = select(y, x, p.y > 0.); let q = abs(p) - b + x; return min(max(q.x, q.y), 0.) + length(max(q, vec2(0.))) - x; } fn WriteRGBAValues( location: vec2, value: vec4, screen_poz: vec2, alpha: f32, ) { let poz = screen_poz / uni.iResolution * 20. * vec2(aspect_debug, 1.0); let window_ajusted = uni.iResolution / vec2(960., 600.); let box_pos = vec2(align_debug.w, align_debug.x - FONT_SPACE_DEBUG ) / 10.; // let box_pos = mp; // // box location follows mouse position // let box_location = vec2( // uni.iMouse.x + 100. * window_ajusted.x / ( aspect_debug / 1.6 ) , // uni.iMouse.y - 48. * window_ajusted.y // ); let box_location = vec2( 100. * window_ajusted.x / ( aspect_debug / 1.6 ) , uni.iResolution.y - 60. * window_ajusted.y, ); let inverted_screen_poz = vec2(screen_poz.x, -screen_poz.y) ; // / vec2(aspect_debug, 1.) ; let d_box = sdRoundedBox( vec2(location) - box_location - inverted_screen_poz, vec2(73. / ( aspect_debug / 1.6 ), 75.) * window_ajusted, vec4(5.,5.,5.,5.) * 5.0 ); // let alpha = 0.225; let decimal_places = 3; SetColor(1., 1., 1.); var c: f32 = 0.; let lspace = 0.8; let bg_color = vec3(.8, .7, .9); vColor = mix( vColor, bg_color, (1.0 - step(0.0, d_box)) * alpha ); // red SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1.) - 0.0 + poz.y ) ; c = c + (chara(114)); // r tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (chara(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.r, 3, decimal_places, alpha ); // green SetTextPosition( 10. * ((box_pos.x +1. + lspace)) + poz.x, 10. * (-box_pos.y +1. ) + 1.0 + poz.y, ) ; c = c + (chara(103)); // g tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (chara(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.g, 3, decimal_places, alpha ); // blue SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1. ) + 2.0 + poz.y, ) ; c = c + (chara(98)); // b tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (chara(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.b, 4, decimal_places, alpha ); // alpha SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1. ) + 3.0 + poz.y, ) ; c = c + (chara(97)); // a tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (chara(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.a, 4, decimal_places, alpha ); vColor = mix(vColor, drawColorDebug, c * alpha); } fn sdSegment(p: vec2, a: vec2, b: vec2) -> f32 { let pa = p - a; let ba = b - a; let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.); return length(pa - ba * h); } fn ring(pos: vec2, radius: f32, thick: f32) -> f32 { return mix(1., 0., smoothstep(thick, thick + 0.01, abs(length(uv_debug - pos) - radius))); } fn sdCircle(p: vec2, c: vec2, r: f32) -> f32 { let d = length(p - c); return d - r; } fn draw_ring(location: vec2) { let mouse_click_poz = vec2(abs(uni.iMouse.z) , abs(uni.iMouse.w)); let alpha = 0.75; let ring_dist = sdCircle(vec2(location) , mouse_click_poz, 2.3); let d = smoothstep(0.5, 1.5, abs(ring_dist - 1.)); vColor = mix(vColor, headColorDebug, (1. - d) * alpha ); } fn draw_crossair(location: vec2) { let start = 5.0; let end = 20.; let segment1 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(start, 0.), vec2(end, 0.) ); let segment2 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(-start, 0.), vec2(-end, 0.) ); let segment3 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(0., start), vec2(0., end) ); let segment4 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(0., -start), vec2(0., -end) ); var alpha = 0.75; if (uni.iMouse.z > 0.) { alpha = 1.0; } let d = smoothstep(0.5, 1.5, segment1); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothstep(0.5, 1.5, segment2); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothstep(0.5, 1.5, segment3); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothstep(0.5, 1.5, segment4); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); } fn show_debug_info(location: vec2, color: vec3) -> vec4 { var fragCoord = vec2(f32(location.x), f32(location.y) ); vColor = color; aspect_debug = uni.iResolution.x / uni.iResolution.y; let ratio: vec2 = vec2(aspect_debug, 1.); pixelPosDebug = fragCoord.xy; // mousePosDebug = uni.iMouse.xy; uv_debug = (2. * fragCoord.xy / uni.iResolution.xy - 1.) * ratio; align_debug = 10. * vec4( 1., // North aspect_debug, // East -1., // South -aspect_debug, // West ); WriteMousePos(uni.iMouse.zw, align_debug.z + 2.0 * FONT_SPACE_DEBUG); // Click position WriteMousePos(uni.iMouse.xy, align_debug.z + 0.2 * FONT_SPACE_DEBUG); // Current mouse position var c: f32 = 0.; SetTextPositionAbs( align_debug.y - FONT_SPACE_DEBUG, align_debug.x - 2. * FONT_SPACE_DEBUG, ); SetColor(0.8, 0.8, 0.8); var resx = i32(uni.iResolution.x); var resy = i32(uni.iResolution.y); WriteIntegerBack(&resx); c = c + (chara(28)); tp_debug.x = tp_debug.x + 0. * (FONT_SPACE_DEBUG); WriteIntegerBack(&resy); SetTextPositionAbs( align_debug.w - 1. * FONT_SPACE_DEBUG, align_debug.z - 0. * FONT_SPACE_DEBUG, ); WriteFPS(); SetColor(0.9, 0.7, 0.8); let fragColor = vec4(vColor, 1.); let poz = vec2(0., uni.iResolution.y / 2.); // // RGBA probe labels follow mouse // let poz = vec2(uni.iMouse.x , uni.iResolution.y - uni.iMouse.y); let inverted_y_mouse_location = vec2(vec2(uni.iMouse.x, uni.iResolution.y - uni.iMouse.y)); let value: vec4 = textureLoad(texture, inverted_y_mouse_location); WriteRGBAValues(location, value, poz, 0.85); let inverted_y_mouseclick_location = vec2(vec2(abs(uni.iMouse.z), uni.iResolution.y - abs(uni.iMouse.w))); let value2: vec4 = textureLoad(texture, inverted_y_mouseclick_location); WriteRGBAValues(location, value2, vec2(0.), 0.65); draw_crossair(location); draw_ring(location); let fragColor = vec4(vColor, 1.); return fragColor; } let PI = 3.14159265; let dt = 2.5; let border_h = 5.; let h = 1.; let mass = 1.; let fluid_rho = 0.5; // let dif = 1.12; var R: vec2; var Mouse: vec4; var time: f32; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; // return length(max(d, 0.)) + min(max(d.x, d.y), 0.); return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } // uint pack(vec2 x) // { // x = 65534.0*clamp(0.5*x+0.5, 0., 1.); // return uint(round(x.x)) + 65535u*uint(round(x.y)); // } // fn unpack(a: u32) -> vec2 { // var x: vec2 = vec2(f32(a) % 65535., f32(a) / 65535.); // return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; // } // vec2 unpack(uint a) // { // vec2 x = vec2(a % 65535u, a / 65535u); // return clamp(x/65534.0, 0.,1.)*2.0 - 1.0; // } // fn decode(x: f32) -> vec2 { // var X: u32 = floatBitsToUint(x); // return unpack(X); // } // fn encode(x: vec2) -> f32 { // var X: u32 = pack(x); // return uintBitsToFloat(X); // } // fn decode(&self, place: u8, precis: u8) -> f32 { // let value_u32 = self >> (place - precis); // let mut mask = u32::MAX; // if precis < 32 { // mask = (1 << (precis)) - 1; // } // // println!("mask: {:#0b}", value_u32); // let masked_value_u32 = value_u32 & mask; // let value_f32 = masked_value_u32 as f32 / ((1u32 << (precis - 1u8)) as f32); // value_f32 // } fn pack(xIn: vec2) -> u32 { var x = xIn; let x = 65534. * clamp(0.5 * x + 0.5, vec2(0.00), vec2(1.0)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } fn decode2(input: u32, place: u32, precis: u32) -> f32 { let value_u32 = input >> (place - precis); var mask: u32 = 4294967295u; if (precis < 32u) { mask = (1u << precis) - 1u; } let masked_value_u32 = value_u32 & mask; let max_val = 1u << (precis - 1u); let value_f32 = f32(masked_value_u32) / f32(max_val) ; return value_f32; } fn decode1uToVec2(q: f32) -> vec2 { let uq = u32(q); let x = decode2(uq, 32u, 16u); let y = decode2(uq, 16u, 16u); return vec2(x, y) * 2. - 1.; } fn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 { var input = input2; // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ; let value_f32_normalized = value * f32((1u << (precis - 1u))); let delta_bits = u32(place - precis); let value_u32 = u32(value_f32_normalized) << delta_bits; var mask: u32 = 0u; if (precis < 32u) { mask = 4294967295u - (((1u << precis) - 1u) << (place - precis)); } let input = (input2 & mask) | value_u32; return input; } fn encodeVec2To1u(value: vec2) -> u32 { var input: u32 = 0u; let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0)); let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0)); input = encode2(x, input, 32u, 16u); input = encode2(y, input, 16u, 16u); return input; } struct particle { X: vec2, V: vec2, M: vec2, }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle; P.X = decode1uToVec2(data.x) + pos; P.V = decode1uToVec2(data.y); P.M = data.zw; return P; } fn saveParticle(PIn: particle, pos: vec2) -> vec4 { var P: particle = PIn; P.X = clamp(P.X - pos, vec2(-0.5), vec2(0.5)); return vec4( f32(encodeVec2To1u(P.X)), f32(encodeVec2To1u(P.V)), P.M ); } // fn getParticle(data: vec4, pos: vec2) -> particle { // var P: particle = particle( // decode(data.x) + pos, // decode(data.y), // data.zw // ); // return P; // } // fn saveParticle(P: particle, pos: vec2) -> vec4 { // var P2: particle = particle(P.X, P.V, P.M); // P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); // return vec4(encode(P2.X), encode(P2.V), P2.M); // } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(0.1031, 0.103, 0.0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } // struct particle { // X: vec2, // V: vec2, // M: vec2, // }; // fn fromLinear(linearRGB: vec4) -> vec4 { // let cutoff: vec4 = vec4(linearRGB < vec4(0.0031308)); // let higher: vec4 = vec4(1.055) * pow(linearRGB, vec4(1.0 / 2.4)) - vec4(0.055); // let lower: vec4 = linearRGB * vec4(12.92); // return mix(higher, lower, cutoff); // } // Converts a color from sRGB gamma to linear light gamma fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } // https://www.shadertoy.com/view/WtfyDj // no license // https://michaelmoroz.github.io/Reintegration-Tracking/ fn mixN(a: vec3, b: vec3, k: f32) -> vec3 { return sqrt(mix(a * a, b * b, clamp(k, 0., 1.))); } fn V(p: vec2) -> vec4 { let data: vec4 = textureLoad(buffer_c, vec2(p)); // let data: vec4 = textureSampleLevel(buffer_c, buffer_sampler, p / R, 0.0); // let data: vec4 = textureSampleGrad(buffer_c, // buffer_sampler, // p / R, // vec2(0.0), // vec2(0.0)) ; return data; } fn border(p: vec2, R2: vec2) -> f32 { let bound: f32 = -sdBox(p - R2 * 0.5, R2 * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time) * (p - R2 * vec2(0.5, 0.6)), R2 * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R2 * vec2(0.5, 0.7), R2 * vec2(1.5, 0.5)); return max(drain, min(bound, box)); } fn bN(p: vec2, R2: vec2) -> vec3 { let dx: vec3 = vec3(-h, 0., h); let idx: vec4 = vec4(-1. / h, 0., 1. / h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy, R2) + idx.xyw * border(p + dx.xy, R2) + idx.yzw * border(p + dx.yz, R2) + idx.yxw * border(p + dx.yx, R2); return vec3(normalize(r.xy), r.z + 1.0e-4); } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { R = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var col: vec4; var pos = vec2(f32(location.x), f32(location.y)) ; // let Mouse = uni.iMouse; time = uni.iTime; let p: vec2 = vec2(pos); let data: vec4 = textureLoad(buffer_a, location); var P: particle = getParticle(data, pos); let Nb: vec3 = bN(P.X, R); let bord: f32 = smoothstep(2. * border_h, border_h * 0.5, border(pos, R)); let rho: vec4 = V(pos); let dx: vec3 = vec3(-2., 0., 2.); let grad: vec4 = -0.5 * vec4(V(pos + dx.zy).zw - V(pos + dx.xy).zw, V(pos + dx.yz).zw - V(pos + dx.yx).zw); let N: vec2 = pow(length(grad.xz), 0.2) * normalize(grad.xz + 0.00001); let specular: f32 = pow(max(dot(N, Dir(1.4)), 0.), 3.5); let specularb: f32 = G(0.4 * (Nb.zz - border_h)) * pow(max(dot(Nb.xy, Dir(1.4)), 0.), 3.); let a: f32 = pow(smoothstep(fluid_rho * 0., fluid_rho * 2., rho.z), 0.1); let b: f32 = exp(-1.7 * smoothstep(fluid_rho * 1., fluid_rho * 7.5, rho.z)); let col0: vec3 = vec3(1., 0.5, 0.); let col1: vec3 = vec3(0.1, 0.4, 1.); let fcol: vec3 = mixN(col0, col1, tanh(3. * (rho.w - 0.7)) * 0.5 + 0.5); col = vec4(3.); var colxyz = col.xyz; colxyz = mixN(col.xyz, fcol.xyz * (1.5 * b + specular * 5.), a); col.x = colxyz.x; col.y = colxyz.y; col.z = colxyz.z; var colxyz = col.xyz; colxyz = mixN(col.xyz, 0. * vec3(0.5, 0.5, 1.), bord); col.x = colxyz.x; col.y = colxyz.y; col.z = colxyz.z; var colxyz = col.xyz; colxyz = tanh(col.xyz); col.x = colxyz.x; col.y = colxyz.y; col.z = colxyz.z; // let bufa: vec4 = textureLoad(buffer_a, location); // var col2 = vec4(0.2, 0.6, 0.9, 1.0); // var col2 = vec4(0.3, 0.5, 0.29, 1.0); // if (y_inverted_location.x > i32(R.x / 2.0)) { // let v = vec2(0.3, 0.5) * 2.0; // let u = f32(encodeVec2To1u(v)); // let back = decode1uToVec2(u) / 2.0; // col2 = vec4(back.x, back.y, 0.29, 1.0); // } // let data2: vec4 = (textureLoad(buffer_a, location) ) ; // var pb: particle = getParticle(data2, pos); // let v2 = (pb.X - pos + 1.0) / 2.; // let v2 = (pb.M ) / 1.; // let debug = vec4(v2.x, 0.0, 0.0, 1.0); // if (Mouse.z > 0.5) { // col = debug; // } let col_debug_info = show_debug_info(location, col.xyz); // textureStore(texture, y_inverted_location, toLinear(debug)); // textureStore(texture, y_inverted_location, toLinear(col)); textureStore(texture, y_inverted_location, toLinear(col_debug_info)); } ================================================ FILE: assets/shaders/paint_streams2/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; let PI = 3.14159265; let dt = 2.5; let border_h = 5.; let h = 1.; let mass = 1.; let fluid_rho = 0.5; // let dif = 1.12; var R: vec2; var Mouse: vec4; var time: f32; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; // return length(max(d, 0.)) + min(max(d.x, d.y), 0.); return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } // uint pack(vec2 x) // { // x = 65534.0*clamp(0.5*x+0.5, 0., 1.); // return uint(round(x.x)) + 65535u*uint(round(x.y)); // } // fn unpack(a: u32) -> vec2 { // var x: vec2 = vec2(f32(a) % 65535., f32(a) / 65535.); // return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; // } // vec2 unpack(uint a) // { // vec2 x = vec2(a % 65535u, a / 65535u); // return clamp(x/65534.0, 0.,1.)*2.0 - 1.0; // } // fn decode(x: f32) -> vec2 { // var X: u32 = floatBitsToUint(x); // return unpack(X); // } // fn encode(x: vec2) -> f32 { // var X: u32 = pack(x); // return uintBitsToFloat(X); // } // fn decode(&self, place: u8, precision: u8) -> f32 { // let value_u32 = self >> (place - precision); // let mut mask = u32::MAX; // if precision < 32 { // mask = (1 << (precision)) - 1; // } // // println!("mask: {:#0b}", value_u32); // let masked_value_u32 = value_u32 & mask; // let value_f32 = masked_value_u32 as f32 / ((1u32 << (precision - 1u8)) as f32); // value_f32 // } fn pack(xIn: vec2) -> u32 { var x = xIn; let x = 65534. * clamp(0.5 * x + 0.5, vec2(0.00), vec2(1.0)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } fn decode2(input: u32, place: u32, precision: u32) -> f32 { let value_u32 = input >> (place - precision); var mask: u32 = 4294967295u; if (precision < 32u) { mask = (1u << precision) - 1u; } let masked_value_u32 = value_u32 & mask; let max_val = 1u << (precision - 1u); let value_f32 = f32(masked_value_u32) / f32(max_val) ; return value_f32; } fn decode1uToVec2(q: f32) -> vec2 { let uq = u32(q); let x = decode2(uq, 32u, 16u); let y = decode2(uq, 16u, 16u); return vec2(x, y) * 2. - 1.; } fn encode2(value: f32, input2: u32, place: u32, precision: u32) -> u32 { var input = input2; // let value_f32_normalized = value * f32(1u, 32u << (precision - 1u)) ; let value_f32_normalized = value * f32((1u << (precision - 1u))); let delta_bits = u32(place - precision); let value_u32 = u32(value_f32_normalized) << delta_bits; var mask: u32 = 0u; if (precision < 32u) { mask = 4294967295u - (((1u << precision) - 1u) << (place - precision)); } let input = (input2 & mask) | value_u32; return input; } fn encodeVec2To1u(value: vec2) -> u32 { var input: u32 = 0u; let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0)); let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0)); input = encode2(x, input, 32u, 16u); input = encode2(y, input, 16u, 16u); return input; } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle; P.X = decode1uToVec2(data.x) + pos; P.V = decode1uToVec2(data.y); P.M = data.zw; return P; } fn saveParticle(PIn: particle, pos: vec2) -> vec4 { var P: particle = PIn; P.X = clamp(P.X - pos, vec2(-0.5), vec2(0.5)); return vec4( f32(encodeVec2To1u(P.X)), f32(encodeVec2To1u(P.V)), P.M ); } // fn getParticle(data: vec4, pos: vec2) -> particle { // var P: particle = particle( // decode(data.x) + pos, // decode(data.y), // data.zw // ); // return P; // } // fn saveParticle(P: particle, pos: vec2) -> vec4 { // var P2: particle = particle(P.X, P.V, P.M); // P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); // return vec4(encode(P2.X), encode(P2.V), P2.M); // } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(0.1031, 0.103, 0.0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } struct particle { X: vec2; V: vec2; M: vec2; }; // fn fromLinear(linearRGB: vec4) -> vec4 { // let cutoff: vec4 = vec4(linearRGB < vec4(0.0031308)); // let higher: vec4 = vec4(1.055) * pow(linearRGB, vec4(1.0 / 2.4)) - vec4(0.055); // let lower: vec4 = linearRGB * vec4(12.92); // return mix(higher, lower, cutoff); // } // Converts a color from sRGB gamma to linear light gamma fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } fn Reintegration(ch: texture_storage_2d, pos: vec2) -> particle { var P: particle = particle(vec2(0.0), vec2(0.0), vec2(0.0)); for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(j)); let data: vec4 = textureLoad(ch, vec2(tpos)); var P0: particle = getParticle(data, tpos); P0.X = P0.X + (P0.V * dt); //integrate position let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x); let D: vec3 = distribution(P0.X, pos, difR); let m: f32 = P0.M.x * D.z; P.X = P.X + (D.xy * m); P.V = P.V + (P0.V * m); P.M.y = P.M.y + (P0.M.y * m); P.M.x = P.M.x + (m); } } if (P.M.x > 0.0000001) { P.X = P.X / (P.M.x); P.V = P.V / (P.M.x); P.M.y = P.M.y / (P.M.x); } return P; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; // let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var U: vec4; var pos = vec2(f32(location.x), f32(location.y)); // R = uni.iResolution.xy; // time = uni.iTime; // Mouse = uni.iMouse; // let p: vec2 = vec2(pos); // let data: vec4 = texel(ch0, pos); // var P: particle; var P: particle = Reintegration(buffer_b, pos); // if (uni.iFrame < 1) { #ifdef INIT let rand: vec3 = hash32(pos); if (rand.z < 0.) { P.X = pos; P.V = 0.5 * (rand.xy - 0.5) + vec2(0., 0.); P.M = vec2(mass, 0.); } else { P.X = pos; P.V = vec2(0.); P.M = vec2(0.000001); } #endif // } U = saveParticle(P, pos); // U = clamp(U, vec4(0.), vec4(1.)); textureStore(buffer_a, location, U); } ================================================ FILE: assets/shaders/paint_streams2/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; let PI = 3.14159265; let dt = 2.5; let border_h = 5.; let h = 1.; let mass = 1.; let fluid_rho = 0.5; // let dif = 1.12; var R: vec2; var Mouse: vec4; var time: f32; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; // return length(max(d, 0.)) + min(max(d.x, d.y), 0.); return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } // uint pack(vec2 x) // { // x = 65534.0*clamp(0.5*x+0.5, 0., 1.); // return uint(round(x.x)) + 65535u*uint(round(x.y)); // } // fn unpack(a: u32) -> vec2 { // var x: vec2 = vec2(f32(a) % 65535., f32(a) / 65535.); // return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; // } // vec2 unpack(uint a) // { // vec2 x = vec2(a % 65535u, a / 65535u); // return clamp(x/65534.0, 0.,1.)*2.0 - 1.0; // } // fn decode(x: f32) -> vec2 { // var X: u32 = floatBitsToUint(x); // return unpack(X); // } // fn encode(x: vec2) -> f32 { // var X: u32 = pack(x); // return uintBitsToFloat(X); // } // fn decode(&self, place: u8, precision: u8) -> f32 { // let value_u32 = self >> (place - precision); // let mut mask = u32::MAX; // if precision < 32 { // mask = (1 << (precision)) - 1; // } // // println!("mask: {:#0b}", value_u32); // let masked_value_u32 = value_u32 & mask; // let value_f32 = masked_value_u32 as f32 / ((1u32 << (precision - 1u8)) as f32); // value_f32 // } fn pack(xIn: vec2) -> u32 { var x = xIn; let x = 65534. * clamp(0.5 * x + 0.5, vec2(0.00), vec2(1.0)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } fn decode2(input: u32, place: u32, precision: u32) -> f32 { let value_u32 = input >> (place - precision); var mask: u32 = 4294967295u; if (precision < 32u) { mask = (1u << precision) - 1u; } let masked_value_u32 = value_u32 & mask; let max_val = 1u << (precision - 1u); let value_f32 = f32(masked_value_u32) / f32(max_val) ; return value_f32; } fn decode1uToVec2(q: f32) -> vec2 { let uq = u32(q); let x = decode2(uq, 32u, 16u); let y = decode2(uq, 16u, 16u); return vec2(x, y) * 2. - 1.; } fn encode2(value: f32, input2: u32, place: u32, precision: u32) -> u32 { var input = input2; // let value_f32_normalized = value * f32(1u, 32u << (precision - 1u)) ; let value_f32_normalized = value * f32((1u << (precision - 1u))); let delta_bits = u32(place - precision); let value_u32 = u32(value_f32_normalized) << delta_bits; var mask: u32 = 0u; if (precision < 32u) { mask = 4294967295u - (((1u << precision) - 1u) << (place - precision)); } let input = (input2 & mask) | value_u32; return input; } fn encodeVec2To1u(value: vec2) -> u32 { var input: u32 = 0u; let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0)); let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0)); input = encode2(x, input, 32u, 16u); input = encode2(y, input, 16u, 16u); return input; } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle; P.X = decode1uToVec2(data.x) + pos; P.V = decode1uToVec2(data.y); P.M = data.zw; return P; } fn saveParticle(PIn: particle, pos: vec2) -> vec4 { var P: particle = PIn; P.X = clamp(P.X - pos, vec2(-0.5), vec2(0.5)); return vec4( f32(encodeVec2To1u(P.X)), f32(encodeVec2To1u(P.V)), P.M ); } // fn getParticle(data: vec4, pos: vec2) -> particle { // var P: particle = particle( // decode(data.x) + pos, // decode(data.y), // data.zw // ); // return P; // } // fn saveParticle(P: particle, pos: vec2) -> vec4 { // var P2: particle = particle(P.X, P.V, P.M); // P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); // return vec4(encode(P2.X), encode(P2.V), P2.M); // } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(0.1031, 0.103, 0.0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } struct particle { X: vec2; V: vec2; M: vec2; }; // fn fromLinear(linearRGB: vec4) -> vec4 { // let cutoff: vec4 = vec4(linearRGB < vec4(0.0031308)); // let higher: vec4 = vec4(1.055) * pow(linearRGB, vec4(1.0 / 2.4)) - vec4(0.055); // let lower: vec4 = linearRGB * vec4(12.92); // return mix(higher, lower, cutoff); // } // Converts a color from sRGB gamma to linear light gamma fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } fn border(p: vec2, R2: vec2) -> f32 { let bound: f32 = -sdBox(p - R2 * 0.5, R2 * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time) * (p - R2 * vec2(0.5, 0.6)), R2 * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R2 * vec2(0.5, 0.7), R2 * vec2(1.5, 0.5)); return max(drain, min(bound, box)); } fn bN(p: vec2, R2: vec2) -> vec3 { let dx: vec3 = vec3(-h, 0., h); let idx: vec4 = vec4(-1. / h, 0., 1. / h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy, R2) + idx.xyw * border(p + dx.xy, R2) + idx.yzw * border(p + dx.yz, R2) + idx.yxw * border(p + dx.yx, R2); return vec3(normalize(r.xy), r.z + 1.0e-4); } fn Simulation( ch: texture_storage_2d, P: ptr, pos: vec2) { var F: vec2 = vec2(0.); var avgV: vec3 = vec3(0.,); // var P = *PIn; for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(j)); // let data: vec4 = texelFetch(ch, Bi(tpos), 0.); let data: vec4 = textureLoad(ch, vec2(tpos)) ; var P0: particle = getParticle(data, tpos); let dx: vec2 = P0.X - (*P).X; let avgP: f32 = 0.5 * P0.M.x * (Pf((*P).M) + Pf(P0.M)); F = F - (0.5 * G(1. * dx) * avgP * dx); avgV = avgV + (P0.M.x * G(1. * dx) * vec3(P0.V.x, P0.V.y, 1.)); } } var avgVxy = avgV.xy; avgVxy = avgV.xy / (avgV.z); avgV.x = avgVxy.x; avgV.y = avgVxy.y; F = F + (0. * (*P).M.x * (avgV.xy - (*P).V)); F = F + ((*P).M.x * vec2(0., -0.0004)); if (Mouse.z > 0.) { let dm: vec2 = (Mouse.xy - Mouse.zw ) / 10.; let d: f32 = distance(Mouse.xy, (*P).X) / 20.; F = F + (0.001 * dm * exp(-d * d)); // let Part = particle(vec2(0.), vec2(0.), vec2(0.)); // return Part; } (*P).V = (*P).V + (F * dt / (*P).M.x); let N: vec3 = bN((*P).X, R); let vdotN: f32 = step(N.z, border_h) * dot(-N.xy, (*P).V); (*P).V = (*P).V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN))); (*P).V = (*P).V + (0. * (*P).M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z)); if (N.z < 0.) { (*P).V = vec2(0.); } let v: f32 = length((*P).V); var dum: f32; if (v > 1.) { dum = v; } else { dum = 1.; } (*P).V = (*P).V / dum; // return P; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { R = uni.iResolution.xy; // let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var U: vec4; var pos = vec2(f32(location.x), f32(location.y)); // R = uni.iResolution.xy; time = uni.iTime; Mouse = uni.iMouse; let p: vec2 = vec2(pos); // let data: vec4 = texel(ch0, pos); let data: vec4 = textureLoad(buffer_a, location); var P: particle = getParticle(data, pos); if (P.M.x != 0.) { Simulation(buffer_a, &P, pos); } let timeMult = 1.0; if (length(P.X - R * vec2(0.55, 0.9)) < 20.) { P.X = pos; P.V = 0.5 * Dir(-PI * 0.75 + 0.3 * sin(0.4 * 2.0 * timeMult)); P.M = mix(P.M, vec2(fluid_rho, 1.), 0.4); } if (length(P.X - R * vec2(0.45, 0.9)) < 20.) { // P.X = pos; // P.V = 0.5 * Dir(-PI * 0.25 + 0.3 * sin(0.3 * timeMult)); // P.M = mix(P.M, vec2(fluid_rho, 0.), 0.4); P.X = pos; P.V = 0.5 * Dir(PI * 0.25 - PI * 0.5 + 0.3 * sin(0.4 * 2.0 * timeMult)); P.M = mix(P.M, vec2(fluid_rho, 0.5), 0.4); } U = saveParticle(P, pos); // U = clamp(U, vec4(-1000000.), vec4(100000.)); // U.y = clamp(U.y, -1000000., 100000.); textureStore(buffer_b, location, U); // let b = vec4(.5, 0.2, 0.1, 1.0) * -10000.0; // textureStore(buffer_b, location, b); } ================================================ FILE: assets/shaders/paint_streams2/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; let PI = 3.14159265; let dt = 2.5; let border_h = 5.; let h = 1.; let mass = 1.; let fluid_rho = 0.5; // let dif = 1.12; var R: vec2; var Mouse: vec4; var time: f32; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; // return length(max(d, 0.)) + min(max(d.x, d.y), 0.); return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } // uint pack(vec2 x) // { // x = 65534.0*clamp(0.5*x+0.5, 0., 1.); // return uint(round(x.x)) + 65535u*uint(round(x.y)); // } // fn unpack(a: u32) -> vec2 { // var x: vec2 = vec2(f32(a) % 65535., f32(a) / 65535.); // return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; // } // vec2 unpack(uint a) // { // vec2 x = vec2(a % 65535u, a / 65535u); // return clamp(x/65534.0, 0.,1.)*2.0 - 1.0; // } // fn decode(x: f32) -> vec2 { // var X: u32 = floatBitsToUint(x); // return unpack(X); // } // fn encode(x: vec2) -> f32 { // var X: u32 = pack(x); // return uintBitsToFloat(X); // } // fn decode(&self, place: u8, precision: u8) -> f32 { // let value_u32 = self >> (place - precision); // let mut mask = u32::MAX; // if precision < 32 { // mask = (1 << (precision)) - 1; // } // // println!("mask: {:#0b}", value_u32); // let masked_value_u32 = value_u32 & mask; // let value_f32 = masked_value_u32 as f32 / ((1u32 << (precision - 1u8)) as f32); // value_f32 // } fn pack(xIn: vec2) -> u32 { var x = xIn; let x = 65534. * clamp(0.5 * x + 0.5, vec2(0.00), vec2(1.0)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } fn decode2(input: u32, place: u32, precision: u32) -> f32 { let value_u32 = input >> (place - precision); var mask: u32 = 4294967295u; if (precision < 32u) { mask = (1u << precision) - 1u; } let masked_value_u32 = value_u32 & mask; let max_val = 1u << (precision - 1u); let value_f32 = f32(masked_value_u32) / f32(max_val) ; return value_f32; } fn decode1uToVec2(q: f32) -> vec2 { let uq = u32(q); let x = decode2(uq, 32u, 16u); let y = decode2(uq, 16u, 16u); return vec2(x, y) * 2. - 1.; } fn encode2(value: f32, input2: u32, place: u32, precision: u32) -> u32 { var input = input2; // let value_f32_normalized = value * f32(1u, 32u << (precision - 1u)) ; let value_f32_normalized = value * f32((1u << (precision - 1u))); let delta_bits = u32(place - precision); let value_u32 = u32(value_f32_normalized) << delta_bits; var mask: u32 = 0u; if (precision < 32u) { mask = 4294967295u - (((1u << precision) - 1u) << (place - precision)); } let input = (input2 & mask) | value_u32; return input; } fn encodeVec2To1u(value: vec2) -> u32 { var input: u32 = 0u; let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0)); let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0)); input = encode2(x, input, 32u, 16u); input = encode2(y, input, 16u, 16u); return input; } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle; P.X = decode1uToVec2(data.x) + pos; P.V = decode1uToVec2(data.y); P.M = data.zw; return P; } fn saveParticle(PIn: particle, pos: vec2) -> vec4 { var P: particle = PIn; P.X = clamp(P.X - pos, vec2(-0.5), vec2(0.5)); return vec4( f32(encodeVec2To1u(P.X)), f32(encodeVec2To1u(P.V)), P.M ); } // fn getParticle(data: vec4, pos: vec2) -> particle { // var P: particle = particle( // decode(data.x) + pos, // decode(data.y), // data.zw // ); // return P; // } // fn saveParticle(P: particle, pos: vec2) -> vec4 { // var P2: particle = particle(P.X, P.V, P.M); // P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); // return vec4(encode(P2.X), encode(P2.V), P2.M); // } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(0.1031, 0.103, 0.0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } struct particle { X: vec2; V: vec2; M: vec2; }; // fn fromLinear(linearRGB: vec4) -> vec4 { // let cutoff: vec4 = vec4(linearRGB < vec4(0.0031308)); // let higher: vec4 = vec4(1.055) * pow(linearRGB, vec4(1.0 / 2.4)) - vec4(0.055); // let lower: vec4 = linearRGB * vec4(12.92); // return mix(higher, lower, cutoff); // } // Converts a color from sRGB gamma to linear light gamma fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { R = uni.iResolution.xy; let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var fragColor: vec4; var pos = vec2(f32(location.x), f32(location.y)); // R = uni.iResolution.xy; time = uni.iTime; let p: vec2 = vec2(pos); // let data: vec4 = texel(ch0, pos); let data: vec4 = textureLoad(buffer_a, location); var P: particle = getParticle(data, pos); var rho: vec4 = vec4(0.); for (var i: i32 = -1; i <= 1; i = i + 1) { for (var j: i32 = -1; j <= 1; j = j + 1) { let ij: vec2 = vec2(i, j); // let data: vec4 = texel(ch0, pos + ij); let data: vec4 = textureLoad(buffer_a, location + ij); var P0: particle = getParticle(data, pos + vec2(ij)); let x0: vec2 = P0.X; rho = rho + (1. * vec4(P.V, P.M) * G((pos - x0) / 0.75)); } } // fragColor = rho;d // rho = clamp(rho, vec4(0.), vec4(1.)); textureStore(buffer_c, location, rho); } ================================================ FILE: assets/shaders/paint_streams2/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; let PI = 3.14159265; let dt = 2.5; let border_h = 5.; let h = 1.; let mass = 1.; let fluid_rho = 0.5; // let dif = 1.12; var R: vec2; var Mouse: vec4; var time: f32; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; // return length(max(d, 0.)) + min(max(d.x, d.y), 0.); return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } // uint pack(vec2 x) // { // x = 65534.0*clamp(0.5*x+0.5, 0., 1.); // return uint(round(x.x)) + 65535u*uint(round(x.y)); // } // fn unpack(a: u32) -> vec2 { // var x: vec2 = vec2(f32(a) % 65535., f32(a) / 65535.); // return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; // } // vec2 unpack(uint a) // { // vec2 x = vec2(a % 65535u, a / 65535u); // return clamp(x/65534.0, 0.,1.)*2.0 - 1.0; // } // fn decode(x: f32) -> vec2 { // var X: u32 = floatBitsToUint(x); // return unpack(X); // } // fn encode(x: vec2) -> f32 { // var X: u32 = pack(x); // return uintBitsToFloat(X); // } // fn decode(&self, place: u8, precision: u8) -> f32 { // let value_u32 = self >> (place - precision); // let mut mask = u32::MAX; // if precision < 32 { // mask = (1 << (precision)) - 1; // } // // println!("mask: {:#0b}", value_u32); // let masked_value_u32 = value_u32 & mask; // let value_f32 = masked_value_u32 as f32 / ((1u32 << (precision - 1u8)) as f32); // value_f32 // } fn pack(xIn: vec2) -> u32 { var x = xIn; let x = 65534. * clamp(0.5 * x + 0.5, vec2(0.00), vec2(1.0)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } fn decode2(input: u32, place: u32, precision: u32) -> f32 { let value_u32 = input >> (place - precision); var mask: u32 = 4294967295u; if (precision < 32u) { mask = (1u << precision) - 1u; } let masked_value_u32 = value_u32 & mask; let max_val = 1u << (precision - 1u); let value_f32 = f32(masked_value_u32) / f32(max_val) ; return value_f32; } fn decode1uToVec2(q: f32) -> vec2 { let uq = u32(q); let x = decode2(uq, 32u, 16u); let y = decode2(uq, 16u, 16u); return vec2(x, y) * 2. - 1.; } fn encode2(value: f32, input2: u32, place: u32, precision: u32) -> u32 { var input = input2; // let value_f32_normalized = value * f32(1u, 32u << (precision - 1u)) ; let value_f32_normalized = value * f32((1u << (precision - 1u))); let delta_bits = u32(place - precision); let value_u32 = u32(value_f32_normalized) << delta_bits; var mask: u32 = 0u; if (precision < 32u) { mask = 4294967295u - (((1u << precision) - 1u) << (place - precision)); } let input = (input2 & mask) | value_u32; return input; } fn encodeVec2To1u(value: vec2) -> u32 { var input: u32 = 0u; let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0)); let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0)); input = encode2(x, input, 32u, 16u); input = encode2(y, input, 16u, 16u); return input; } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle; P.X = decode1uToVec2(data.x) + pos; P.V = decode1uToVec2(data.y); P.M = data.zw; return P; } fn saveParticle(PIn: particle, pos: vec2) -> vec4 { var P: particle = PIn; P.X = clamp(P.X - pos, vec2(-0.5), vec2(0.5)); return vec4( f32(encodeVec2To1u(P.X)), f32(encodeVec2To1u(P.V)), P.M ); } // fn getParticle(data: vec4, pos: vec2) -> particle { // var P: particle = particle( // decode(data.x) + pos, // decode(data.y), // data.zw // ); // return P; // } // fn saveParticle(P: particle, pos: vec2) -> vec4 { // var P2: particle = particle(P.X, P.V, P.M); // P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); // return vec4(encode(P2.X), encode(P2.V), P2.M); // } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(0.1031, 0.103, 0.0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } struct particle { X: vec2; V: vec2; M: vec2; }; // fn fromLinear(linearRGB: vec4) -> vec4 { // let cutoff: vec4 = vec4(linearRGB < vec4(0.0031308)); // let higher: vec4 = vec4(1.055) * pow(linearRGB, vec4(1.0 / 2.4)) - vec4(0.055); // let lower: vec4 = linearRGB * vec4(12.92); // return mix(higher, lower, cutoff); // } // Converts a color from sRGB gamma to linear light gamma fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/paint_streams2/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // [[group(0), binding(1)]] // var buffer_a: texture_storage_2d; // [[group(0), binding(2)]] // var buffer_b: texture_storage_2d; // [[group(0), binding(3)]] // var buffer_c: texture_storage_2d; // [[group(0), binding(4)]] // var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; [[group(0), binding(6)]] var font_texture: texture_2d; [[group(0), binding(7)]] var font_texture_sampler: sampler; [[group(0), binding(8)]] var rgba_noise_256_texture: texture_2d; [[group(0), binding(9)]] var rgba_noise_256_texture_sampler: sampler; // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // let color = vec4(f32(0)); // textureStore(texture, location, color); // } // Why are the characters so pixelated? // One possible reason is that we are in a compute shader and the textures are not // filtered. let backColorDebug: vec3 = vec3(0.2, 0.2, 0.2); var uv_debug: vec2 ; var tp_debug: vec2 ; var align_debug: vec4; // north, east, south, west var font_size_debug: f32; var dotColor_debug: vec3 = vec3(0.5, 0.5, 0.); var drawColorDebug: vec3 = vec3(1., 1., 0.); var vColor: vec3 = backColorDebug; var aspect_debug: f32 = 1.; var pixelPosDebug: vec2 = vec2(0., 0.); let FONT_SPACE_DEBUG: f32 = 0.5; let headColorDebug: vec3 = vec3(0.9, 0.6, 0.2); let mpColorDebug: vec3 = vec3(0.99, 0.99, 0.); let mxColorDebug: vec3 = vec3(1., 0., 0.); let myColorDebug: vec3 = vec3(0., 1., 0.); let font_png_size_debug: vec2 = vec2(1023.0, 1023.0); fn char(ch: i32) -> f32 { let fr = fract(floor(vec2(f32(ch), 15.999 - f32(ch) / 16.)) / 16.); let q = clamp(tp_debug, vec2(0.), vec2(1.)) / 16. + fr ; let inverted_q = vec2(q.x, 1. - q.y); // // There is aliasing on the characters // let f = textureSampleGrad(font_texture, // font_texture_sampler, // inverted_q, // vec2(1.0, 0.0), // vec2(0.0, 1.0)); // using textureLoad without sampler let q1 = vec2(font_png_size_debug * q ); let y_inverted_q1 = vec2(q1.x, i32(font_png_size_debug.y) - q1.y); var f: vec4 = textureLoad(font_texture, y_inverted_q1 , 0); // smoothing out the aliasing let dx = vec2(1, 0); let dy = vec2(0, 1); let fx1: vec4 = textureLoad(font_texture, y_inverted_q1 + dx, 0); let fx2: vec4 = textureLoad(font_texture, y_inverted_q1 - dx, 0); let fy1: vec4 = textureLoad(font_texture, y_inverted_q1 + dy, 0); let fy2: vec4 = textureLoad(font_texture, y_inverted_q1 - dy, 0); let rp = 0.25; f = f * rp + (1.0 - rp) * (fx1 + fx2 + fy1 + fy2) / 4.0 ; return f.x * (f.y + 0.3) * (f.z + 0.3) * 2.; } fn SetTextPosition(x: f32, y: f32) { tp_debug = 10. * uv_debug; tp_debug.x = tp_debug.x + 17. - x; tp_debug.y = tp_debug.y - 9.4 + y; } fn SetTextPositionAbs(x: f32, y: f32) { tp_debug.x = 10. * uv_debug.x - x; tp_debug.y = 10. * uv_debug.y - y; } fn drawFract(value: ptr, digits: ptr) -> f32 { var c: f32 = 0.; *value = fract(*value) * 10.; for (var ni: i32 = 1; ni < 60; ni = ni + 1) { c = c + (char(48 + i32(*value))); tp_debug.x = tp_debug.x - (0.5); *digits = *digits - (1); *value = fract(*value) * 10.; if (*digits <= 0 || *value == 0.) { break; } } tp_debug.x = tp_debug.x - (0.5 * f32(*digits)); return c; } fn maxInt(a: i32, b: i32) -> i32 { var ret: i32; if (a > b) { ret = a; } else { ret = b; }; return ret; } fn drawInt(value: ptr, minDigits: ptr) -> f32 { var c: f32 = 0.; if (*value < 0) { *value = -*value; if (*minDigits < 1) { *minDigits = 1; } else { *minDigits = *minDigits - 1; } c = c + (char(45)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); } var fn2: i32 = *value; var digits: i32 = 1; for (var ni: i32 = 0; ni < 10; ni = ni + 1) { fn2 = fn2 / (10); if (fn2 == 0) { break; } digits = digits + 1; } digits = maxInt(*minDigits, digits); tp_debug.x = tp_debug.x - (0.5 * f32(digits)); for (var ni: i32 = 1; ni < 11; ni = ni + 1) { tp_debug.x = tp_debug.x + (0.5); c = c + (char(48 + *value % 10)); *value = *value / (10); if (ni >= digits) { break; } } tp_debug.x = tp_debug.x - (0.5 * f32(digits)); return c; } fn drawIntBackwards(value: ptr, minDigits: ptr) -> f32 { var c: f32 = 0.; let original_value: i32 = *value; if (*value < 0) { *value = -*value; if (*minDigits < 1) { *minDigits = 1; } else { *minDigits = *minDigits - 1; } // tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); // c = c + (char(45)); } var fn2: i32 = *value; var digits: i32 = 1; for (var ni: i32 = 0; ni < 10; ni = ni + 1) { fn2 = fn2 / (10); if (fn2 == 0) { break; } digits = digits + 1; } digits = maxInt(*minDigits, digits); // tp_debug.x = tp_debug.x - (0.5 * f32(digits)); for (var ni: i32 = digits - 1; ni < 11; ni = ni - 1) { tp_debug.x = tp_debug.x + (0.5); c = c + (char(48 + *value % 10)); *value = *value / (10); if (ni == 0) { break; } } if (original_value < 0) { tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); c = c + (char(45)); } // tp_debug.x = tp_debug.x + (0.5 * f32(digits)); return c; } // fn drawFloat(value: ptr, prec: ptr, maxDigits: i32) -> f32 { fn drawFloat(val: f32, prec: ptr, maxDigits: i32) -> f32 { // in case of 0.099999..., round up to 0.1000000 var value = round(val * pow(10., f32(maxDigits))) / pow(10., f32(maxDigits)); let tp_debugx: f32 = tp_debug.x - 0.5 * f32(maxDigits); var c: f32 = 0.; if (value < 0.) { c = char(45); value = -value; } tp_debug.x = tp_debug.x - (0.5); var ival = i32(value); var one: i32 = 1; c = c + (drawInt(&ival, &one)); c = c + (char(46)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); var frac_val = fract(value); c = c + (drawFract(&frac_val, prec)); tp_debug.x = min(tp_debug.x, tp_debugx); return c; } fn drawFloat_f32(value: f32) -> f32 { var two: i32 = 2; return drawFloat(value, &two, 5); } fn drawFloat_f32_prec(value: f32, prec: ptr) -> f32 { return drawFloat(value, prec, 2); } fn drawInt_i32_back(value: ptr) -> f32 { var one: i32 = 1; return drawIntBackwards(value, &one); } fn drawInt_i32(value: ptr) -> f32 { var one: i32 = 1; return drawInt(value, &one); } fn SetColor(red: f32, green: f32, blue: f32) { drawColorDebug = vec3(red, green, blue); } fn WriteFloat(fValue: f32, maxDigits: i32, decimalPlaces: ptr) { // vColor = mix(vColor, drawColorDebug, drawFloat_f32_prec(fValue, decimalPlaces)); vColor = mix(vColor, drawColorDebug, drawFloat(fValue, decimalPlaces, maxDigits)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); ; } fn WriteFloatBox( fValue: f32, maxDigits: i32, decimalPlaces: i32, alpha: f32 ) { var decs = decimalPlaces; vColor = mix(vColor, drawColorDebug, drawFloat(fValue, &decs, maxDigits) * alpha); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); ; } fn WriteInteger(iValue: ptr) { vColor = mix(vColor, drawColorDebug, drawInt_i32(iValue)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); } fn WriteIntegerBack(iValue: ptr) { vColor = mix(vColor, drawColorDebug, drawInt_i32_back(iValue)); tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); } fn WriteFPS() { var fps: f32 = f32(uni.iSampleRate); SetColor(0.8, 0.6, 0.3); var max_digits_one = 1; WriteFloat(fps, 5, &max_digits_one); var c: f32 = 0.; c = c + (char(102)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(112)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(115)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); // let c2 = smoothStep(0.0, 1.0, c ); vColor = mix(vColor, drawColorDebug, c); } fn WriteMousePos(mPos: vec2, y_pos: f32) { let digits: i32 = 3; let radius: f32 = uni.iResolution.x / 400.; if (uni.iMouse.z > 0.) { dotColor_debug = mpColorDebug; } let r: f32 = length(abs(mPos.xy) - pixelPosDebug) - radius; // vColor = vColor + (mix(vec3(0.), dotColor_debug, 1. - clamp(r, 0., 1.))); var max_digits_three: i32 = 3; var mposxi: i32 = i32(mPos.x); var mposyi: i32 = i32(mPos.y); var mposx: f32 = (mPos.x); var mposy: f32 = (mPos.y); let x_pos = align_debug.y - 1. * FONT_SPACE_DEBUG; SetTextPositionAbs( x_pos, y_pos, ); drawColorDebug = myColorDebug; WriteIntegerBack(&mposyi); SetTextPositionAbs( x_pos - 7. * FONT_SPACE_DEBUG, y_pos, ); drawColorDebug = mxColorDebug; WriteIntegerBack(&mposxi); } fn sdRoundedBox(p: vec2, b: vec2, r: vec4) -> f32 { var x = r.x; var y = r.y; x = select(r.z, r.x, p.x > 0.); y = select(r.w, r.y, p.x > 0.); x = select(y, x, p.y > 0.); let q = abs(p) - b + x; return min(max(q.x, q.y), 0.) + length(max(q, vec2(0.))) - x; } fn WriteRGBAValues( location: vec2, value: vec4, screen_poz: vec2, alpha: f32, ) { let poz = screen_poz / uni.iResolution * 20. * vec2(aspect_debug, 1.0); let window_ajusted = uni.iResolution / vec2(960., 600.); let box_pos = vec2(align_debug.w, align_debug.x - FONT_SPACE_DEBUG ) / 10.; // let box_pos = mp; // // box location follows mouse position // let box_location = vec2( // uni.iMouse.x + 100. * window_ajusted.x / ( aspect_debug / 1.6 ) , // uni.iMouse.y - 48. * window_ajusted.y // ); let box_location = vec2( 100. * window_ajusted.x / ( aspect_debug / 1.6 ) , uni.iResolution.y - 60. * window_ajusted.y, ); let inverted_screen_poz = vec2(screen_poz.x, -screen_poz.y) ; // / vec2(aspect_debug, 1.) ; let d_box = sdRoundedBox( vec2(location) - box_location - inverted_screen_poz, vec2(73. / ( aspect_debug / 1.6 ), 75.) * window_ajusted, vec4(5.,5.,5.,5.) * 5.0 ); // let alpha = 0.225; let decimal_places = 3; SetColor(1., 1., 1.); var c: f32 = 0.; let lspace = 0.8; let bg_color = vec3(.8, .7, .9); vColor = mix( vColor, bg_color, (1.0 - step(0.0, d_box)) * alpha ); // red SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1.) - 0.0 + poz.y ) ; c = c + (char(114)); // r tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.r, 3, decimal_places, alpha ); // green SetTextPosition( 10. * ((box_pos.x +1. + lspace)) + poz.x, 10. * (-box_pos.y +1. ) + 1.0 + poz.y, ) ; c = c + (char(103)); // g tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.g, 3, decimal_places, alpha ); // blue SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1. ) + 2.0 + poz.y, ) ; c = c + (char(98)); // b tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.b, 4, decimal_places, alpha ); // alpha SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1. ) + 3.0 + poz.y, ) ; c = c + (char(97)); // a tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.a, 4, decimal_places, alpha ); vColor = mix(vColor, drawColorDebug, c * alpha); } fn sdSegment(p: vec2, a: vec2, b: vec2) -> f32 { let pa = p - a; let ba = b - a; let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.); return length(pa - ba * h); } fn ring(pos: vec2, radius: f32, thick: f32) -> f32 { return mix(1., 0., smoothStep(thick, thick + 0.01, abs(length(uv_debug - pos) - radius))); } fn sdCircle(p: vec2, c: vec2, r: f32) -> f32 { let d = length(p - c); return d - r; } fn draw_ring(location: vec2) { let mouse_click_poz = vec2(abs(uni.iMouse.z) , abs(uni.iMouse.w)); let alpha = 0.75; let ring_dist = sdCircle(vec2(location) , mouse_click_poz, 2.3); let d = smoothStep(0.5, 1.5, abs(ring_dist - 1.)); vColor = mix(vColor, headColorDebug, (1. - d) * alpha ); } fn draw_crossair(location: vec2) { let start = 5.0; let end = 20.; let segment1 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(start, 0.), vec2(end, 0.) ); let segment2 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(-start, 0.), vec2(-end, 0.) ); let segment3 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(0., start), vec2(0., end) ); let segment4 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(0., -start), vec2(0., -end) ); var alpha = 0.75; if (uni.iMouse.z > 0.) { alpha = 1.0; } let d = smoothStep(0.5, 1.5, segment1); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothStep(0.5, 1.5, segment2); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothStep(0.5, 1.5, segment3); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothStep(0.5, 1.5, segment4); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); } fn show_debug_info(location: vec2, color: vec3) -> vec4 { var fragCoord = vec2(f32(location.x), f32(location.y) ); vColor = color; aspect_debug = uni.iResolution.x / uni.iResolution.y; let ratio: vec2 = vec2(aspect_debug, 1.); pixelPosDebug = fragCoord.xy; // mousePosDebug = uni.iMouse.xy; uv_debug = (2. * fragCoord.xy / uni.iResolution.xy - 1.) * ratio; align_debug = 10. * vec4( 1., // North aspect_debug, // East -1., // South -aspect_debug, // West ); WriteMousePos(uni.iMouse.zw, align_debug.z + 2.0 * FONT_SPACE_DEBUG); // Click position WriteMousePos(uni.iMouse.xy, align_debug.z + 0.2 * FONT_SPACE_DEBUG); // Current mouse position var c: f32 = 0.; SetTextPositionAbs( align_debug.y - FONT_SPACE_DEBUG, align_debug.x - 2. * FONT_SPACE_DEBUG, ); SetColor(0.8, 0.8, 0.8); var resx = i32(uni.iResolution.x); var resy = i32(uni.iResolution.y); WriteIntegerBack(&resx); c = c + (char(28)); tp_debug.x = tp_debug.x + 0. * (FONT_SPACE_DEBUG); WriteIntegerBack(&resy); SetTextPositionAbs( align_debug.w - 1. * FONT_SPACE_DEBUG, align_debug.z - 0. * FONT_SPACE_DEBUG, ); WriteFPS(); SetColor(0.9, 0.7, 0.8); let fragColor = vec4(vColor, 1.); let poz = vec2(0., uni.iResolution.y / 2.); // // RGBA probe labels follow mouse // let poz = vec2(uni.iMouse.x , uni.iResolution.y - uni.iMouse.y); let inverted_y_mouse_location = vec2(vec2(uni.iMouse.x, uni.iResolution.y - uni.iMouse.y)); let value: vec4 = textureLoad(texture, inverted_y_mouse_location); WriteRGBAValues(location, value, poz, 0.85); let inverted_y_mouseclick_location = vec2(vec2(abs(uni.iMouse.z), uni.iResolution.y - abs(uni.iMouse.w))); let value2: vec4 = textureLoad(texture, inverted_y_mouseclick_location); WriteRGBAValues(location, value2, vec2(0.), 0.65); draw_crossair(location); draw_ring(location); let fragColor = vec4(vColor, 1.); return fragColor; } let PI = 3.14159265; let dt = 2.5; let border_h = 5.; let h = 1.; let mass = 1.; let fluid_rho = 0.5; // let dif = 1.12; var R: vec2; var Mouse: vec4; var time: f32; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; // return length(max(d, 0.)) + min(max(d.x, d.y), 0.); return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } // uint pack(vec2 x) // { // x = 65534.0*clamp(0.5*x+0.5, 0., 1.); // return uint(round(x.x)) + 65535u*uint(round(x.y)); // } // fn unpack(a: u32) -> vec2 { // var x: vec2 = vec2(f32(a) % 65535., f32(a) / 65535.); // return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; // } // vec2 unpack(uint a) // { // vec2 x = vec2(a % 65535u, a / 65535u); // return clamp(x/65534.0, 0.,1.)*2.0 - 1.0; // } // fn decode(x: f32) -> vec2 { // var X: u32 = floatBitsToUint(x); // return unpack(X); // } // fn encode(x: vec2) -> f32 { // var X: u32 = pack(x); // return uintBitsToFloat(X); // } // fn decode(&self, place: u8, precision: u8) -> f32 { // let value_u32 = self >> (place - precision); // let mut mask = u32::MAX; // if precision < 32 { // mask = (1 << (precision)) - 1; // } // // println!("mask: {:#0b}", value_u32); // let masked_value_u32 = value_u32 & mask; // let value_f32 = masked_value_u32 as f32 / ((1u32 << (precision - 1u8)) as f32); // value_f32 // } fn pack(xIn: vec2) -> u32 { var x = xIn; let x = 65534. * clamp(0.5 * x + 0.5, vec2(0.00), vec2(1.0)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } fn decode2(input: u32, place: u32, precision: u32) -> f32 { let value_u32 = input >> (place - precision); var mask: u32 = 4294967295u; if (precision < 32u) { mask = (1u << precision) - 1u; } let masked_value_u32 = value_u32 & mask; let max_val = 1u << (precision - 1u); let value_f32 = f32(masked_value_u32) / f32(max_val) ; return value_f32; } fn decode1uToVec2(q: f32) -> vec2 { let uq = u32(q); let x = decode2(uq, 32u, 16u); let y = decode2(uq, 16u, 16u); return vec2(x, y) * 2. - 1.; } fn encode2(value: f32, input2: u32, place: u32, precision: u32) -> u32 { var input = input2; // let value_f32_normalized = value * f32(1u, 32u << (precision - 1u)) ; let value_f32_normalized = value * f32((1u << (precision - 1u))); let delta_bits = u32(place - precision); let value_u32 = u32(value_f32_normalized) << delta_bits; var mask: u32 = 0u; if (precision < 32u) { mask = 4294967295u - (((1u << precision) - 1u) << (place - precision)); } let input = (input2 & mask) | value_u32; return input; } fn encodeVec2To1u(value: vec2) -> u32 { var input: u32 = 0u; let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0)); let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0)); input = encode2(x, input, 32u, 16u); input = encode2(y, input, 16u, 16u); return input; } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle; P.X = decode1uToVec2(data.x) + pos; P.V = decode1uToVec2(data.y); P.M = data.zw; return P; } fn saveParticle(PIn: particle, pos: vec2) -> vec4 { var P: particle = PIn; P.X = clamp(P.X - pos, vec2(-0.5), vec2(0.5)); return vec4( f32(encodeVec2To1u(P.X)), f32(encodeVec2To1u(P.V)), P.M ); } // fn getParticle(data: vec4, pos: vec2) -> particle { // var P: particle = particle( // decode(data.x) + pos, // decode(data.y), // data.zw // ); // return P; // } // fn saveParticle(P: particle, pos: vec2) -> vec4 { // var P2: particle = particle(P.X, P.V, P.M); // P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); // return vec4(encode(P2.X), encode(P2.V), P2.M); // } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(0.1031, 0.103, 0.0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } struct particle { X: vec2; V: vec2; M: vec2; }; // fn fromLinear(linearRGB: vec4) -> vec4 { // let cutoff: vec4 = vec4(linearRGB < vec4(0.0031308)); // let higher: vec4 = vec4(1.055) * pow(linearRGB, vec4(1.0 / 2.4)) - vec4(0.055); // let lower: vec4 = linearRGB * vec4(12.92); // return mix(higher, lower, cutoff); // } // Converts a color from sRGB gamma to linear light gamma fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } // https://www.shadertoy.com/view/WtfyDj // no license // https://michaelmoroz.github.io/Reintegration-Tracking/ fn mixN(a: vec3, b: vec3, k: f32) -> vec3 { return sqrt(mix(a * a, b * b, clamp(k, 0., 1.))); } fn V(p: vec2) -> vec4 { let data: vec4 = textureLoad(buffer_c, vec2(p)); // let data: vec4 = textureSampleLevel(buffer_c, buffer_sampler, p / R, 0.0); // let data: vec4 = textureSampleGrad(buffer_c, // buffer_sampler, // p / R, // vec2(0.0), // vec2(0.0)) ; return data; } fn border(p: vec2, R2: vec2) -> f32 { let bound: f32 = -sdBox(p - R2 * 0.5, R2 * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time) * (p - R2 * vec2(0.5, 0.6)), R2 * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R2 * vec2(0.5, 0.7), R2 * vec2(1.5, 0.5)); return max(drain, min(bound, box)); } fn bN(p: vec2, R2: vec2) -> vec3 { let dx: vec3 = vec3(-h, 0., h); let idx: vec4 = vec4(-1. / h, 0., 1. / h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy, R2) + idx.xyw * border(p + dx.xy, R2) + idx.yzw * border(p + dx.yz, R2) + idx.yxw * border(p + dx.yx, R2); return vec3(normalize(r.xy), r.z + 1.0e-4); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { R = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var col: vec4; var pos = vec2(f32(location.x), f32(location.y)) ; // let Mouse = uni.iMouse; time = uni.iTime; let p: vec2 = vec2(pos); let data: vec4 = textureLoad(buffer_a, location); var P: particle = getParticle(data, pos); let Nb: vec3 = bN(P.X, R); let bord: f32 = smoothStep(2. * border_h, border_h * 0.5, border(pos, R)); let rho: vec4 = V(pos); let dx: vec3 = vec3(-2., 0., 2.); let grad: vec4 = -0.5 * vec4(V(pos + dx.zy).zw - V(pos + dx.xy).zw, V(pos + dx.yz).zw - V(pos + dx.yx).zw); let N: vec2 = pow(length(grad.xz), 0.2) * normalize(grad.xz + 0.00001); let specular: f32 = pow(max(dot(N, Dir(1.4)), 0.), 3.5); let specularb: f32 = G(0.4 * (Nb.zz - border_h)) * pow(max(dot(Nb.xy, Dir(1.4)), 0.), 3.); let a: f32 = pow(smoothStep(fluid_rho * 0., fluid_rho * 2., rho.z), 0.1); let b: f32 = exp(-1.7 * smoothStep(fluid_rho * 1., fluid_rho * 7.5, rho.z)); let col0: vec3 = vec3(1., 0.5, 0.); let col1: vec3 = vec3(0.1, 0.4, 1.); let fcol: vec3 = mixN(col0, col1, tanh(3. * (rho.w - 0.7)) * 0.5 + 0.5); col = vec4(3.); var colxyz = col.xyz; colxyz = mixN(col.xyz, fcol.xyz * (1.5 * b + specular * 5.), a); col.x = colxyz.x; col.y = colxyz.y; col.z = colxyz.z; var colxyz = col.xyz; colxyz = mixN(col.xyz, 0. * vec3(0.5, 0.5, 1.), bord); col.x = colxyz.x; col.y = colxyz.y; col.z = colxyz.z; var colxyz = col.xyz; colxyz = tanh(col.xyz); col.x = colxyz.x; col.y = colxyz.y; col.z = colxyz.z; // let bufa: vec4 = textureLoad(buffer_a, location); // var col2 = vec4(0.2, 0.6, 0.9, 1.0); // var col2 = vec4(0.3, 0.5, 0.29, 1.0); // if (y_inverted_location.x > i32(R.x / 2.0)) { // let v = vec2(0.3, 0.5) * 2.0; // let u = f32(encodeVec2To1u(v)); // let back = decode1uToVec2(u) / 2.0; // col2 = vec4(back.x, back.y, 0.29, 1.0); // } // let data2: vec4 = (textureLoad(buffer_a, location) ) ; // var pb: particle = getParticle(data2, pos); // let v2 = (pb.X - pos + 1.0) / 2.; // let v2 = (pb.M ) / 1.; // let debug = vec4(v2.x, 0.0, 0.0, 1.0); // if (Mouse.z > 0.5) { // col = debug; // } let col_debug_info = show_debug_info(location, col.xyz); // textureStore(texture, y_inverted_location, toLinear(debug)); // textureStore(texture, y_inverted_location, toLinear(col)); textureStore(texture, y_inverted_location, toLinear(col_debug_info)); } ================================================ FILE: assets/shaders/preludes/image_prelude ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iResolution: vec2; iMouse: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; // change to vec4 when possible }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; {{IMAGE_CODE}} ================================================ FILE: assets/shaders/protean_clouds/buffer_a.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); } ================================================ FILE: assets/shaders/protean_clouds/buffer_b.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/protean_clouds/buffer_c.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/protean_clouds/buffer_d.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/protean_clouds/image.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @group(0) @binding(5) var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; @group(0) @binding(6) var font_texture: texture_2d; @group(0) @binding(7) var font_texture_sampler: sampler; @group(0) @binding(8) var rgba_noise_256_texture: texture_2d; @group(0) @binding(9) var rgba_noise_256_texture_sampler: sampler; @group(0) @binding(10) var blue_noise_texture: texture_2d; @group(0) @binding(11) var blue_noise_texture_sampler: sampler; // https://www.shadertoy.com/view/3l23Rh // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License fn rot(a: f32) -> mat2x2 { let c: f32 = cos(a); let s: f32 = sin(a); return mat2x2(vec2(c, s), vec2(-s, c)); } let m3: mat3x3 = mat3x3( vec3(0.64342, 1.08146, -1.38607), vec3(-1.696, 0.6302, -0.2957), vec3(0.2926, 1.3432, 1.1838) ); fn mag2(p: vec2) -> f32 { return dot(p, p); } fn linstep(mn: f32, mx: f32, x: f32) -> f32 { return clamp((x - mn) / (mx - mn), 0., 1.); } var prm1: f32 = 0.; var bsMo: vec2 = vec2(0., 0.); fn disp(t: f32) -> vec2 { return vec2(sin(t * 0.22) * 1., cos(t * 0.175) * 1.) * 2.; } fn map(p_in: vec3) -> vec2 { var p = p_in; var p2: vec3 = p; var p2xy = p2.xy; p2xy = p2.xy - (disp(p.z).xy); p2.x = p2xy.x; p2.y = p2xy.y; var pxy = p.xy; pxy = p.xy * (rot(sin(p.z + uni.iTime) * (0.1 + prm1 * 0.05) + uni.iTime * 0.09)); p.x = pxy.x; p.y = pxy.y; let cl: f32 = mag2(p2.xy); var d: f32 = 0.; p = p * (0.61); var z: f32 = 1.; var trk: f32 = 1.; var dspAmp: f32 = 0.1 + prm1 * 0.2; for (var i: i32 = 0; i < 5; i = i + 1) { p = p + (sin(p.zxy * 0.75 * trk + uni.iTime * trk * 0.8) * dspAmp); d = d - (abs(dot(cos(p), sin(p.yzx)) * z)); z = z * (0.57); trk = trk * (1.4); p = p * m3; } d = abs(d + prm1 * 3.) + prm1 * 0.3 - 2.5 + bsMo.y; return vec2(d + cl * 0.2 + 0.25, cl); } fn render(ro: vec3, rd: vec3, time: f32) -> vec4 { var rez: vec4 = vec4(0.); let ldst: f32 = 8.; let lpos: vec3 = vec3(disp(time + ldst) * 0.5, time + ldst); var t: f32 = 1.5; var fogT: f32 = 0.; for (var i: i32 = 0; i < 130; i = i + 1) { if (rez.a > 0.99) { break; } let pos: vec3 = ro + t * rd; let mpv: vec2 = map(pos); let den: f32 = clamp(mpv.x - 0.3, 0., 1.) * 1.12; let dn: f32 = clamp(mpv.x + 2., 0., 3.); var col: vec4 = vec4(0.); if (mpv.x > 0.6) { col = vec4(sin(vec3(5., 0.4, 0.2) + mpv.y * 0.1 + sin(pos.z * 0.4) * 0.5 + 1.8) * 0.5 + 0.5, 0.08); col = col * (den * den * den); var colrgb = col.rgb; colrgb = col.rgb * (linstep(4., -2.5, mpv.x) * 2.3); col.r = colrgb.r; col.g = colrgb.g; col.b = colrgb.b; var dif: f32 = clamp((den - map(pos + 0.8).x) / 9., 0.001, 1.); dif = dif + (clamp((den - map(pos + 0.35).x) / 2.5, 0.001, 1.)); var colxyz = col.xyz; colxyz = col.xyz * (den * (vec3(0.005, 0.045, 0.075) + 1.5 * vec3(0.033, 0.07, 0.03) * dif)); col.x = colxyz.x; col.y = colxyz.y; col.z = colxyz.z; } let fogC: f32 = exp(t * 0.2 - 2.2); var colrgba = col.rgba; colrgba = col.rgba + (vec4(0.06, 0.11, 0.11, 0.1) * clamp(fogC - fogT, 0., 1.)); col.r = colrgba.r; col.g = colrgba.g; col.b = colrgba.b; col.a = colrgba.a; fogT = fogC; rez = rez + col * (1. - rez.a); t = t + (clamp(0.5 - dn * dn * 0.05, 0.09, 0.3)); } return clamp(rez, vec4(0.), vec4(1.)); } fn getsat(c: vec3) -> f32 { let mi: f32 = min(min(c.x, c.y), c.z); let ma: f32 = max(max(c.x, c.y), c.z); return (ma - mi) / (ma + 0.0000001); } fn iLerp(a: vec3, b: vec3, x: f32) -> vec3 { var ic: vec3 = mix(a, b, x) + vec3(0.000001, 0., 0.); let sd: f32 = abs(getsat(ic) - mix(getsat(a), getsat(b), x)); let dir: vec3 = normalize(vec3(2. * ic.x - ic.y - ic.z, 2. * ic.y - ic.x - ic.z, 2. * ic.z - ic.y - ic.x)); let lgt: f32 = dot(vec3(1.), ic); let ff: f32 = dot(dir, normalize(ic)); ic = ic + (1.5 * dir * sd * ff * lgt); return clamp(ic, vec3(0.), vec3(1.)); } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var fragColor: vec4; var fragCoord = vec2(f32(location.x), f32(location.y) ); let q: vec2 = fragCoord.xy / uni.iResolution.xy; let p: vec2 = (fragCoord - 0.5 * uni.iResolution.xy) / uni.iResolution.y; bsMo = (uni.iMouse.xy - 0.5 * uni.iResolution.xy) / uni.iResolution.y; let time: f32 = uni.iTime * 3.; var ro: vec3 = vec3(0., 0., time); ro = ro + (vec3(sin(uni.iTime) * 0.5, sin(uni.iTime * 1.) * 0., 0.)); let dspAmp: f32 = 0.85; var roxy = ro.xy; roxy = ro.xy + (disp(ro.z) * dspAmp); ro.x = roxy.x; ro.y = roxy.y; let tgtDst: f32 = 3.5; let targt: vec3 = normalize(ro - vec3(disp(time + tgtDst) * dspAmp, time + tgtDst)); ro.x = ro.x - (bsMo.x * 2.); var rightdir: vec3 = normalize(cross(targt, vec3(0., 1., 0.))); let updir: vec3 = normalize(cross(rightdir, targt)); rightdir = normalize(cross(updir, targt)); var rd: vec3 = normalize((p.x * rightdir + p.y * updir) * 1. - targt); var rdxy = rd.xy; rdxy = rd.xy * (rot(-disp(time + 3.5).x * 0.2 + bsMo.x)); rd.x = rdxy.x; rd.y = rdxy.y; prm1 = smoothstep(-0.4, 0.4, sin(uni.iTime * 0.3)); let scn: vec4 = render(ro, rd, time); var col: vec3 = scn.rgb; col = iLerp(col.bgr, col.rgb, clamp(1. - prm1, 0.05, 1.)); col = pow(col, vec3(0.55, 0.65, 0.6)) * vec3(1., 0.97, 0.9); col = col * (pow(16. * q.x * q.y * (1. - q.x) * (1. - q.y), 0.12) * 0.7 + 0.3); fragColor = vec4(col, 1.); textureStore(texture, location, fragColor); } ================================================ FILE: assets/shaders/seascape/buffer_a.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let color = vec4(0.5); textureStore(buffer_a, location, color); } ================================================ FILE: assets/shaders/seascape/buffer_b.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/seascape/buffer_c.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/seascape/buffer_d.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/seascape/image.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @group(0) @binding(5) var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; @group(0) @binding(6) var font_texture: texture_2d; @group(0) @binding(7) var font_texture_sampler: sampler; @group(0) @binding(8) var rgba_noise_256_texture: texture_2d; @group(0) @binding(9) var rgba_noise_256_texture_sampler: sampler; @group(0) @binding(10) var blue_noise_texture: texture_2d; @group(0) @binding(11) var blue_noise_texture_sampler: sampler; // https://www.shadertoy.com/view/Ms2SD1 // Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. let NUM_STEPS: i32 = 8; let PI: f32 = 3.141592; let EPSILON: f32 = 0.001; let ITER_GEOMETRY: i32 = 3; let ITER_FRAGMENT: i32 = 5; let SEA_HEIGHT: f32 = 0.6; let SEA_CHOPPY: f32 = 4.; let SEA_SPEED: f32 = 0.8; let SEA_FREQ: f32 = 0.16; let SEA_BASE: vec3 = vec3(0., 0.09, 0.18); let SEA_WATER_COLOR: vec3 = vec3(0.48, 0.54, 0.36); let octave_m: mat2x2 = mat2x2(vec2(1.6, 1.2), vec2(-1.2, 1.6)); fn fromEuler(ang: vec3) -> mat3x3 { let a1: vec2 = vec2(sin(ang.x), cos(ang.x)); let a2: vec2 = vec2(sin(ang.y), cos(ang.y)); let a3: vec2 = vec2(sin(ang.z), cos(ang.z)); var m: mat3x3; m[0] = vec3(a1.y * a3.y + a1.x * a2.x * a3.x, a1.y * a2.x * a3.x + a3.y * a1.x, -a2.y * a3.x); m[1] = vec3(-a2.y * a1.x, a1.y * a2.y, a2.x); m[2] = vec3(a3.y * a1.x * a2.x + a1.y * a3.x, a1.x * a3.x - a1.y * a3.y * a2.x, a2.y * a3.y); return m; } fn hash(p: vec2) -> f32 { let h: f32 = dot(p, vec2(127.1, 311.7)); return fract(sin(h) * 43758.547); } fn noise(p: vec2) -> f32 { let i: vec2 = floor(p); let f: vec2 = fract(p); let u: vec2 = f * f * (3. - 2. * f); return -1. + 2. * mix(mix(hash(i + vec2(0., 0.)), hash(i + vec2(1., 0.)), u.x), mix(hash(i + vec2(0., 1.)), hash(i + vec2(1., 1.)), u.x), u.y); } fn diffuse(n: vec3, l: vec3, p: f32) -> f32 { return pow(dot(n, l) * 0.4 + 0.6, p); } fn specular(n: vec3, l: vec3, e: vec3, s: f32) -> f32 { let nrm: f32 = (s + 8.) / (PI * 8.); return pow(max(dot(reflect(e, n), l), 0.), s) * nrm; } fn getSkyColor(e: vec3) -> vec3 { var e_var = e; e_var.y = (max(e_var.y, 0.) * 0.8 + 0.2) * 0.8; return vec3(pow(1. - e_var.y, 2.), 1. - e_var.y, 0.6 + (1. - e_var.y) * 0.4) * 1.1; } fn sea_octave(uv: vec2, choppy: f32) -> f32 { var uv_var = uv; uv_var = uv_var + (noise(uv_var)); var wv: vec2 = 1. - abs(sin(uv_var)); let swv: vec2 = abs(cos(uv_var)); wv = mix(wv, swv, wv); return pow(1. - pow(wv.x * wv.y, 0.65), choppy); } fn map(p: vec3) -> f32 { var freq: f32 = SEA_FREQ; var amp: f32 = SEA_HEIGHT; var choppy: f32 = SEA_CHOPPY; var uv: vec2 = p.xz; uv.x = uv.x * (0.75); var d: f32; var h: f32 = 0.; for (var i: i32 = 0; i < ITER_GEOMETRY; i = i + 1) { d = sea_octave((uv + (1. + uni.iTime * SEA_SPEED)) * freq, choppy); d = d + (sea_octave((uv - (1. + uni.iTime * SEA_SPEED)) * freq, choppy)); h = h + (d * amp); uv = uv * (octave_m); freq = freq * (1.9); amp = amp * (0.22); choppy = mix(choppy, 1., 0.2); } return p.y - h; } fn map_detailed(p: vec3) -> f32 { var freq: f32 = SEA_FREQ; var amp: f32 = SEA_HEIGHT; var choppy: f32 = SEA_CHOPPY; var uv: vec2 = p.xz; uv.x = uv.x * (0.75); var d: f32; var h: f32 = 0.; for (var i: i32 = 0; i < ITER_FRAGMENT; i = i + 1) { d = sea_octave((uv + (1. + uni.iTime * SEA_SPEED)) * freq, choppy); d = d + (sea_octave((uv - (1. + uni.iTime * SEA_SPEED)) * freq, choppy)); h = h + (d * amp); uv = uv * (octave_m); freq = freq * (1.9); amp = amp * (0.22); choppy = mix(choppy, 1., 0.2); } return p.y - h; } fn getSeaColor(p: vec3, n: vec3, l: vec3, eye: vec3, dist: vec3) -> vec3 { var fresnel: f32 = clamp(1. - dot(n, -eye), 0., 1.); fresnel = pow(fresnel, 3.) * 0.5; let reflected: vec3 = getSkyColor(reflect(eye, n)); let refracted: vec3 = SEA_BASE + diffuse(n, l, 80.) * SEA_WATER_COLOR * 0.12; var color: vec3 = mix(refracted, reflected, fresnel); let atten: f32 = max(1. - dot(dist, dist) * 0.001, 0.); color = color + (SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten); color = color + (vec3(specular(n, l, eye, 60.))); return color; } fn getNormal(p: vec3, eps: f32) -> vec3 { var n: vec3; n.y = map_detailed(p); n.x = map_detailed(vec3(p.x + eps, p.y, p.z)) - n.y; n.z = map_detailed(vec3(p.x, p.y, p.z + eps)) - n.y; n.y = eps; return normalize(n); } fn heightMapTracing(ori: vec3, dir: vec3, p: ptr>) -> f32 { var p_var: vec3; var tm: f32 = 0.; var tx: f32 = 1000.; var hx: f32 = map(ori + dir * tx); if (hx > 0.) { p_var = ori + dir * tx; return tx; } var hm: f32 = map(ori + dir * tm); var tmid: f32 = 0.; for (var i: i32 = 0; i < NUM_STEPS; i = i + 1) { tmid = mix(tm, tx, hm / (hm - hx)); p_var = ori + dir * tmid; let hmid: f32 = map(p_var); if (hmid < 0.) { tx = tmid; hx = hmid; } else { tm = tmid; hm = hmid; } } *p = p_var; return tmid; } fn getPixel(coord: vec2, time: f32) -> vec3 { var uv: vec2 = coord / uni.iResolution.xy; uv = uv * 2. - 1.; uv.x = uv.x * (uni.iResolution.x / uni.iResolution.y); let ang: vec3 = vec3(sin(time * 3.) * 0.1, sin(time) * 0.2 + 0.3, time); let ori: vec3 = vec3(0., 3.5, time * 5.); var dir: vec3 = normalize(vec3(uv.xy, -2.)); dir.z = dir.z + (length(uv) * 0.14); dir = normalize(dir) * fromEuler(ang); var p: vec3; heightMapTracing(ori, dir, &p); let dist: vec3 = p - ori; let n: vec3 = getNormal(p, dot(dist, dist) * (0.1 / uni.iResolution.x)); let light: vec3 = normalize(vec3(0., 1., 0.8)); return mix(getSkyColor(dir), getSeaColor(p, n, light, dir, dist), pow(smoothstep(0., -0.02, dir.y), 0.2)); } fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var fragColor: vec4; var fragCoord = vec2(f32(location.x), f32(location.y) ); let time: f32 = uni.iTime * 0.3 + uni.iMouse.x * 0.01; // var color: vec3 = vec3(0.); // for (var i: i32 = -1; i <= 1; i = i + 1) { // for (var j: i32 = -1; j <= 1; j = j + 1) { // let uv2: vec2 = fragCoord + vec2(f32(i), f32(j)) / 3.; // color = color + (getPixel(uv2, time)); // } // } // color = color / (9.); var color: vec3 = getPixel(fragCoord, time); fragColor = vec4(pow(color, vec3(0.65)), 1.); // fragColor = vec4(1.); // fragColor = getSkyColor(location); // let col_debug_info = show_debug_info(location, fragColor.xyz); textureStore(texture, y_inverted_location, toLinear(fragColor)); } ================================================ FILE: assets/shaders/simpler_particles/buffer_a.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; // RUST_LOG="wgpu=error,naga=warn,info" cargo run --release --example simpler_particles var R: vec2; var Mouse: vec4; var time: f32; var s0: vec4; // let particle_size: f32 = 10.5; let particle_size: f32 = 2.5; let relax_value: f32 = 0.3; fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { var d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn border(p: vec2) -> f32 { let bound: f32 = -sdBox(p - R * 0.5, R * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time - 0.) * (p - R * vec2(0.5, 0.6)), R * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R * vec2(0.5, 0.7), R * vec2(1.5, 0.5)); // return bound - 15.; // return min(bound, box); return max(drain, min(bound, box)); } fn bN(p: vec2) -> vec3 { var dx: vec3 = vec3(-1., 0., 1.); let idx: vec4 = vec4(-1. / 1., 0., 1. / 1., 0.25); var r: vec3 = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx); return vec3(normalize(r.xy), r.z + 0.0001); } // fn decode(x: f32) -> vec2 { // var X: u32 = floatBitsToUint(x); // return unpackHalf2x16(X); // } // fn encode(x: vec2) -> f32 { // var X: u32 = packHalf2x16(x); // return uintBitsToFloat(X); // } fn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 { var input = input2; // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ; let value_f32_normalized = value * f32((1u << (precis - 1u))); let delta_bits = u32(place - precis); let value_u32 = u32(value_f32_normalized) << delta_bits; var mask: u32 = 0u; if (precis < 32u) { mask = 4294967295u - (((1u << precis) - 1u) << (place - precis)); } let input = (input2 & mask) | value_u32; return input; } fn encodeVec2To1u(value: vec2) -> u32 { var input: u32 = 0u; let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0)); let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0)); input = encode2(x, input, 32u, 16u); input = encode2(y, input, 16u, 16u); return input; } fn decode2(input: u32, place: u32, precis: u32) -> f32 { let value_u32 = input >> (place - precis); var mask: u32 = 4294967295u; if (precis < 32u) { mask = (1u << precis) - 1u; } let masked_value_u32 = value_u32 & mask; let max_val = 1u << (precis - 1u); let value_f32 = f32(masked_value_u32) / f32(max_val) ; return value_f32; } fn decode1uToVec2(q: f32) -> vec2 { let uq = u32(q); let x = decode2(uq, 32u, 16u); let y = decode2(uq, 16u, 16u); return vec2(x, y) * 2. - 1.; } struct particle { X: vec2, NX: vec2, R: f32, M: f32, }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle; P.X = decode1uToVec2(data.x) + pos; P.NX = decode1uToVec2(data.y) + pos; P.R = data.z; P.M = data.w; return P; } fn saveParticle(P_in: particle, pos: vec2) -> vec4 { var P = P_in; P.X = P.X - pos; P.NX = P.NX - pos; return vec4( f32(encodeVec2To1u(P.X)), f32(encodeVec2To1u(P.NX)), P.R, P.M ); } fn rng_initialize(p: vec2, frame: i32) { s0 = vec4(u32(p.x), u32(p.y), u32(frame), u32(p.x) + u32(p.y)); } // // https://www.pcg-random.org/ // void pcg4d(inout uvec4 v) // { // v = v * 1664525u + 1013904223u; // v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z; // v = v ^ (v>>16u); // v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z; // } fn pcg4d(v: ptr>) { (*v) = (*v) * 1664525u + 1013904223u; (*v).x = (*v).x + ((*v).y * (*v).w); (*v).y = (*v).y + ((*v).z * (*v).x); (*v).z = (*v).z + ((*v).x * (*v).y); (*v).w = (*v).w + ((*v).y * (*v).z); let v2 = vec4((*v).x >> 16u, (*v).y >> 16u, (*v).z >> 16u, (*v).w >> 16u); (*v) = (*v) ^ v2; // (*v) = (*v) ^ ((*v) >> 16u); (*v).x = (*v).x + ((*v).y * (*v).w); (*v).y = (*v).y + ((*v).z * (*v).x); (*v).z = (*v).z + ((*v).x * (*v).y); (*v).w = (*v).w + ((*v).y * (*v).z); } fn rand() -> f32 { pcg4d(&s0); return f32(s0.x) / f32(4294967300.); } fn rand2() -> vec2 { pcg4d(&s0); return vec2(s0.xy) / f32(4294967300.); } fn rand3() -> vec3 { pcg4d(&s0); return vec3(s0.xyz) / f32(4294967300.); } fn rand4() -> vec4 { pcg4d(&s0); return vec4(s0) / f32(4294967300.); } fn Simulation( ch: texture_storage_2d, P: ptr, pos: vec2 ) { var F: vec2 = vec2(0.); var I: i32 = i32(ceil(particle_size)); // var I: i32 = 4; for (var i: i32 = -I; i <= I; i = i + 1) { for (var j: i32 = -I; j <= I; j = j + 1) { if (i == 0 && j == 0) { continue; } let tpos: vec2 = pos + vec2(f32(i), f32(j)); let data: vec4 = textureLoad(ch, vec2(tpos)); let P0: particle = getParticle(data, tpos); if (P0.M == 0.) { continue; } let dx: vec2 = P0.NX - (*P).NX; var d: f32 = length(dx); var r: f32 = (*P).R + P0.R; var m: f32 = 1. / (*P).M / (1. / (*P).M + 1. / P0.M) * 2.; m = ((*P).M - P0.M) / ((*P).M + P0.M) + 2. * P0.M / ((*P).M + P0.M); m = P0.M / ((*P).M + P0.M); if (d < r) { F = F - (normalize(dx) * (r - d) * m); } } } let dp: vec2 = (*P).NX; var d: f32 = border(dp); if (d < 0.) { F = F - (bN(dp).xy * d); } (*P).NX = (*P).NX + (F * 0.9 / 3.); } // RUST_LOG="wgpu=error,naga=warn,info" cargo run --release --example simpler_particles // RUST_LOG="wgpu=error,naga=warn,info" cargo run --release --example simpler_particles fn Integrate( ch: texture_storage_2d, P: ptr, pos: vec2 ) { var I: i32 = 3; for (var i: i32 = -I; i <= I; i = i + 1) { for (var j: i32 = -I; j <= I; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(j)); let data: vec4 = textureLoad(ch, vec2(tpos)); if (tpos.x < 0. || tpos.y < 0.) { continue; } var P0: particle = getParticle(data, tpos); if ( (P0.NX.x >= pos.x - 0.5 && P0.NX.x < pos.x + 0.5) && (P0.NX.y >= pos.y - 0.5) && (P0.NX.y < pos.y + 0.5) && (P0.M > 0.5) ) { var P0V: vec2 = (P0.NX - P0.X) / 2.; if (uni.iMouse.z > 0.) { let dm: vec2 = P0.NX - uni.iMouse.xy; let d: f32 = length(dm / 50.); P0V = P0V + (normalize(dm) * exp(-d * d) * 0.3); } P0V = P0V + (vec2(0., -0.005)); let v: f32 = length(P0V); var denom = 1.; if (v > 1.) { denom = v; } P0V = P0V / denom; P0.X = P0.NX; P0.NX = P0.NX + P0V * 2.; (*P) = P0; break; } } } } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { // let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // var U: vec4; var pos = vec2(f32(location.x), f32(location.y) ); R = uni.iResolution.xy; rng_initialize(pos, i32(uni.iFrame)); var P: particle; Integrate(buffer_d, &P, pos); // if (uni.iFrame == 0) { #ifdef INIT if (rand() > 0.992) { P.X = pos; P.NX = pos + (rand2() - 0.5) * 0.; let r: f32 = pow(rand(), 2.); P.M = mix(1., 4., r); P.R = mix(1., particle_size * 0.5, r); } else { P.X = pos; P.NX = pos; P.M = 0.; P.R = particle_size * 0.5; } // } #endif let U = saveParticle(P, pos); textureStore(buffer_a, location, U); } ================================================ FILE: assets/shaders/simpler_particles/buffer_b.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; // RUST_LOG="wgpu=error,naga=warn,info" cargo run --release --example simpler_particles var R: vec2; var Mouse: vec4; var time: f32; var s0: vec4; // let particle_size: f32 = 10.5; let particle_size: f32 = 2.5; let relax_value: f32 = 0.3; fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { var d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn border(p: vec2) -> f32 { let bound: f32 = -sdBox(p - R * 0.5, R * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time - 0.) * (p - R * vec2(0.5, 0.6)), R * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R * vec2(0.5, 0.7), R * vec2(1.5, 0.5)); // return bound - 15.; // return min(bound, box); return max(drain, min(bound, box)); } fn bN(p: vec2) -> vec3 { var dx: vec3 = vec3(-1., 0., 1.); let idx: vec4 = vec4(-1. / 1., 0., 1. / 1., 0.25); var r: vec3 = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx); return vec3(normalize(r.xy), r.z + 0.0001); } // fn decode(x: f32) -> vec2 { // var X: u32 = floatBitsToUint(x); // return unpackHalf2x16(X); // } // fn encode(x: vec2) -> f32 { // var X: u32 = packHalf2x16(x); // return uintBitsToFloat(X); // } fn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 { var input = input2; // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ; let value_f32_normalized = value * f32((1u << (precis - 1u))); let delta_bits = u32(place - precis); let value_u32 = u32(value_f32_normalized) << delta_bits; var mask: u32 = 0u; if (precis < 32u) { mask = 4294967295u - (((1u << precis) - 1u) << (place - precis)); } let input = (input2 & mask) | value_u32; return input; } fn encodeVec2To1u(value: vec2) -> u32 { var input: u32 = 0u; let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0)); let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0)); input = encode2(x, input, 32u, 16u); input = encode2(y, input, 16u, 16u); return input; } fn decode2(input: u32, place: u32, precis: u32) -> f32 { let value_u32 = input >> (place - precis); var mask: u32 = 4294967295u; if (precis < 32u) { mask = (1u << precis) - 1u; } let masked_value_u32 = value_u32 & mask; let max_val = 1u << (precis - 1u); let value_f32 = f32(masked_value_u32) / f32(max_val) ; return value_f32; } fn decode1uToVec2(q: f32) -> vec2 { let uq = u32(q); let x = decode2(uq, 32u, 16u); let y = decode2(uq, 16u, 16u); return vec2(x, y) * 2. - 1.; } struct particle { X: vec2, NX: vec2, R: f32, M: f32, }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle; P.X = decode1uToVec2(data.x) + pos; P.NX = decode1uToVec2(data.y) + pos; P.R = data.z; P.M = data.w; return P; } fn saveParticle(P_in: particle, pos: vec2) -> vec4 { var P = P_in; P.X = P.X - pos; P.NX = P.NX - pos; return vec4( f32(encodeVec2To1u(P.X)), f32(encodeVec2To1u(P.NX)), P.R, P.M ); } fn rng_initialize(p: vec2, frame: i32) { s0 = vec4(u32(p.x), u32(p.y), u32(frame), u32(p.x) + u32(p.y)); } // // https://www.pcg-random.org/ // void pcg4d(inout uvec4 v) // { // v = v * 1664525u + 1013904223u; // v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z; // v = v ^ (v>>16u); // v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z; // } fn pcg4d(v: ptr>) { (*v) = (*v) * 1664525u + 1013904223u; (*v).x = (*v).x + ((*v).y * (*v).w); (*v).y = (*v).y + ((*v).z * (*v).x); (*v).z = (*v).z + ((*v).x * (*v).y); (*v).w = (*v).w + ((*v).y * (*v).z); let v2 = vec4((*v).x >> 16u, (*v).y >> 16u, (*v).z >> 16u, (*v).w >> 16u); (*v) = (*v) ^ v2; // (*v) = (*v) ^ ((*v) >> 16u); (*v).x = (*v).x + ((*v).y * (*v).w); (*v).y = (*v).y + ((*v).z * (*v).x); (*v).z = (*v).z + ((*v).x * (*v).y); (*v).w = (*v).w + ((*v).y * (*v).z); } fn rand() -> f32 { pcg4d(&s0); return f32(s0.x) / f32(4294967300.); } fn rand2() -> vec2 { pcg4d(&s0); return vec2(s0.xy) / f32(4294967300.); } fn rand3() -> vec3 { pcg4d(&s0); return vec3(s0.xyz) / f32(4294967300.); } fn rand4() -> vec4 { pcg4d(&s0); return vec4(s0) / f32(4294967300.); } fn Simulation( ch: texture_storage_2d, P: ptr, pos: vec2 ) { var F: vec2 = vec2(0.); var I: i32 = i32(ceil(particle_size)); // var I: i32 = 4; for (var i: i32 = -I; i <= I; i = i + 1) { for (var j: i32 = -I; j <= I; j = j + 1) { if (i == 0 && j == 0) { continue; } let tpos: vec2 = pos + vec2(f32(i), f32(j)); let data: vec4 = textureLoad(ch, vec2(tpos)); let P0: particle = getParticle(data, tpos); if (P0.M == 0.) { continue; } let dx: vec2 = P0.NX - (*P).NX; var d: f32 = length(dx); var r: f32 = (*P).R + P0.R; var m: f32 = 1. / (*P).M / (1. / (*P).M + 1. / P0.M) * 2.; m = ((*P).M - P0.M) / ((*P).M + P0.M) + 2. * P0.M / ((*P).M + P0.M); m = P0.M / ((*P).M + P0.M); if (d < r) { F = F - (normalize(dx) * (r - d) * m); } } } let dp: vec2 = (*P).NX; var d: f32 = border(dp); if (d < 0.) { F = F - (bN(dp).xy * d); } (*P).NX = (*P).NX + (F * 0.9 / 3.); } // RUST_LOG="wgpu=error,naga=warn,info" cargo run --release --example simpler_particles @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { // let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // var U: vec4; var pos = vec2(f32(location.x), f32(location.y) ); R = uni.iResolution.xy; time = uni.iTime; Mouse = uni.iMouse; let data: vec4 = textureLoad(buffer_a, vec2(pos)); var P: particle = getParticle(data, pos); if (P.M > 0.) { Simulation(buffer_a, &P, pos); } let U = saveParticle(P, pos); textureStore(buffer_b, location, U); } ================================================ FILE: assets/shaders/simpler_particles/buffer_c.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; // RUST_LOG="wgpu=error,naga=warn,info" cargo run --release --example simpler_particles var R: vec2; var Mouse: vec4; var time: f32; var s0: vec4; // let particle_size: f32 = 10.5; let particle_size: f32 = 2.5; let relax_value: f32 = 0.3; fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { var d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn border(p: vec2) -> f32 { let bound: f32 = -sdBox(p - R * 0.5, R * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time - 0.) * (p - R * vec2(0.5, 0.6)), R * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R * vec2(0.5, 0.7), R * vec2(1.5, 0.5)); // return bound - 15.; // return min(bound, box); return max(drain, min(bound, box)); } fn bN(p: vec2) -> vec3 { var dx: vec3 = vec3(-1., 0., 1.); let idx: vec4 = vec4(-1. / 1., 0., 1. / 1., 0.25); var r: vec3 = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx); return vec3(normalize(r.xy), r.z + 0.0001); } // fn decode(x: f32) -> vec2 { // var X: u32 = floatBitsToUint(x); // return unpackHalf2x16(X); // } // fn encode(x: vec2) -> f32 { // var X: u32 = packHalf2x16(x); // return uintBitsToFloat(X); // } fn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 { var input = input2; // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ; let value_f32_normalized = value * f32((1u << (precis - 1u))); let delta_bits = u32(place - precis); let value_u32 = u32(value_f32_normalized) << delta_bits; var mask: u32 = 0u; if (precis < 32u) { mask = 4294967295u - (((1u << precis) - 1u) << (place - precis)); } let input = (input2 & mask) | value_u32; return input; } fn encodeVec2To1u(value: vec2) -> u32 { var input: u32 = 0u; let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0)); let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0)); input = encode2(x, input, 32u, 16u); input = encode2(y, input, 16u, 16u); return input; } fn decode2(input: u32, place: u32, precis: u32) -> f32 { let value_u32 = input >> (place - precis); var mask: u32 = 4294967295u; if (precis < 32u) { mask = (1u << precis) - 1u; } let masked_value_u32 = value_u32 & mask; let max_val = 1u << (precis - 1u); let value_f32 = f32(masked_value_u32) / f32(max_val) ; return value_f32; } fn decode1uToVec2(q: f32) -> vec2 { let uq = u32(q); let x = decode2(uq, 32u, 16u); let y = decode2(uq, 16u, 16u); return vec2(x, y) * 2. - 1.; } struct particle { X: vec2, NX: vec2, R: f32, M: f32, }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle; P.X = decode1uToVec2(data.x) + pos; P.NX = decode1uToVec2(data.y) + pos; P.R = data.z; P.M = data.w; return P; } fn saveParticle(P_in: particle, pos: vec2) -> vec4 { var P = P_in; P.X = P.X - pos; P.NX = P.NX - pos; return vec4( f32(encodeVec2To1u(P.X)), f32(encodeVec2To1u(P.NX)), P.R, P.M ); } fn rng_initialize(p: vec2, frame: i32) { s0 = vec4(u32(p.x), u32(p.y), u32(frame), u32(p.x) + u32(p.y)); } // // https://www.pcg-random.org/ // void pcg4d(inout uvec4 v) // { // v = v * 1664525u + 1013904223u; // v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z; // v = v ^ (v>>16u); // v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z; // } fn pcg4d(v: ptr>) { (*v) = (*v) * 1664525u + 1013904223u; (*v).x = (*v).x + ((*v).y * (*v).w); (*v).y = (*v).y + ((*v).z * (*v).x); (*v).z = (*v).z + ((*v).x * (*v).y); (*v).w = (*v).w + ((*v).y * (*v).z); let v2 = vec4((*v).x >> 16u, (*v).y >> 16u, (*v).z >> 16u, (*v).w >> 16u); (*v) = (*v) ^ v2; // (*v) = (*v) ^ ((*v) >> 16u); (*v).x = (*v).x + ((*v).y * (*v).w); (*v).y = (*v).y + ((*v).z * (*v).x); (*v).z = (*v).z + ((*v).x * (*v).y); (*v).w = (*v).w + ((*v).y * (*v).z); } fn rand() -> f32 { pcg4d(&s0); return f32(s0.x) / f32(4294967300.); } fn rand2() -> vec2 { pcg4d(&s0); return vec2(s0.xy) / f32(4294967300.); } fn rand3() -> vec3 { pcg4d(&s0); return vec3(s0.xyz) / f32(4294967300.); } fn rand4() -> vec4 { pcg4d(&s0); return vec4(s0) / f32(4294967300.); } fn Simulation( ch: texture_storage_2d, P: ptr, pos: vec2 ) { var F: vec2 = vec2(0.); var I: i32 = i32(ceil(particle_size)); // var I: i32 = 4; for (var i: i32 = -I; i <= I; i = i + 1) { for (var j: i32 = -I; j <= I; j = j + 1) { if (i == 0 && j == 0) { continue; } let tpos: vec2 = pos + vec2(f32(i), f32(j)); let data: vec4 = textureLoad(ch, vec2(tpos)); let P0: particle = getParticle(data, tpos); if (P0.M == 0.) { continue; } let dx: vec2 = P0.NX - (*P).NX; var d: f32 = length(dx); var r: f32 = (*P).R + P0.R; var m: f32 = 1. / (*P).M / (1. / (*P).M + 1. / P0.M) * 2.; m = ((*P).M - P0.M) / ((*P).M + P0.M) + 2. * P0.M / ((*P).M + P0.M); m = P0.M / ((*P).M + P0.M); if (d < r) { F = F - (normalize(dx) * (r - d) * m); } } } let dp: vec2 = (*P).NX; var d: f32 = border(dp); if (d < 0.) { F = F - (bN(dp).xy * d); } (*P).NX = (*P).NX + (F * 0.9 / 3.); } // RUST_LOG="wgpu=error,naga=warn,info" cargo run --release --example simpler_particles @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { // let R: vec2 = uni.iResolution.xy; // let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // var U: vec4; var pos = vec2(f32(location.x), f32(location.y) ); R = uni.iResolution.xy; time = uni.iTime; Mouse = uni.iMouse; let data: vec4 = textureLoad(buffer_b, vec2(pos)); var P: particle = getParticle(data, pos); if (P.M > 0.) { Simulation(buffer_b, &P, pos); } let U = saveParticle(P, pos); textureStore(buffer_c, location, U); } ================================================ FILE: assets/shaders/simpler_particles/buffer_d.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; // RUST_LOG="wgpu=error,naga=warn,info" cargo run --release --example simpler_particles var R: vec2; var Mouse: vec4; var time: f32; var s0: vec4; // let particle_size: f32 = 10.5; let particle_size: f32 = 2.5; let relax_value: f32 = 0.3; fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { var d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn border(p: vec2) -> f32 { let bound: f32 = -sdBox(p - R * 0.5, R * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time - 0.) * (p - R * vec2(0.5, 0.6)), R * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R * vec2(0.5, 0.7), R * vec2(1.5, 0.5)); // return bound - 15.; // return min(bound, box); return max(drain, min(bound, box)); } fn bN(p: vec2) -> vec3 { var dx: vec3 = vec3(-1., 0., 1.); let idx: vec4 = vec4(-1. / 1., 0., 1. / 1., 0.25); var r: vec3 = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx); return vec3(normalize(r.xy), r.z + 0.0001); } // fn decode(x: f32) -> vec2 { // var X: u32 = floatBitsToUint(x); // return unpackHalf2x16(X); // } // fn encode(x: vec2) -> f32 { // var X: u32 = packHalf2x16(x); // return uintBitsToFloat(X); // } fn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 { var input = input2; // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ; let value_f32_normalized = value * f32((1u << (precis - 1u))); let delta_bits = u32(place - precis); let value_u32 = u32(value_f32_normalized) << delta_bits; var mask: u32 = 0u; if (precis < 32u) { mask = 4294967295u - (((1u << precis) - 1u) << (place - precis)); } let input = (input2 & mask) | value_u32; return input; } fn encodeVec2To1u(value: vec2) -> u32 { var input: u32 = 0u; let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0)); let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0)); input = encode2(x, input, 32u, 16u); input = encode2(y, input, 16u, 16u); return input; } fn decode2(input: u32, place: u32, precis: u32) -> f32 { let value_u32 = input >> (place - precis); var mask: u32 = 4294967295u; if (precis < 32u) { mask = (1u << precis) - 1u; } let masked_value_u32 = value_u32 & mask; let max_val = 1u << (precis - 1u); let value_f32 = f32(masked_value_u32) / f32(max_val) ; return value_f32; } fn decode1uToVec2(q: f32) -> vec2 { let uq = u32(q); let x = decode2(uq, 32u, 16u); let y = decode2(uq, 16u, 16u); return vec2(x, y) * 2. - 1.; } struct particle { X: vec2, NX: vec2, R: f32, M: f32, }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle; P.X = decode1uToVec2(data.x) + pos; P.NX = decode1uToVec2(data.y) + pos; P.R = data.z; P.M = data.w; return P; } fn saveParticle(P_in: particle, pos: vec2) -> vec4 { var P = P_in; P.X = P.X - pos; P.NX = P.NX - pos; return vec4( f32(encodeVec2To1u(P.X)), f32(encodeVec2To1u(P.NX)), P.R, P.M ); } fn rng_initialize(p: vec2, frame: i32) { s0 = vec4(u32(p.x), u32(p.y), u32(frame), u32(p.x) + u32(p.y)); } // // https://www.pcg-random.org/ // void pcg4d(inout uvec4 v) // { // v = v * 1664525u + 1013904223u; // v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z; // v = v ^ (v>>16u); // v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z; // } fn pcg4d(v: ptr>) { (*v) = (*v) * 1664525u + 1013904223u; (*v).x = (*v).x + ((*v).y * (*v).w); (*v).y = (*v).y + ((*v).z * (*v).x); (*v).z = (*v).z + ((*v).x * (*v).y); (*v).w = (*v).w + ((*v).y * (*v).z); let v2 = vec4((*v).x >> 16u, (*v).y >> 16u, (*v).z >> 16u, (*v).w >> 16u); (*v) = (*v) ^ v2; // (*v) = (*v) ^ ((*v) >> 16u); (*v).x = (*v).x + ((*v).y * (*v).w); (*v).y = (*v).y + ((*v).z * (*v).x); (*v).z = (*v).z + ((*v).x * (*v).y); (*v).w = (*v).w + ((*v).y * (*v).z); } fn rand() -> f32 { pcg4d(&s0); return f32(s0.x) / f32(4294967300.); } fn rand2() -> vec2 { pcg4d(&s0); return vec2(s0.xy) / f32(4294967300.); } fn rand3() -> vec3 { pcg4d(&s0); return vec3(s0.xyz) / f32(4294967300.); } fn rand4() -> vec4 { pcg4d(&s0); return vec4(s0) / f32(4294967300.); } fn Simulation( ch: texture_storage_2d, P: ptr, pos: vec2 ) { var F: vec2 = vec2(0.); var I: i32 = i32(ceil(particle_size)); // var I: i32 = 4; for (var i: i32 = -I; i <= I; i = i + 1) { for (var j: i32 = -I; j <= I; j = j + 1) { if (i == 0 && j == 0) { continue; } let tpos: vec2 = pos + vec2(f32(i), f32(j)); let data: vec4 = textureLoad(ch, vec2(tpos)); let P0: particle = getParticle(data, tpos); if (P0.M == 0.) { continue; } let dx: vec2 = P0.NX - (*P).NX; var d: f32 = length(dx); var r: f32 = (*P).R + P0.R; var m: f32 = 1. / (*P).M / (1. / (*P).M + 1. / P0.M) * 2.; m = ((*P).M - P0.M) / ((*P).M + P0.M) + 2. * P0.M / ((*P).M + P0.M); m = P0.M / ((*P).M + P0.M); if (d < r) { F = F - (normalize(dx) * (r - d) * m); } } } let dp: vec2 = (*P).NX; var d: f32 = border(dp); if (d < 0.) { F = F - (bN(dp).xy * d); } (*P).NX = (*P).NX + (F * 0.9 / 3.); } // RUST_LOG="wgpu=error,naga=warn,info" cargo run --release --example simpler_particles @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { // let R: vec2 = uni.iResolution.xy; // let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // var U: vec4; var pos = vec2(f32(location.x), f32(location.y) ); R = uni.iResolution.xy; time = uni.iTime; Mouse = uni.iMouse; let data: vec4 = textureLoad(buffer_c, vec2(pos)); var P: particle = getParticle(data, pos); if (P.M > 0.) { Simulation(buffer_c, &P, pos); } let U = saveParticle(P, pos); textureStore(buffer_d, location, U); } ================================================ FILE: assets/shaders/simpler_particles/image.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @group(0) @binding(5) var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; @group(0) @binding(6) var font_texture: texture_2d; @group(0) @binding(7) var font_texture_sampler: sampler; @group(0) @binding(8) var rgba_noise_256_texture: texture_2d; @group(0) @binding(9) var rgba_noise_256_texture_sampler: sampler; @group(0) @binding(10) var blue_noise_texture: texture_2d; @group(0) @binding(11) var blue_noise_texture_sampler: sampler; // RUST_LOG="wgpu=error,naga=warn,info" cargo run --release --example simpler_particles var R: vec2; var Mouse: vec4; var time: f32; var s0: vec4; // let particle_size: f32 = 10.5; let particle_size: f32 = 2.5; let relax_value: f32 = 0.3; fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { var d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn border(p: vec2) -> f32 { let bound: f32 = -sdBox(p - R * 0.5, R * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time - 0.) * (p - R * vec2(0.5, 0.6)), R * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R * vec2(0.5, 0.7), R * vec2(1.5, 0.5)); // return bound - 15.; // return min(bound, box); return max(drain, min(bound, box)); } fn bN(p: vec2) -> vec3 { var dx: vec3 = vec3(-1., 0., 1.); let idx: vec4 = vec4(-1. / 1., 0., 1. / 1., 0.25); var r: vec3 = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx); return vec3(normalize(r.xy), r.z + 0.0001); } // fn decode(x: f32) -> vec2 { // var X: u32 = floatBitsToUint(x); // return unpackHalf2x16(X); // } // fn encode(x: vec2) -> f32 { // var X: u32 = packHalf2x16(x); // return uintBitsToFloat(X); // } fn encode2(value: f32, input2: u32, place: u32, precis: u32) -> u32 { var input = input2; // let value_f32_normalized = value * f32(1u, 32u << (precis - 1u)) ; let value_f32_normalized = value * f32((1u << (precis - 1u))); let delta_bits = u32(place - precis); let value_u32 = u32(value_f32_normalized) << delta_bits; var mask: u32 = 0u; if (precis < 32u) { mask = 4294967295u - (((1u << precis) - 1u) << (place - precis)); } let input = (input2 & mask) | value_u32; return input; } fn encodeVec2To1u(value: vec2) -> u32 { var input: u32 = 0u; let x = clamp(0.5 * value.x + 0.5, (0.00), (1.0)); let y = clamp(0.5 * value.y + 0.5, (0.00), (1.0)); input = encode2(x, input, 32u, 16u); input = encode2(y, input, 16u, 16u); return input; } fn decode2(input: u32, place: u32, precis: u32) -> f32 { let value_u32 = input >> (place - precis); var mask: u32 = 4294967295u; if (precis < 32u) { mask = (1u << precis) - 1u; } let masked_value_u32 = value_u32 & mask; let max_val = 1u << (precis - 1u); let value_f32 = f32(masked_value_u32) / f32(max_val) ; return value_f32; } fn decode1uToVec2(q: f32) -> vec2 { let uq = u32(q); let x = decode2(uq, 32u, 16u); let y = decode2(uq, 16u, 16u); return vec2(x, y) * 2. - 1.; } struct particle { X: vec2, NX: vec2, R: f32, M: f32, }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle; P.X = decode1uToVec2(data.x) + pos; P.NX = decode1uToVec2(data.y) + pos; P.R = data.z; P.M = data.w; return P; } fn saveParticle(P_in: particle, pos: vec2) -> vec4 { var P = P_in; P.X = P.X - pos; P.NX = P.NX - pos; return vec4( f32(encodeVec2To1u(P.X)), f32(encodeVec2To1u(P.NX)), P.R, P.M ); } fn rng_initialize(p: vec2, frame: i32) { s0 = vec4(u32(p.x), u32(p.y), u32(frame), u32(p.x) + u32(p.y)); } // // https://www.pcg-random.org/ // void pcg4d(inout uvec4 v) // { // v = v * 1664525u + 1013904223u; // v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z; // v = v ^ (v>>16u); // v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z; // } fn pcg4d(v: ptr>) { (*v) = (*v) * 1664525u + 1013904223u; (*v).x = (*v).x + ((*v).y * (*v).w); (*v).y = (*v).y + ((*v).z * (*v).x); (*v).z = (*v).z + ((*v).x * (*v).y); (*v).w = (*v).w + ((*v).y * (*v).z); let v2 = vec4((*v).x >> 16u, (*v).y >> 16u, (*v).z >> 16u, (*v).w >> 16u); (*v) = (*v) ^ v2; // (*v) = (*v) ^ ((*v) >> 16u); (*v).x = (*v).x + ((*v).y * (*v).w); (*v).y = (*v).y + ((*v).z * (*v).x); (*v).z = (*v).z + ((*v).x * (*v).y); (*v).w = (*v).w + ((*v).y * (*v).z); } fn rand() -> f32 { pcg4d(&s0); return f32(s0.x) / f32(4294967300.); } fn rand2() -> vec2 { pcg4d(&s0); return vec2(s0.xy) / f32(4294967300.); } fn rand3() -> vec3 { pcg4d(&s0); return vec3(s0.xyz) / f32(4294967300.); } fn rand4() -> vec4 { pcg4d(&s0); return vec4(s0) / f32(4294967300.); } fn Simulation( ch: texture_storage_2d, P: ptr, pos: vec2 ) { var F: vec2 = vec2(0.); var I: i32 = i32(ceil(particle_size)); // var I: i32 = 4; for (var i: i32 = -I; i <= I; i = i + 1) { for (var j: i32 = -I; j <= I; j = j + 1) { if (i == 0 && j == 0) { continue; } let tpos: vec2 = pos + vec2(f32(i), f32(j)); let data: vec4 = textureLoad(ch, vec2(tpos)); let P0: particle = getParticle(data, tpos); if (P0.M == 0.) { continue; } let dx: vec2 = P0.NX - (*P).NX; var d: f32 = length(dx); var r: f32 = (*P).R + P0.R; var m: f32 = 1. / (*P).M / (1. / (*P).M + 1. / P0.M) * 2.; m = ((*P).M - P0.M) / ((*P).M + P0.M) + 2. * P0.M / ((*P).M + P0.M); m = P0.M / ((*P).M + P0.M); if (d < r) { F = F - (normalize(dx) * (r - d) * m); } } } let dp: vec2 = (*P).NX; var d: f32 = border(dp); if (d < 0.) { F = F - (bN(dp).xy * d); } (*P).NX = (*P).NX + (F * 0.9 / 3.); } // RUST_LOG="wgpu=error,naga=warn,info" cargo run --release --example simpler_particles @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { R = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var col: vec4; var pos = vec2(f32(location.x), f32(location.y) ); R = uni.iResolution.xy; time = uni.iTime; var colxyz = col.xyz; colxyz = vec3(1.); col.x = colxyz.x; col.y = colxyz.y; col.z = colxyz.z; var d: f32 = 100.; var c: vec3 = vec3(1.); var m: f32 = 1.; var I: i32 = i32(ceil(particle_size * 0.5)) + 2; for (var i: i32 = -I; i <= I; i = i + 1) { for (var j: i32 = -I; j <= I; j = j + 1) { var tpos: vec2 = pos + vec2(f32(i), f32(j)); var data: vec4 = textureLoad(buffer_d, vec2(tpos)); var P0: particle = getParticle(data, tpos); if (P0.M == 0.) { continue; } var nd: f32 = distance(pos, P0.NX) - P0.R; if (nd < d) { let V: vec2 = (P0.NX - P0.X) * 1. / 2.; c = vec3(V * 0.5 + 0.5, (P0.M - 1.) / 3.); c = mix(vec3(1.), c, length(V)); m = P0.M; } d = min(d, nd); if (d < 0.) { break; } } } var s: f32 = 100.; let off: vec2 = vec2(5., 5.); if (d > 0. && i32(pos.x) % 2 == 0 && i32(pos.y) % 2 == 0) { for (var i: i32 = -I; i <= I; i = i + 1) { for (var j: i32 = -I; j <= I; j = j + 1) { let tpos: vec2 = pos - off + vec2(f32(i), f32(j)); let data: vec4 = textureLoad(buffer_d, vec2(tpos)); let P0: particle = getParticle(data, tpos); if (tpos.x < 0. || tpos.x > R.x || tpos.y < 0. || tpos.y > R.x) { s = 0.; break; } if (P0.M == 0.) { continue; } let nd: f32 = distance(pos - off, P0.NX) - P0.R; s = min(s, nd); } } } if (d < 0.) { d = sin(d); } var colxyz = col.xyz; colxyz = vec3(abs(d)); col.x = colxyz.x; col.y = colxyz.y; col.z = colxyz.z; if (d < 0.) { var colxyz = col.xyz; colxyz = col.xyz * (c); col.x = colxyz.x; col.y = colxyz.y; col.z = colxyz.z; var colxyz = col.xyz; colxyz = col.xyz / (0.4 + m * 0.25); col.x = colxyz.x; col.y = colxyz.y; col.z = colxyz.z; } var colxyz = col.xyz; colxyz = clamp(col.xyz, vec3(0.), vec3(1.)); col.x = colxyz.x; col.y = colxyz.y; col.z = colxyz.z; if (d > 0.) { var colxyz = col.xyz; colxyz = col.xyz * (mix(vec3(0.5), vec3(1.), clamp(s, 0., 1.))); col.x = colxyz.x; col.y = colxyz.y; col.z = colxyz.z; } if (pos.x < 3.) || (pos.x > R.x - 3.) || (pos.y < 3.) || (pos.y > R.y - 3.) { var colxyz = col.xyz; colxyz = vec3(0.5); col.x = colxyz.x; col.y = colxyz.y; col.z = colxyz.z; } // col = vec4(1.0, 0.0, 0.0, 1.0); col.w = 1.0; textureStore(texture, y_inverted_location, col); } ================================================ FILE: assets/shaders/simplest_detailed_fluid/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_a, location, color); } // https://www.shadertoy.com/view/7t3SDf fn t(i: vec2, location: vec2) -> vec4 { let O: vec4 = textureLoad(buffer_a, i + location ); return O; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { var location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // location = location + vec2(10); var r: vec4 = vec4(0.); for (var i: vec2 = vec2(-7); i.x < 7; i.x = i.x + 1 ) { for (i.y = -7; i.y < 7; i.y = i.y + 1 ) { let ii = i + 1; let a = 0; let v: vec2 = t(ii , location + a ).xy; let what = t(ii, location + a).z ; let fi = vec2(ii); r = r + ( what * exp(-dot(v+fi, v+fi)) / 3.14 * vec4(mix(v+v+fi , v, t(ii, location + a ).z), 1., 1.) ); } } r.x = r.x / (r.z+0.000001); r.y = r.y / (r.z+0.000001); if (i32(uni.iFrame) % 500 == 1) { let u = vec2(location +0) ; let m: vec2 = 4.*u/vec2(uni.iResolution.xy) - 2.; r = r + (vec4(m, 1., 0.)*exp(-dot(m, m))); } textureStore(buffer_a, location , r); } ================================================ FILE: assets/shaders/simplest_detailed_fluid/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_b, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_b, location, vec4(0.85)); // if (uni.iTime > 1.0) { // textureStore(buffer_b, location, vec4(0.95)); // } } ================================================ FILE: assets/shaders/simplest_detailed_fluid/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_c, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_c, location, vec4(0.95)); // if (uni.iTime > 1.0) { // textureStore(buffer_c, location, vec4(0.95)); // } } ================================================ FILE: assets/shaders/simplest_detailed_fluid/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let color = vec4(0.60); textureStore(buffer_d, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_d, location, vec4(0.7)); if (uni.iTime > 1.0) { storageBarrier(); textureStore(buffer_d, location, vec4(0.95)); } // storageBarrier(); } ================================================ FILE: assets/shaders/simplest_detailed_fluid/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; fn hash(value: u32) -> u32 { var state = value; state = state ^ 2747636419u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; return state; } fn randomFloat(value: u32) -> f32 { return f32(hash(value)) / 4294967295.0; } [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let randomNumber = randomFloat(invocation_id.y * num_workgroups.x + invocation_id.x); let alive = randomNumber > 0.9; let color = vec4(f32(alive)); textureStore(texture, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // var alive = true; // let value: vec4 = textureLoad(buffer_a, vec2(0,1)); // if (value.x > 0.79) { // alive = false; // } let r = 1.- textureLoad(buffer_a, location ).zzzz; storageBarrier(); textureStore(texture, location, r); // textureStore(texture, location, vec4(f32(alive))); } ================================================ FILE: assets/shaders/soul/buffer_a.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let color = vec4(0.5); textureStore(buffer_a, location, color); } ================================================ FILE: assets/shaders/soul/buffer_b.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/soul/buffer_c.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/soul/buffer_d.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { } ================================================ FILE: assets/shaders/soul/image.wgsl ================================================ struct CommonUniform { iResolution: vec2, changed_window_size: f32, padding0: f32, iTime: f32, iTimeDelta: f32, iFrame: f32, iSampleRate: f32, iMouse: vec4, iChannelTime: vec4, iChannelResolution: vec4, iDate: vec4, }; @group(0) @binding(0) var uni: CommonUniform; @group(0) @binding(1) var buffer_a: texture_storage_2d; @group(0) @binding(2) var buffer_b: texture_storage_2d; @group(0) @binding(3) var buffer_c: texture_storage_2d; @group(0) @binding(4) var buffer_d: texture_storage_2d; @group(0) @binding(5) var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; @group(0) @binding(6) var font_texture: texture_2d; @group(0) @binding(7) var font_texture_sampler: sampler; @group(0) @binding(8) var rgba_noise_256_texture: texture_2d; @group(0) @binding(9) var rgba_noise_256_texture_sampler: sampler; @group(0) @binding(10) var blue_noise_texture: texture_2d; @group(0) @binding(11) var blue_noise_texture_sampler: sampler; // https://www.shadertoy.com/view/3ltyRB // by leon // License Attribution-NonCommercial 2.0 Generic (CC BY-NC 2.0) struct Volume { dist: f32, mate: i32, density: f32, space: f32, }; fn select2(a: Volume, b: Volume) -> Volume { if (a.dist < b.dist) { return a; } return b; } let mat_eye_globe: i32 = 1; let mat_pupils: i32 = 2; let mat_eyebrows: i32 = 3; let mat_iris: i32 = 4; let mat_glass: i32 = 5; fn rot(a: f32) -> mat2x2 { let c: f32 = cos(a); var s: f32 = sin(a); return mat2x2(c, -s, s, c); } fn hash12(p: vec2) -> f32 { var p3: vec3 = fract(vec3(p.xyx) * 0.1031); p3 = p3 + (dot(p3, p3.yzx + 33.33)); return fract((p3.x + p3.y) * p3.z); } fn sdBox(p: vec3, b: vec3) -> f32 { var q: vec3 = abs(p) - b; return length(max(q, vec3(0.))) + min(max(q.x, max(q.y, q.z)), 0.); } fn opSmoothUnion(d1: f32, d2: f32, k: f32) -> f32 { var h: f32 = clamp(0.5 + 0.5 * (d2 - d1) / k, 0., 1.); return mix(d2, d1, h) - k * h * (1. - h); } fn opSmoothSubtraction(d1: f32, d2: f32, k: f32) -> f32 { var h: f32 = clamp(0.5 - 0.5 * (d2 + d1) / k, 0., 1.); return mix(d2, -d1, h) + k * h * (1. - h); } fn opSmoothIntersection(d1: f32, d2: f32, k: f32) -> f32 { let h: f32 = clamp(0.5 - 0.5 * (d2 - d1) / k, 0., 1.); return mix(d2, d1, h) + k * h * (1. - h); } fn sdCappedTorus(p2: vec3, sc: vec2, ra: f32, rb: f32) -> f32 { var p = p2; p.x = abs(p.x); var k: f32 = 0.; if (sc.y * p.x > sc.x * p.y) { k = dot(p.xy, sc); } else { k = length(p.xy); }; return sqrt(dot(p, p) + ra * ra - 2. * ra * k) - rb; } fn sdVerticalCapsule(p2: vec3, h: f32, r: f32) -> f32 { var p = p2; p.y = p.y - (clamp(p.y, 0., h)); return length(p) - r; } fn sdCappedCone(p: vec3, a: vec3, b: vec3, ra: f32, rb: f32) -> f32 { let rba: f32 = rb - ra; let baba: f32 = dot(b - a, b - a); let papa: f32 = dot(p - a, p - a); let paba: f32 = dot(p - a, b - a) / baba; let x: f32 = sqrt(papa - paba * paba * baba); var rab: f32; if (paba < 0.5) { rab = ra; } else { rab = rb; } let cax: f32 = max(0., x - rab); var cay: f32 = abs(paba - 0.5) - 0.5; let k: f32 = rba * rba + baba; let f: f32 = clamp((rba * (x - ra) + paba * baba) / k, 0., 1.); var cbx: f32 = x - ra - f * rba; let cby: f32 = paba - f; var s: f32; if (cbx < 0. && cay < 0.) { s = -1.; } else { s = 1.; }; return s * sqrt(min(cax * cax + cay * cay * baba, cbx * cbx + cby * cby * baba)); } fn sdRoundedCylinder(p: vec3, ra: f32, rb: f32, h: f32) -> f32 { let d: vec2 = vec2(length(p.xz) - 2. * ra + rb, abs(p.y) - h); return min(max(d.x, d.y), 0.) + length(max(d, vec2(0.))) - rb; } fn sdRoundBox(p: vec3, b: vec3, r: f32) -> f32 { let q: vec3 = abs(p) - b; return length(max(q, vec3(0.))) + min(max(q.x, max(q.y, q.z)), 0.) - r; } var ao_pass: bool = false; fn map2(pos_in: vec3) -> Volume { var pos = pos_in; var shape: f32 = 100.; var poszy = pos.zy; poszy = pos.zy * (rot(sin(pos.y * 0.2 + uni.iTime) * 0.1 + 0.2)); pos.z = poszy.x; pos.y = poszy.y; var posyx = pos.yx; posyx = pos.yx * (rot(0.1 * sin(pos.y * 0.3 + uni.iTime))); pos.y = posyx.x; pos.x = posyx.y; var p: vec3 = pos; var ghost: Volume; ghost.mate = 0; ghost.density = 0.05; ghost.space = 0.12; var opaque: Volume; opaque.mate = 0; opaque.density = 1.; opaque.space = 0.; var hair: Volume; hair.mate = mat_eyebrows; hair.density = 0.2; hair.space = 0.1; var glass: Volume; glass.mate = mat_glass; glass.density = 0.15; glass.space = 0.1; glass.dist = 0.; ghost.dist = length(p * vec3(1., 0.9, 1.)) - 1.; ghost.dist = opSmoothUnion(ghost.dist, length(p - vec3(0., 1.2, 0.)) - 0.55, 0.35); p.z = p.z + (1.3); var pyz = p.yz; pyz = p.yz * (rot(p.z * 0.5 + 0.1 * sin(uni.iTime + p.z * 4.))); p.y = pyz.x; p.z = pyz.y; shape = sdBox(p, vec3(1., 0.01, 1.)); shape = max(shape, -length(pos.xz) + 0.99); ghost.dist = opSmoothSubtraction(shape, ghost.dist, 0.1); p = pos - vec3(0., 1.6, 0.); shape = sdRoundedCylinder(p + sin(p.z * 4.) * 0.03, 0.4, 0.01, 0.01); shape = min(shape, sdCappedCone(p + 0.05 * sin(p.z * 8.), vec3(0., 0.5, 0.), vec3(0.), 0.3, 0.445)); ghost.dist = min(ghost.dist, shape); p = pos - vec3(0., 1., -0.55); let s: f32 = sign(p.x); var pxz = p.xz; pxz = p.xz * (rot(-pos.x * 1.)); p.x = pxz.x; p.z = pxz.y; p.x = abs(p.x) - 0.15; opaque.dist = max(length(p * vec3(1., 1., 1.3)) - 0.18, -ghost.dist); opaque.mate = mat_eye_globe; p = p - (vec3(0.05, 0.3, -0.03)); p.y = p.y - (0.01 * sin(uni.iTime * 3.)); var pxy = p.xy; pxy = p.xy * (rot(0.2 + sin(pos.x * 2. + uni.iTime) * 0.5)); p.x = pxy.x; p.y = pxy.y; shape = sdBox(p, vec3(0.15, 0.02 - p.x * 0.1, 0.03)); hair.dist = shape; p = pos; ghost.dist = opSmoothUnion(ghost.dist, length(p + vec3(0., 1.8, 0.)) - 0.5, 0.6); p.x = abs(p.x) - 0.2; p.z = p.z + (0.1 * sin(p.x * 4. + uni.iTime)); ghost.dist = opSmoothUnion(ghost.dist, sdVerticalCapsule(p + vec3(0., 2.8, 0.), 0.6, 0.01 + max(0., p.y + 3.) * 0.3), 0.2); p = pos; p.x = abs(p.x) - 0.4; var pxy = p.xy; pxy = p.xy * (rot(3.14 / 2.)); p.x = pxy.x; p.y = pxy.y; p.x = p.x + (pos.x * 0.2 * sin(pos.x + uni.iTime)); ghost.dist = opSmoothUnion(ghost.dist, sdVerticalCapsule(p + vec3(-1.5, 0., 0.), 0.6, 0.2), 0.2); let vvv = select2(ghost, opaque); var volume: Volume = select2(vvv, hair); if (!ao_pass) { p = pos - vec3(0., 1., -0.65); p.x = abs(p.x) - 0.18; glass.dist = sdRoundBox(p + vec3(-0.1, 0., 0.1), vec3(0.2 + p.y * 0.1, 0.15 + p.x * 0.05, 0.001), 0.05); glass.dist = max(glass.dist, -sdRoundBox(p + vec3(-0.1, 0., 0.1), vec3(0.18 + p.y * 0.1, 0.14 + p.x * 0.05, 0.1), 0.05)); glass.dist = max(glass.dist, abs(p.z) - 0.1); volume = select2(volume, glass); } return volume; } fn getNormal(p: vec3) -> vec3 { let off: vec2 = vec2(0.001, 0.); return normalize(map2(p).dist - vec3(map2(p - off.xyy).dist, map2(p - off.yxy).dist, map2(p - off.yyx).dist)); } fn getAO(pos: vec3, nor: vec3) -> f32 { var occ: f32 = 0.; var sca: f32 = 1.; for (var i: i32 = 0; i < 5; i = i + 1) { let h: f32 = 0.01 + 0.12 * f32(i) / 4.; var volume: Volume = map2(pos + h * nor); let d: f32 = volume.dist; occ = occ + ((h - d) * sca); sca = sca * (0.95); if (occ > 0.35) { break; } } return clamp(1. - 3. * occ, 0., 1.) * (0.5 + 0.5 * nor.y); } // @compute @workgroup_size(8, 8, 1) // fn update(@builtin(global_invocation_id) invocation_id: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // var O: vec4 = textureLoad(buffer_a, location); // textureStore(texture, location, O); // } @compute @workgroup_size(8, 8, 1) fn update(@builtin(global_invocation_id) invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var color: vec4; var coordinate = vec2(f32(location.x), f32(location.y) ); color = vec4(0., 0., 0., 0.); let uv: vec2 = coordinate / uni.iResolution.xy; let p: vec2 = 2. * (coordinate - 0.5 * uni.iResolution.xy) / uni.iResolution.y; var pos: vec3 = vec3(-5., 0., -8.); var z: vec3 = normalize(vec3(0., -0.3, 0.) - pos); var x: vec3 = normalize(cross(z, vec3(0., 1., 0.))); var y: vec3 = normalize(cross(x, z)); let ray: vec3 = normalize(z * 3. + x * p.x + y * p.y); var colorrgb = color.rgb; colorrgb = color.rgb + (vec3(0.2235, 0.3804, 0.5882) * uv.y); color.r = colorrgb.x; color.g = colorrgb.y; color.b = colorrgb.z; color.a = 1.; var shade: f32 = 0.; var normal: vec3 = vec3(0., 1., 0.); var ao: f32 = 1.; let rng: f32 = hash12(coordinate + uni.iTime); var count: i32 = 30; for (var index: i32 = 0; index < count; index += 1) { var volume: Volume = map2(pos); if (volume.dist < 0.01) { if (shade < 0.001) { ao_pass = true; ao = getAO(pos, normal); ao_pass = false; } shade = shade + (volume.density); normal = getNormal(pos); let fresnel: f32 = pow(dot(ray, normal) * 0.5 + 0.5, 1.2); volume.dist = volume.space * fresnel; var col: vec3 = vec3(0.); if (volume.mate == mat_eye_globe) { let globe: f32 = dot(normal, vec3(0., 1., 0.)) * 0.5 + 0.5; var look: vec3 = vec3(0., 0., -1.); var lookxz = look.xz; lookxz = look.xz * (rot(sin(uni.iTime) * 0.2 - 0.2)); look.x = lookxz.x; look.z = lookxz.y; var lookyz = look.yz; lookyz = look.yz * (rot(sin(uni.iTime * 2.) * 0.1 + 0.5)); look.y = lookyz.x; look.z = lookyz.y; let pupils: f32 = smoothstep(0.01, 0., dot(normal, look) - 0.95); col = col + (vec3(1.) * globe * pupils); // break; } else if (volume.mate == mat_eyebrows) { col = col + (vec3(0.3451, 0.2314, 0.5255)); // break; } else if (volume.mate == mat_glass) { col = col + (vec3(0.2)); // break; } else { let leftlight: vec3 = normalize(vec3(6., -5., 1.)); let rightlight: vec3 = normalize(vec3(-3., 1., 1.)); let frontlight: vec3 = normalize(vec3(-1., 1., -2.)); let blue: vec3 = vec3(0., 0., 1.) * pow(dot(normal, leftlight) * 0.5 + 0.5, 0.2); let green: vec3 = vec3(0., 1., 0.) * pow(dot(normal, frontlight) * 0.5 + 0.5, 2.); let red: vec3 = vec3(0.8941, 0.2039, 0.0824) * pow(dot(normal, rightlight) * 0.5 + 0.5, 0.5); col = col + (blue + green + red); col = col * (ao * 0.5 + 0.3); // break; } var colorrgb = color.rgb; colorrgb = color.rgb + (col * volume.density); color.r = colorrgb.x; color.g = colorrgb.y; color.b = colorrgb.z; // color = vec4(1.0, 0.0, 0.0, 1.0); } if (shade >= 1.) { break; } volume.dist = volume.dist * (0.9 + 0.1 * rng); pos = pos + (ray * volume.dist); } // color = vec4(1.0, 0.0, 0.0, 1.0); // color.a = 1.0; textureStore(texture, y_inverted_location, color); } ================================================ FILE: assets/shaders/sunset/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let color = vec4(0.5); textureStore(buffer_a, location, color); } ================================================ FILE: assets/shaders/sunset/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/sunset/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/sunset/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: assets/shaders/sunset/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // [[group(0), binding(1)]] // var buffer_a: texture_storage_2d; // [[group(0), binding(2)]] // var buffer_b: texture_storage_2d; // [[group(0), binding(3)]] // var buffer_c: texture_storage_2d; // [[group(0), binding(4)]] // var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; // [[group(0), binding(6)]] // var font_texture: texture_storage_2d; [[group(0), binding(6)]] var font_texture: texture_2d; [[group(0), binding(7)]] var font_texture_sampler: sampler; [[group(0), binding(8)]] var rgba_noise_256_texture: texture_2d; [[group(0), binding(9)]] var rgba_noise_256_texture_sampler: sampler; // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // let color = vec4(f32(0)); // textureStore(texture, location, color); // } // Why are the characters so pixelated? // One possible reason is that we are in a compute shader and the textures are not // filtered. let backColorDebug: vec3 = vec3(0.2, 0.2, 0.2); var uv_debug: vec2 ; var tp_debug: vec2 ; var align_debug: vec4; // north, east, south, west var font_size_debug: f32; var dotColor_debug: vec3 = vec3(0.5, 0.5, 0.); var drawColorDebug: vec3 = vec3(1., 1., 0.); var vColor: vec3 = backColorDebug; var aspect_debug: f32 = 1.; var pixelPosDebug: vec2 = vec2(0., 0.); let FONT_SPACE_DEBUG: f32 = 0.5; let headColorDebug: vec3 = vec3(0.9, 0.6, 0.2); let mpColorDebug: vec3 = vec3(0.99, 0.99, 0.); let mxColorDebug: vec3 = vec3(1., 0., 0.); let myColorDebug: vec3 = vec3(0., 1., 0.); let font_png_size_debug: vec2 = vec2(1023.0, 1023.0); fn char(ch: i32) -> f32 { let fr = fract(floor(vec2(f32(ch), 15.999 - f32(ch) / 16.)) / 16.); let q = clamp(tp_debug, vec2(0.), vec2(1.)) / 16. + fr ; let inverted_q = vec2(q.x, 1. - q.y); // // There is aliasing on the characters // let f = textureSampleGrad(font_texture, // font_texture_sampler, // inverted_q, // vec2(1.0, 0.0), // vec2(0.0, 1.0)); // using textureLoad without sampler let q1 = vec2(font_png_size_debug * q ); let y_inverted_q1 = vec2(q1.x, i32(font_png_size_debug.y) - q1.y); var f: vec4 = textureLoad(font_texture, y_inverted_q1 , 0); // smoothing out the aliasing let dx = vec2(1, 0); let dy = vec2(0, 1); let fx1: vec4 = textureLoad(font_texture, y_inverted_q1 + dx, 0); let fx2: vec4 = textureLoad(font_texture, y_inverted_q1 - dx, 0); let fy1: vec4 = textureLoad(font_texture, y_inverted_q1 + dy, 0); let fy2: vec4 = textureLoad(font_texture, y_inverted_q1 - dy, 0); let rp = 0.25; f = f * rp + (1.0 - rp) * (fx1 + fx2 + fy1 + fy2) / 4.0 ; return f.x * (f.y + 0.3) * (f.z + 0.3) * 2.; } fn SetTextPosition(x: f32, y: f32) { tp_debug = 10. * uv_debug; tp_debug.x = tp_debug.x + 17. - x; tp_debug.y = tp_debug.y - 9.4 + y; } fn SetTextPositionAbs(x: f32, y: f32) { tp_debug.x = 10. * uv_debug.x - x; tp_debug.y = 10. * uv_debug.y - y; } fn drawFract(value: ptr, digits: ptr) -> f32 { var c: f32 = 0.; *value = fract(*value) * 10.; for (var ni: i32 = 1; ni < 60; ni = ni + 1) { c = c + (char(48 + i32(*value))); tp_debug.x = tp_debug.x - (0.5); *digits = *digits - (1); *value = fract(*value) * 10.; if (*digits <= 0 || *value == 0.) { break; } } tp_debug.x = tp_debug.x - (0.5 * f32(*digits)); return c; } fn maxInt(a: i32, b: i32) -> i32 { var ret: i32; if (a > b) { ret = a; } else { ret = b; }; return ret; } fn drawInt(value: ptr, minDigits: ptr) -> f32 { var c: f32 = 0.; if (*value < 0) { *value = -*value; if (*minDigits < 1) { *minDigits = 1; } else { *minDigits = *minDigits - 1; } c = c + (char(45)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); } var fn2: i32 = *value; var digits: i32 = 1; for (var ni: i32 = 0; ni < 10; ni = ni + 1) { fn2 = fn2 / (10); if (fn2 == 0) { break; } digits = digits + 1; } digits = maxInt(*minDigits, digits); tp_debug.x = tp_debug.x - (0.5 * f32(digits)); for (var ni: i32 = 1; ni < 11; ni = ni + 1) { tp_debug.x = tp_debug.x + (0.5); c = c + (char(48 + *value % 10)); *value = *value / (10); if (ni >= digits) { break; } } tp_debug.x = tp_debug.x - (0.5 * f32(digits)); return c; } fn drawIntBackwards(value: ptr, minDigits: ptr) -> f32 { var c: f32 = 0.; let original_value: i32 = *value; if (*value < 0) { *value = -*value; if (*minDigits < 1) { *minDigits = 1; } else { *minDigits = *minDigits - 1; } // tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); // c = c + (char(45)); } var fn2: i32 = *value; var digits: i32 = 1; for (var ni: i32 = 0; ni < 10; ni = ni + 1) { fn2 = fn2 / (10); if (fn2 == 0) { break; } digits = digits + 1; } digits = maxInt(*minDigits, digits); // tp_debug.x = tp_debug.x - (0.5 * f32(digits)); for (var ni: i32 = digits - 1; ni < 11; ni = ni - 1) { tp_debug.x = tp_debug.x + (0.5); c = c + (char(48 + *value % 10)); *value = *value / (10); if (ni == 0) { break; } } if (original_value < 0) { tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); c = c + (char(45)); } // tp_debug.x = tp_debug.x + (0.5 * f32(digits)); return c; } // fn drawFloat(value: ptr, prec: ptr, maxDigits: i32) -> f32 { fn drawFloat(val: f32, prec: ptr, maxDigits: i32) -> f32 { // in case of 0.099999..., round up to 0.1000000 var value = round(val * pow(10., f32(maxDigits))) / pow(10., f32(maxDigits)); let tp_debugx: f32 = tp_debug.x - 0.5 * f32(maxDigits); var c: f32 = 0.; if (value < 0.) { c = char(45); value = -value; } tp_debug.x = tp_debug.x - (0.5); var ival = i32(value); var one: i32 = 1; c = c + (drawInt(&ival, &one)); c = c + (char(46)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); var frac_val = fract(value); c = c + (drawFract(&frac_val, prec)); tp_debug.x = min(tp_debug.x, tp_debugx); return c; } fn drawFloat_f32(value: f32) -> f32 { var two: i32 = 2; return drawFloat(value, &two, 5); } fn drawFloat_f32_prec(value: f32, prec: ptr) -> f32 { return drawFloat(value, prec, 2); } fn drawInt_i32_back(value: ptr) -> f32 { var one: i32 = 1; return drawIntBackwards(value, &one); } fn drawInt_i32(value: ptr) -> f32 { var one: i32 = 1; return drawInt(value, &one); } fn SetColor(red: f32, green: f32, blue: f32) { drawColorDebug = vec3(red, green, blue); } fn WriteFloat(fValue: f32, maxDigits: i32, decimalPlaces: ptr) { // vColor = mix(vColor, drawColorDebug, drawFloat_f32_prec(fValue, decimalPlaces)); vColor = mix(vColor, drawColorDebug, drawFloat(fValue, decimalPlaces, maxDigits)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); ; } fn WriteFloatBox( fValue: f32, maxDigits: i32, decimalPlaces: i32, alpha: f32 ) { var decs = decimalPlaces; vColor = mix(vColor, drawColorDebug, drawFloat(fValue, &decs, maxDigits) * alpha); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); ; } fn WriteInteger(iValue: ptr) { vColor = mix(vColor, drawColorDebug, drawInt_i32(iValue)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); } fn WriteIntegerBack(iValue: ptr) { vColor = mix(vColor, drawColorDebug, drawInt_i32_back(iValue)); tp_debug.x = tp_debug.x + (FONT_SPACE_DEBUG); } fn WriteFPS() { var fps: f32 = f32(uni.iSampleRate); SetColor(0.8, 0.6, 0.3); var max_digits_one = 1; WriteFloat(fps, 5, &max_digits_one); var c: f32 = 0.; c = c + (char(102)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(112)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(115)); tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); // let c2 = smoothStep(0.0, 1.0, c ); vColor = mix(vColor, drawColorDebug, c); } fn WriteMousePos(mPos: vec2, y_pos: f32) { let digits: i32 = 3; let radius: f32 = uni.iResolution.x / 400.; if (uni.iMouse.z > 0.) { dotColor_debug = mpColorDebug; } let r: f32 = length(abs(mPos.xy) - pixelPosDebug) - radius; // vColor = vColor + (mix(vec3(0.), dotColor_debug, 1. - clamp(r, 0., 1.))); var max_digits_three: i32 = 3; var mposxi: i32 = i32(mPos.x); var mposyi: i32 = i32(mPos.y); var mposx: f32 = (mPos.x); var mposy: f32 = (mPos.y); let x_pos = align_debug.y - 1. * FONT_SPACE_DEBUG; SetTextPositionAbs( x_pos, y_pos, ); drawColorDebug = myColorDebug; WriteIntegerBack(&mposyi); SetTextPositionAbs( x_pos - 7. * FONT_SPACE_DEBUG, y_pos, ); drawColorDebug = mxColorDebug; WriteIntegerBack(&mposxi); } fn sdRoundedBox(p: vec2, b: vec2, r: vec4) -> f32 { var x = r.x; var y = r.y; x = select(r.z, r.x, p.x > 0.); y = select(r.w, r.y, p.x > 0.); x = select(y, x, p.y > 0.); let q = abs(p) - b + x; return min(max(q.x, q.y), 0.) + length(max(q, vec2(0.))) - x; } fn WriteRGBAValues( location: vec2, value: vec4, screen_poz: vec2, alpha: f32, ) { let poz = screen_poz / uni.iResolution * 20. * vec2(aspect_debug, 1.0); let window_ajusted = uni.iResolution / vec2(960., 600.); let box_pos = vec2(align_debug.w, align_debug.x - FONT_SPACE_DEBUG ) / 10.; // let box_pos = mp; // // box location follows mouse position // let box_location = vec2( // uni.iMouse.x + 100. * window_ajusted.x / ( aspect_debug / 1.6 ) , // uni.iMouse.y - 48. * window_ajusted.y // ); let box_location = vec2( 100. * window_ajusted.x / ( aspect_debug / 1.6 ) , uni.iResolution.y - 60. * window_ajusted.y, ); let inverted_screen_poz = vec2(screen_poz.x, -screen_poz.y) ; // / vec2(aspect_debug, 1.) ; let d_box = sdRoundedBox( vec2(location) - box_location - inverted_screen_poz, vec2(73. / ( aspect_debug / 1.6 ), 75.) * window_ajusted, vec4(5.,5.,5.,5.) * 5.0 ); // let alpha = 0.225; let decimal_places = 3; SetColor(1., 1., 1.); var c: f32 = 0.; let lspace = 0.8; let bg_color = vec3(.8, .7, .9); vColor = mix( vColor, bg_color, (1.0 - step(0.0, d_box)) * alpha ); // red SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1.) - 0.0 + poz.y ) ; c = c + (char(114)); // r tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.r, 3, decimal_places, alpha ); // green SetTextPosition( 10. * ((box_pos.x +1. + lspace)) + poz.x, 10. * (-box_pos.y +1. ) + 1.0 + poz.y, ) ; c = c + (char(103)); // g tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.g, 3, decimal_places, alpha ); // blue SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1. ) + 2.0 + poz.y, ) ; c = c + (char(98)); // b tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.b, 4, decimal_places, alpha ); // alpha SetTextPosition( 10. * (box_pos.x +1. + lspace) + poz.x, 10. * (-box_pos.y +1. ) + 3.0 + poz.y, ) ; c = c + (char(97)); // a tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); c = c + (char(58)); // colon tp_debug.x = tp_debug.x - (FONT_SPACE_DEBUG); WriteFloatBox(value.a, 4, decimal_places, alpha ); vColor = mix(vColor, drawColorDebug, c * alpha); } fn sdSegment(p: vec2, a: vec2, b: vec2) -> f32 { let pa = p - a; let ba = b - a; let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.); return length(pa - ba * h); } fn ring(pos: vec2, radius: f32, thick: f32) -> f32 { return mix(1., 0., smoothStep(thick, thick + 0.01, abs(length(uv_debug - pos) - radius))); } fn sdCircle(p: vec2, c: vec2, r: f32) -> f32 { let d = length(p - c); return d - r; } fn draw_ring(location: vec2) { let mouse_click_poz = vec2(abs(uni.iMouse.z) , abs(uni.iMouse.w)); let alpha = 0.75; let ring_dist = sdCircle(vec2(location) , mouse_click_poz, 2.3); let d = smoothStep(0.5, 1.5, abs(ring_dist - 1.)); vColor = mix(vColor, headColorDebug, (1. - d) * alpha ); } fn draw_crossair(location: vec2) { let start = 5.0; let end = 20.; let segment1 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(start, 0.), vec2(end, 0.) ); let segment2 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(-start, 0.), vec2(-end, 0.) ); let segment3 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(0., start), vec2(0., end) ); let segment4 = sdSegment( vec2(location) - uni.iMouse.xy, vec2(0., -start), vec2(0., -end) ); var alpha = 0.75; if (uni.iMouse.z > 0.) { alpha = 1.0; } let d = smoothStep(0.5, 1.5, segment1); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothStep(0.5, 1.5, segment2); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothStep(0.5, 1.5, segment3); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); let d = smoothStep(0.5, 1.5, segment4); vColor = mix(vColor, headColorDebug, (1.0 - d) * alpha ); } fn show_debug_info(location: vec2, color: vec3) -> vec4 { var fragCoord = vec2(f32(location.x), f32(location.y) ); vColor = color; aspect_debug = uni.iResolution.x / uni.iResolution.y; let ratio: vec2 = vec2(aspect_debug, 1.); pixelPosDebug = fragCoord.xy; // mousePosDebug = uni.iMouse.xy; uv_debug = (2. * fragCoord.xy / uni.iResolution.xy - 1.) * ratio; align_debug = 10. * vec4( 1., // North aspect_debug, // East -1., // South -aspect_debug, // West ); WriteMousePos(uni.iMouse.zw, align_debug.z + 2.0 * FONT_SPACE_DEBUG); // Click position WriteMousePos(uni.iMouse.xy, align_debug.z + 0.2 * FONT_SPACE_DEBUG); // Current mouse position var c: f32 = 0.; SetTextPositionAbs( align_debug.y - FONT_SPACE_DEBUG, align_debug.x - 2. * FONT_SPACE_DEBUG, ); SetColor(0.8, 0.8, 0.8); var resx = i32(uni.iResolution.x); var resy = i32(uni.iResolution.y); WriteIntegerBack(&resx); c = c + (char(28)); tp_debug.x = tp_debug.x + 0. * (FONT_SPACE_DEBUG); WriteIntegerBack(&resy); SetTextPositionAbs( align_debug.w - 1. * FONT_SPACE_DEBUG, align_debug.z - 0. * FONT_SPACE_DEBUG, ); WriteFPS(); SetColor(0.9, 0.7, 0.8); let fragColor = vec4(vColor, 1.); let poz = vec2(0., uni.iResolution.y / 2.); // // RGBA probe labels follow mouse // let poz = vec2(uni.iMouse.x , uni.iResolution.y - uni.iMouse.y); let inverted_y_mouse_location = vec2(vec2(uni.iMouse.x, uni.iResolution.y - uni.iMouse.y)); let value: vec4 = textureLoad(texture, inverted_y_mouse_location); WriteRGBAValues(location, value, poz, 0.85); let inverted_y_mouseclick_location = vec2(vec2(abs(uni.iMouse.z), uni.iResolution.y - abs(uni.iMouse.w))); let value2: vec4 = textureLoad(texture, inverted_y_mouseclick_location); WriteRGBAValues(location, value2, vec2(0.), 0.65); draw_crossair(location); draw_ring(location); let fragColor = vec4(vColor, 1.); return fragColor; } fn calculate_scattering(start: vec3, dir: vec3, max_dist: f32, scene_color: vec3, light_dir: vec3, light_intensity: vec3, planet_position: vec3, planet_radius: f32, atmo_radius: f32, beta_ray: vec3, beta_mie: vec3, beta_absorption: vec3, beta_ambient: vec3, g: f32, height_ray: f32, height_mie: f32, height_absorption: f32, absorption_falloff: f32, steps_i: i32, steps_l: i32) -> vec3 { var start_var = start; start_var = start_var - (planet_position); var a: f32 = dot(dir, dir); var b: f32 = 2. * dot(dir, start_var); var c: f32 = dot(start_var, start_var) - atmo_radius * atmo_radius; var d: f32 = b * b - 4. * a * c; if (d < 0.) { return scene_color; } var ray_length: vec2 = vec2(max((-b - sqrt(d)) / (2. * a), 0.), min((-b + sqrt(d)) / (2. * a), max_dist)); if (ray_length.x > ray_length.y) { return scene_color; } var allow_mie: bool = max_dist > ray_length.y; ray_length.y = min(ray_length.y, max_dist); ray_length.x = max(ray_length.x, 0.); let step_size_i: f32 = (ray_length.y - ray_length.x) / f32(steps_i); var ray_pos_i: f32 = ray_length.x + step_size_i * 0.5; var total_ray: vec3 = vec3(0.); var total_mie: vec3 = vec3(0.); var opt_i: vec3 = vec3(0.); let scale_height: vec2 = vec2(height_ray, height_mie); var mu: f32 = dot(dir, light_dir); var mumu: f32 = mu * mu; var gg: f32 = g * g; let phase_ray: f32 = 3. / 50.265484 * (1. + mumu); var phase_mie: f32; if (allow_mie) { phase_mie = 3. / 25.132742 * ((1. - gg) * (mumu + 1.)) / (pow(1. + gg - 2. * mu * g, 1.5) * (2. + gg)); } else { phase_mie = 0.; }; for (var i: i32 = 0; i < steps_i; i = i + 1) { let pos_i: vec3 = start_var + dir * ray_pos_i; let height_i: f32 = length(pos_i) - planet_radius; var density: vec3 = vec3(exp(-height_i / scale_height), 0.); var denom: f32 = (height_absorption - height_i) / absorption_falloff; density.z = 1. / (denom * denom + 1.) * density.x; density = density * (step_size_i); opt_i = opt_i + (density); a = dot(light_dir, light_dir); b = 2. * dot(light_dir, pos_i); c = dot(pos_i, pos_i) - atmo_radius * atmo_radius; d = b * b - 4. * a * c; let step_size_l: f32 = (-b + sqrt(d)) / (2. * a * f32(steps_l)); var ray_pos_l: f32 = step_size_l * 0.5; var opt_l: vec3 = vec3(0.); for (var l: i32 = 0; l < steps_l; l = l + 1) { let pos_l: vec3 = pos_i + light_dir * ray_pos_l; let height_l: f32 = length(pos_l) - planet_radius; var density_l: vec3 = vec3(exp(-height_l / scale_height), 0.); let denom: f32 = (height_absorption - height_l) / absorption_falloff; density_l.z = 1. / (denom * denom + 1.) * density_l.x; density_l = density_l * (step_size_l); opt_l = opt_l + (density_l); ray_pos_l = ray_pos_l + (step_size_l); } let attn: vec3 = exp(-beta_ray * (opt_i.x + opt_l.x) - beta_mie * (opt_i.y + opt_l.y) - beta_absorption * (opt_i.z + opt_l.z)); total_ray = total_ray + (density.x * attn); total_mie = total_mie + (density.y * attn); ray_pos_i = ray_pos_i + (step_size_i); } let opacity: vec3 = exp(-(beta_mie * opt_i.y + beta_ray * opt_i.x + beta_absorption * opt_i.z)); return (phase_ray * beta_ray * total_ray + phase_mie * beta_mie * total_mie + opt_i.x * beta_ambient) * light_intensity + scene_color * opacity; } fn ray_sphere_intersect(start: vec3, dir: vec3, radius: f32) -> vec2 { let a: f32 = dot(dir, dir); let b: f32 = 2. * dot(dir, start); let c: f32 = dot(start, start) - radius * radius; let d: f32 = b * b - 4. * a * c; if (d < 0.) { return vec2(100000., -100000.); } return vec2((-b - sqrt(d)) / (2. * a), (-b + sqrt(d)) / (2. * a)); } fn skylight(sample_pos: vec3, surface_normal: vec3, light_dir: vec3, background_col: vec3) -> vec3 { var surface_normal_var = surface_normal; surface_normal_var = normalize(mix(surface_normal_var, light_dir, 0.6)); return calculate_scattering(sample_pos, surface_normal_var, 3. * 6471000., background_col, light_dir, vec3(40.), vec3(0.), 6371000., 6471000., vec3(0.0000055, 0.000013, 0.0000224), vec3(0.000021), vec3(0.0000204, 0.0000497, 0.00000195), vec3(0.), 0.7, 8000., 1200., 30000., 4000., 4, 4); } fn render_scene(pos: vec3, dir: vec3, light_dir: vec3) -> vec4 { var color: vec4 = vec4(0., 0., 0., 1000000000000.); var colorxyz = color.xyz; // colorxyz = vec3; if (dot(dir, light_dir) > 0.9998) { colorxyz = vec3(3.); } else { colorxyz =vec3( 0.); }; color.x = colorxyz.x; color.y = colorxyz.y; color.z = colorxyz.z; let planet_intersect: vec2 = ray_sphere_intersect(pos - vec3(0.), dir, 6371000.); if (0. < planet_intersect.y) { color.w = max(planet_intersect.x, 0.); let sample_pos: vec3 = pos + dir * planet_intersect.x - vec3(0.); let surface_normal: vec3 = normalize(sample_pos); var colorxyz = color.xyz; colorxyz = vec3(0., 0.25, 0.05); color.x = colorxyz.x; color.y = colorxyz.y; color.z = colorxyz.z; let N: vec3 = surface_normal; let V: vec3 = -dir; let L: vec3 = light_dir; let dotNV: f32 = max(0.000001, dot(N, V)); let dotNL: f32 = max(0.000001, dot(N, L)); let shadow: f32 = dotNL / (dotNL + dotNV); var colorxyz = color.xyz; colorxyz = color.xyz * (shadow); color.x = colorxyz.x; color.y = colorxyz.y; color.z = colorxyz.z; var colorxyz = color.xyz; colorxyz = color.xyz + (clamp(skylight(sample_pos, surface_normal, light_dir, vec3(0.)) * vec3(0., 0.25, 0.05), vec3(0.), vec3(1.))); color.x = colorxyz.x; color.y = colorxyz.y; color.z = colorxyz.z; } return color; } fn get_camera_vector(resolution: vec2, coord: vec2) -> vec3 { var uv: vec2 = coord.xy / resolution.xy - vec2(0.5); uv.x = uv.x * (resolution.x / resolution.y); return normalize(vec3(uv.x, uv.y, -1.)); } fn toLinear(sRGB: vec4) -> vec4 { let cutoff = vec4(sRGB < vec4(0.04045)); let higher = pow((sRGB + vec4(0.055)) / vec4(1.055), vec4(2.4)); let lower = sRGB / vec4(12.92); return mix(higher, lower, cutoff); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let R: vec2 = uni.iResolution.xy; let y_inverted_location = vec2(i32(invocation_id.x), i32(R.y) - i32(invocation_id.y)); let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var fragColor: vec4; var fragCoord = vec2(f32(location.x), f32(location.y) ); let time = uni.iTime / 3.0; let camera_vector: vec3 = get_camera_vector(uni.iResolution, fragCoord); let offset: f32 = (1. - cos(time / 2.)) * 6471000.; let camera_position: vec3 = vec3(0., 6371000. + 1., offset); var light_dir: vec3; if (uni.iMouse.y == 0.) { light_dir = normalize(vec3(0., cos(-time / 8.), sin(-time / 8.))); } else { light_dir = normalize(vec3(0., cos(uni.iMouse.y * -5. / uni.iResolution.y), sin(uni.iMouse.y * -5. / uni.iResolution.y))); }; let scene: vec4 = render_scene(camera_position, camera_vector, light_dir); var col: vec3 = vec3(0.); col = col + (calculate_scattering(camera_position, camera_vector, scene.w, scene.xyz, light_dir, vec3(40.), vec3(0.), 6371000., 6471000., vec3(0.0000055, 0.000013, 0.0000224), vec3(0.000021), vec3(0.0000204, 0.0000497, 0.00000195), vec3(0.), 0.7, 8000., 1200., 30000., 4000., 12, 4)); col = 1. - exp(-col); // fragColor = vec4(col, 1.); textureStore(texture, y_inverted_location, toLinear(vec4((col), 1.))); } ================================================ FILE: bin/assets/shaders/image_load.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: i32; iSampleRate: i32; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; iResolution: vec2; iMouse: vec2; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; fn hash(value: u32) -> u32 { var state = value; state = state ^ 2747636419u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; return state; } fn randomFloat(value: u32) -> f32 { return f32(hash(value)) / 4294967295.0; } [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let randomNumber = randomFloat(invocation_id.y * num_workgroups.x + invocation_id.x); let alive = randomNumber > 0.9; let color = vec4(f32(alive)); textureStore(texture, location, color); } // fn get(location: vec2, offset_x: i32, offset_y: i32) -> i32 { // let value: vec4 = textureLoad(texture, location + vec2(offset_x, offset_y)); // return i32(value.x); // } // fn count_alive(location: vec2) -> i32 { // return get(location, -1, -1) + // get(location, -1, 0) + // get(location, -1, 1) + // get(location, 0, -1) + // get(location, 0, 1) + // get(location, 1, -1) + // get(location, 1, 0) + // get(location, 1, 1); // } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let n_alive = count_alive(location); // let color = vec4(f32(n_alive) / 8.0); // var alive: bool; // if (n_alive == 3) { // alive = true; // } else if (n_alive == 2) { // let currently_alive = get(location, 0, 0); // alive = bool(currently_alive); // } else { // alive = false; // } var alive = true; // let value: vec4 = textureLoad(buffer_a, vec2(0,1)); // if (value.x > 0.51) { // alive = false; // } // let value: vec4 = textureLoad(buffer_b, vec2(0,1)); // if (value.x > 0.74) { // alive = false; // } // let value: vec4 = textureLoad(buffer_c, vec2(0,1)); // if (value.x > 0.61) { // alive = false; // } let value: vec4 = textureLoad(buffer_a, vec2(0,1)); if (value.x > 0.79) { alive = false; } // if (ga > 2) { // alive = true; // } // if (uni.iTime > 1.0) { // alive = false; // } // alive = false; storageBarrier(); textureStore(texture, location, vec4(f32(alive))); } ================================================ FILE: bin/assets/shaders/interactive_fluid_simulation/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_a, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_a, location, vec4(0.094)); if (uni.iTime > 1.0) { textureStore(buffer_a, location, vec4(0.95)); } } ================================================ FILE: bin/assets/shaders/interactive_fluid_simulation/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: i32; iSampleRate: i32; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; iResolution: vec2; iMouse: vec2; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_b, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_b, location, vec4(0.85)); // if (uni.iTime > 1.0) { // textureStore(buffer_b, location, vec4(0.95)); // } } ================================================ FILE: bin/assets/shaders/interactive_fluid_simulation/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_c, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_c, location, vec4(0.95)); // if (uni.iTime > 1.0) { // textureStore(buffer_c, location, vec4(0.95)); // } } ================================================ FILE: bin/assets/shaders/interactive_fluid_simulation/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let color = vec4(0.60); textureStore(buffer_d, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_d, location, vec4(0.7)); // let p: vec4 = texture(iChannel0, fragCoord/iResolution.xy); // if (uni.iMouse.z>0.) { // if (p.z>0.) { fragColor = vec4(uni.iMouse.xy, p.xy); // } else { fragColor = vec4(uni.iMouse.xy, uni.iMouse.xy); // } // } else { fragColor = vec4(-uni.iResolution.xy, -uni.iResolution.xy); // } if (uni.iTime > 1.0) { storageBarrier(); textureStore(buffer_d, location, vec4(0.95)); } // storageBarrier(); } // fn mainImage( fragColor: vec4, fragCoord: vec2) -> () { // let p: vec4 = texture(iChannel0, fragCoord/iResolution.xy); // if (iMouse.z>0.) { // if (p.z>0.) { fragColor = vec4(iMouse.xy, p.xy); // } else { fragColor = vec4(iMouse.xy, iMouse.xy); // } // } else { fragColor = vec4(-iResolution.xy, -iResolution.xy); // } // } ================================================ FILE: bin/assets/shaders/interactive_fluid_simulation/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; fn hash(value: u32) -> u32 { var state = value; state = state ^ 2747636419u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; return state; } fn randomFloat(value: u32) -> f32 { return f32(hash(value)) / 4294967295.0; } [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let randomNumber = randomFloat(invocation_id.y * num_workgroups.x + invocation_id.x); let alive = randomNumber > 0.9; let color = vec4(f32(alive)); textureStore(texture, location, color); } fn t(v: vec2) -> vec4 { return textureLoad(buffer_a, v ); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var me: vec4 = t(location) ; let U = location; me.z = me.z - (1.); var C = 1. - 3.*me.www; let d: vec3 = vec3(t(U+vec2(1, 0)).w-t(U-vec2(1, 0)).w, t(U+vec2(0, 1)).w-t(U-vec2(0, 1)).w, 2.); C = C - (max(vec3(0.), sin(vec3(100.*length(me.xy), -5.*me.z, 368.*d.y)*me.w))); storageBarrier(); textureStore(texture, location, vec4(C.x, C.y, C.z, me.w)); } // fn mainImage( C: vec4, U: vec2) -> () { // let me: vec4 = t(U); // me.z = me.z - (1.); // C = 1.-3.*me.wwww; // let d: vec3 = vec3(t(U+vec2(1, 0)).w-t(U-vec2(1, 0)).w, t(U+vec2(0, 1)).w-t(U-vec2(0, 1)).w, 2.); // C.xyz = C.xyz - (max(vec3(0), sin(vec3(100.*length(me.xy), -5.*me.z, 368.*d.y)*me.w))); // } ================================================ FILE: bin/assets/shaders/liquid/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; struct Particle { position: vec2; velocity: vec2; mass: vec2; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; let fluid_rho: f32 = 0.5; let dt: f32 = 1.5; let border_h = 5.0; let h: f32 = 1.; fn Pf(rho: vec2) -> f32 { //return 0.2*rho.x; //gas let GF: f32 = 1.;//smoothstep(0.49, 0.5, 1. - rho.y); return mix(0.5*rho.x, 0.04*rho.x*(rho.x/fluid_rho - 1.), GF); //water pressure } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox(p: vec2, b: vec2) -> f32 { let d = (abs(p) - b) ; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn border(p: vec2, uni: CommonUniform) -> f32 { let R: vec2 = uni.iResolution; let bound: f32 = -sdBox(p - R*0.5, R*vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0.*uni.iTime)*(p - R*vec2(0.5, 0.6)) , R*vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R*vec2(0.5, 0.7), R*vec2(1.5, 0.5)); return max(drain,min(bound, box)); } fn bN( p: vec2, uni: CommonUniform ) -> vec3 { let dx: vec3 = vec3(-h, 0.0 , h); let idx: vec4 = vec4(-1./h, 0., 1./h, 0.25); let r: vec3 = idx.zyw*border(p + dx.zy, uni) + idx.xyw*border(p + dx.xy, uni) + idx.yzw*border(p + dx.yz, uni) + idx.yxw*border(p + dx.yx, uni); return vec3(normalize(r.xy), r.z + 1e-4); } fn pack(x: vec2) -> u32 { var q: vec2; q.x = 65534.0*clamp(0.5*x.x+0.5, 0., 1.); q.y = 65534.0*clamp(0.5*x.y+0.5, 0., 1.); return u32(round(q.x)) + 65535u*u32(round(q.y)); } fn unpack(a: u32) -> vec2 { let q = vec2(a % 65535u, a / 65535u); let p = vec2( clamp(f32(q.x) / 65534.0, 0.,1.)*2.0 - 1.0, clamp(f32(q.y) / 65534.0, 0.,1.)*2.0 - 1.0 ); return p; } fn decode(x: f32) -> vec2 { let X: u32 = bitcast(x); return unpack(X); } fn encode(x: vec2) -> f32 { let X: u32 = pack(x); let casted: f32 = bitcast(X); return casted; } fn getParticle(data: vec4, pos: vec2) -> Particle { var P: Particle; P.position = decode(data.x) + pos; P.velocity = decode(data.y); P.mass = data.zw; return P; } fn saveParticle(in_p: Particle, pos: vec2) -> vec4 { var P: Particle = in_p; // P.position = clamp(P.position - pos, vec2(-0.5), vec2(0.5)); P.position.x = clamp(P.position.x - pos.x, -0.5, 0.5); P.position.y = clamp(P.position.y - pos.y, -0.5, 0.5); return vec4(encode(P.position), encode(P.velocity), P.mass.x, P.mass.y); } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); p3 = p3 + dot(p3, p3.yxz+33.33); return fract((p3.xxy+p3.yzz)*p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x,x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K*0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K*0.5, p - 0.5, p + 0.5); return vec3(0.5*(omin + omax), (omax.x - omin.x)*(omax.y - omin.y)/(K*K)); } //diffusion and advection basically fn Reintegration(buffer: texture_storage_2d, P: Particle, pos: vec2) -> Particle { var particle: Particle = P; //basically integral over all updated neighbor distributions //that fall inside of this pixel //this makes the tracking conservative var i: i32 = -2; loop { if (i > 2) { break; } var j: i32 = -2; loop { if (j > 2) { break; } let tpos: vec2 = pos + vec2(f32(i),f32(j)); let data: vec4 = textureLoad(buffer, vec2(tpos)); var P0: Particle = getParticle(data, tpos); P0.position = P0.position + P0.velocity*dt; //integrate position let difR: f32 = 0.9 + 0.21*smoothStep(fluid_rho*0., fluid_rho*0.333, P0.mass.x); let D: vec3 = distribution(P0.position, pos, difR); //the deposited mass into this cell let m: f32 = P0.mass.x*D.z; //add weighted by mass particle.position = particle.position + D.xy*m; particle.velocity = particle.velocity + P0.velocity*m; particle.mass.y = particle.mass.y + P0.mass.y*m; //add mass particle.mass.x = particle.mass.x + m; } } // range(i, -2, 2) range(j, -2, 2) //normalization if(particle.mass.x != 0.) { particle.position = particle.position / particle.mass.x; particle.velocity= particle.velocity / particle.mass.x; particle.mass.y = particle.mass.y / particle.mass.x; } return particle; } //force calculation and integration fn Simulation( buffer: texture_storage_2d, P: Particle, pos: vec2, Mouse: vec4, uni: CommonUniform ) -> Particle { var particle: Particle = P; //Compute the SPH force var F: vec2 = vec2(0.); var avgV: vec3 = vec3(0.); var i: i32 = -2; loop { if (i > 2) { break; } var j: i32 = -2; loop { if (j > 2) { break; } let tpos: vec2 = pos + vec2(f32(i), f32(j)); // let data: vec4 = texel(ch, tpos); let data: vec4 = textureLoad(buffer, vec2(tpos)); let P0: Particle = getParticle(data, tpos); let dx: vec2 = P0.position - particle.position; let avgP: f32 = 0.5*P0.mass.x*(Pf(particle.mass) + Pf(P0.mass)); F = F - 0.5*G(1.*dx)*avgP*dx; avgV = avgV + P0.mass.x*G(1.*dx)*vec3(P0.velocity,1.); } } avgV.x = avgV.x / avgV.z; avgV.y = avgV.y / avgV.z; //viscosity F = F + 0.*particle.mass.x*(avgV.xy - particle.velocity); //gravity F = F + particle.mass.x*vec2(0., -0.0004); if(Mouse.z > 0.) { let dm: vec2 =(Mouse.xy - Mouse.zw)/10.; let d: f32 = distance(Mouse.xy, particle.position)/20.; F = F + 0.001*dm*exp(-d*d); // particle.mass.y += 0.1*exp(-40.*d*d); } //integrate particle.velocity = particle.velocity + F*dt/particle.mass.x; //border let N: vec3 = bN(particle.position, uni); let vdotN : f32 = step(N.z, border_h) * dot(-N.xy, particle.velocity); particle.velocity = particle.velocity + 0.5*(N.xy*vdotN + N.xy*abs(vdotN)); particle.velocity = particle.velocity + 0.*particle.mass.x*N.xy*step(abs(N.z), border_h)*exp(-N.z); if (N.z < 0.) { particle.velocity = vec2(0.); } //velocity limit let v: f32 = length(particle.velocity); if (v > 1.0) { particle.velocity = particle.velocity / v; } // particle.velocity = particle.velocity / (v > 1.) ? v : 1.; return particle; } // // /* // // vec3 distribution(vec2 x, vec2 p, float K) // // { // // vec4 aabb0 = vec4(p - 0.5, p + 0.5); // // vec4 aabb1 = vec4(x - K*0.5, x + K*0.5); // // vec4 aabbX = vec4(max(aabb0.xy, aabb1.xy), min(aabb0.zw, aabb1.zw)); // // vec2 center = 0.5*(aabbX.xy + aabbX.zw); //center of mass // // vec2 size = max(aabbX.zw - aabbX.xy, 0.); //only positive // // float m = size.x*size.y/(K*K); //relative amount // // //if any of the dimensions are 0 then the mass is 0 // // return vec3(center, m); // // }*/ [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_a, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_a, location, vec4(0.094)); if (uni.iTime > 1.0) { textureStore(buffer_a, location, vec4(0.95)); } } ================================================ FILE: bin/assets/shaders/liquid/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: i32; iSampleRate: i32; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; iResolution: vec2; iMouse: vec2; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_b, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_b, location, vec4(0.85)); // if (uni.iTime > 1.0) { // textureStore(buffer_b, location, vec4(0.95)); // } } ================================================ FILE: bin/assets/shaders/liquid/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_c, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_c, location, vec4(0.95)); // if (uni.iTime > 1.0) { // textureStore(buffer_c, location, vec4(0.95)); // } } ================================================ FILE: bin/assets/shaders/liquid/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let color = vec4(0.60); textureStore(buffer_d, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_d, location, vec4(0.7)); if (uni.iTime > 1.0) { storageBarrier(); textureStore(buffer_d, location, vec4(0.95)); } // storageBarrier(); } ================================================ FILE: bin/assets/shaders/liquid/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; fn hash(value: u32) -> u32 { var state = value; state = state ^ 2747636419u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; return state; } fn randomFloat(value: u32) -> f32 { return f32(hash(value)) / 4294967295.0; } [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let randomNumber = randomFloat(invocation_id.y * num_workgroups.x + invocation_id.x); let alive = randomNumber > 0.9; let color = vec4(f32(alive)); textureStore(texture, location, color); } // fn get(location: vec2, offset_x: i32, offset_y: i32) -> i32 { // let value: vec4 = textureLoad(texture, location + vec2(offset_x, offset_y)); // return i32(value.x); // } // fn count_alive(location: vec2) -> i32 { // return get(location, -1, -1) + // get(location, -1, 0) + // get(location, -1, 1) + // get(location, 0, -1) + // get(location, 0, 1) + // get(location, 1, -1) + // get(location, 1, 0) + // get(location, 1, 1); // } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let n_alive = count_alive(location); // let color = vec4(f32(n_alive) / 8.0); // var alive: bool; // if (n_alive == 3) { // alive = true; // } else if (n_alive == 2) { // let currently_alive = get(location, 0, 0); // alive = bool(currently_alive); // } else { // alive = false; // } var alive = true; // let value: vec4 = textureLoad(buffer_a, vec2(0,1)); // if (value.x > 0.51) { // alive = false; // } // let value: vec4 = textureLoad(buffer_b, vec2(0,1)); // if (value.x > 0.74) { // alive = false; // } // let value: vec4 = textureLoad(buffer_c, vec2(0,1)); // if (value.x > 0.61) { // alive = false; // } let value: vec4 = textureLoad(buffer_a, vec2(0,1)); if (value.x > 0.79) { alive = false; } // if (ga > 2) { // alive = true; // } // if (uni.iTime > 1.0) { // alive = false; // } // alive = false; storageBarrier(); textureStore(texture, location, vec4(f32(alive))); } ================================================ FILE: bin/assets/shaders/minimal/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let color = vec4(0.5); textureStore(buffer_a, location, color); } ================================================ FILE: bin/assets/shaders/minimal/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: bin/assets/shaders/minimal/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_c, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_c, location, vec4(0.95)); // if (uni.iTime > 1.0) { // textureStore(buffer_c, location, vec4(0.95)); // } } ================================================ FILE: bin/assets/shaders/minimal/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let color = vec4(0.60); textureStore(buffer_d, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_d, location, vec4(0.7)); if (uni.iTime > 1.0) { storageBarrier(); textureStore(buffer_d, location, vec4(0.95)); } // storageBarrier(); } ================================================ FILE: bin/assets/shaders/minimal/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // let color = vec4(f32(0)); // textureStore(texture, location, color); // } // displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a // here [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var O: vec4 = textureLoad(buffer_a, location); textureStore(texture, location, O); } ================================================ FILE: bin/assets/shaders/mixing_liquid/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // struct Particle { // a: vec4; // b: vec4; // }; // fn dum(x: Particle) { // let x2 = Particle(x.a, x.b); // let bah = x.a + 1.0; // return; // } // fn miam() -> Particle { // var out: Particle; // out.a = vec4(0.0); // out.b = vec4(1.0); // return out; // } // let ch0: texture_storage_2d = buffer_a; // let ch1: texture_storage_2d = buffer_a; // let ch2: texture_storage_2d = buffer_a; // let ch3: texture_storage_2d = buffer_a; // #define Bf(p) p // #define Bi(p) ivec2(p) // #define texel(a, p) texelFetch(a, Bi(p), 0) // #define pixel(a, p) texture(a, (p)/R) let PI = 3.14159265; let dt = 1.5; let border_h = 5.; var R: vec2 ; var Mouse: vec4 ; var time: f32; let mass = 1.; let fluid_rho = 0.5; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox( p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn border(p: vec2) -> f32 { let bound: f32 = -sdBox(p - R * 0.5, R * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time) * (p - R * vec2(0.5, 0.6)), R * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R * vec2(0.5, 0.7), R * vec2(1.5, 0.5)); return max(drain, min(bound, box)); } let h: f32 = 1.; fn bN(p: vec2) -> vec3 { let dx: vec3 = vec3(-h, 0.0, h); let idx: vec4 = vec4(-1./h, 0., 1./h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx); return vec3(normalize(r.xy), r.z + 1e-4); } fn pack(x: vec2) -> u32 { let x2: vec2 = 65534. * clamp(0.5 * x + 0.5, vec2(0.), vec2(1.)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw); return P; } fn saveParticle(P: particle, pos: vec2) -> vec4 { var P2: particle = particle(P.X, P.V, P.M); P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); return vec4(encode(P2.X), encode(P2.V), P2.M); } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } let dif: f32 = 1.12; fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } // don't forget to use a return value when using Reintegration fn Reintegration(ch: texture_storage_2d, pos: vec2) -> particle { //basically integral over all updated neighbor distributions //that fall inside of this pixel //this makes the tracking conservative for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(i)); // let data: vec4 = texel(ch, tpos); // let data: vec4 = texelFetch(ch, ivec2(tpos), 0); let data: vec4 = textureLoad(ch, vec2(tpos)); var P0: particle = getParticle(data, tpos); P0.X = P0.X + (P0.V * dt);//integrate position let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x); let D: vec3 = distribution(P0.X, pos, difR); //the deposited mass into this cell let m: f32 = P0.M.x * D.z; var P1: particle; // TODO: change the input particle directly using (*P).X = ... //add weighted by mass P1.X = P1.X + (D.xy * m); P1.V = P1.V + (P0.V * m); P1.M.y = P1.M.y + (P0.M.y * m); //add mass P1.M.x = P1.M.x + (m); } } //normalization if (P1.M.x != 0.) { P1.X = P1.X / (P1.M.x); P1.V = P1.V / (P1.M.x); P1.M.y = P1.M.y / (P1.M.x); } return P1; } fn Simulation(ch: texture_storage_2d, P: particle, pos: vec2) -> particle { var F: vec2 = vec2(0.); var avgV: vec3 = vec3(0.); for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(i)); // let data: vec4 = texel(ch, tpos); // let data: vec4 = texelFetch(ch, ivec2(tpos), 0); let data: vec4 = textureLoad(ch, vec2(tpos)); let P0: particle = getParticle(data, tpos); let dx: vec2 = P0.X - P.X; let avgP: f32 = 0.5 * P0.M.x * (Pf(P.M) + Pf(P0.M)); F = F - (0.5 * G(1. * dx) * avgP * dx); avgV = avgV + (P0.M.x * G(1. * dx) * vec3(P0.V, 1.)); } } avgV.y = avgV.y / (avgV.z); avgV.x = avgV.x / (avgV.z); //viscosity F = F + (0. * P.M.x * (avgV.xy - P.V)); //gravity F = F + (P.M.x * vec2(0., -0.0004)); if (Mouse.z > 0.) { let dm: vec2 = (Mouse.xy - Mouse.zw) / 10.; let d: f32 = distance(Mouse.xy, P.X) / 20.; F = F + (0.001 * dm * exp(-d * d)); } var P1: particle = P; //integrate P1.V = P1.V + (F * dt / P1.M.x); //border let N: vec3 = bN(P1.X); let vdotN: f32 = step(N.z, border_h) * dot(-N.xy, P1.V); P1.V = P1.V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN))); P1.V = P1.V + (0. * P1.M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z)); if (N.z < 0.) { P1.V = vec2(0.); } //velocity limit let v: f32 = length(P1.V); var vv: f32; if (v > 1.) { vv = v; } else { vv = 1.; }; P1.V = P1.V / vv; return P1; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let color = vec4(0.5); // textureStore(buffer_a, location, color); // } // fn mainImage( U: vec4, pos: vec2) -> () { let pos: vec2 = vec2(location); R = uni.iResolution.xy; time = uni.iTime; Mouse = uni.iMouse; let p: vec2 = location; // let data: vec4 = texel(ch0, pos); // buffer_b is set as the channel 0 in Buffer A of the paint // streams inside shadertoy let data: vec4 = textureLoad(buffer_b, location); var P: particle = Reintegration(buffer_b, pos); if (uni.iFrame < 4.0) { let rand: vec3 = hash32(pos); if (rand.z < 0.) { P.X = pos; P.V = 0.5 * (rand.xy - 0.5) + vec2(0., 0.); P.M = vec2(mass, 0.); } else { P.X = pos; P.V = vec2(0.); P.M = vec2(0.000001); } } textureStore(buffer_a, location, saveParticle(P, pos)); } ================================================ FILE: bin/assets/shaders/mixing_liquid/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // struct Particle { // a: vec4; // b: vec4; // }; // fn dum(x: Particle) { // let x2 = Particle(x.a, x.b); // let bah = x.a + 1.0; // return; // } // fn miam() -> Particle { // var out: Particle; // out.a = vec4(0.0); // out.b = vec4(1.0); // return out; // } // let ch0: texture_storage_2d = buffer_a; // let ch1: texture_storage_2d = buffer_a; // let ch2: texture_storage_2d = buffer_a; // let ch3: texture_storage_2d = buffer_a; // #define Bf(p) p // #define Bi(p) ivec2(p) // #define texel(a, p) texelFetch(a, Bi(p), 0) // #define pixel(a, p) texture(a, (p)/R) let PI = 3.14159265; let dt = 1.5; let border_h = 5.; var R: vec2 ; var Mouse: vec4 ; var time: f32; let mass = 1.; let fluid_rho = 0.5; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox( p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn border(p: vec2) -> f32 { let bound: f32 = -sdBox(p - R * 0.5, R * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time) * (p - R * vec2(0.5, 0.6)), R * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R * vec2(0.5, 0.7), R * vec2(1.5, 0.5)); return max(drain, min(bound, box)); } let h: f32 = 1.; fn bN(p: vec2) -> vec3 { let dx: vec3 = vec3(-h, 0.0, h); let idx: vec4 = vec4(-1./h, 0., 1./h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx); return vec3(normalize(r.xy), r.z + 1e-4); } fn pack(x: vec2) -> u32 { let x2: vec2 = 65534. * clamp(0.5 * x + 0.5, vec2(0.), vec2(1.)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw); return P; } fn saveParticle(P: particle, pos: vec2) -> vec4 { var P2: particle = particle(P.X, P.V, P.M); P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); return vec4(encode(P2.X), encode(P2.V), P2.M); } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } let dif: f32 = 1.12; fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } // don't forget to use a return value when using Reintegration fn Reintegration(ch: texture_storage_2d, pos: vec2) -> particle { //basically integral over all updated neighbor distributions //that fall inside of this pixel //this makes the tracking conservative for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(i)); // let data: vec4 = texel(ch, tpos); // let data: vec4 = texelFetch(ch, ivec2(tpos), 0); let data: vec4 = textureLoad(ch, vec2(tpos)); var P0: particle = getParticle(data, tpos); P0.X = P0.X + (P0.V * dt);//integrate position let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x); let D: vec3 = distribution(P0.X, pos, difR); //the deposited mass into this cell let m: f32 = P0.M.x * D.z; var P1: particle; // TODO: change the input particle directly using (*P).X = ... //add weighted by mass P1.X = P1.X + (D.xy * m); P1.V = P1.V + (P0.V * m); P1.M.y = P1.M.y + (P0.M.y * m); //add mass P1.M.x = P1.M.x + (m); } } //normalization if (P1.M.x != 0.) { P1.X = P1.X / (P1.M.x); P1.V = P1.V / (P1.M.x); P1.M.y = P1.M.y / (P1.M.x); } return P1; } fn Simulation(ch: texture_storage_2d, P: particle, pos: vec2) -> particle { var F: vec2 = vec2(0.); var avgV: vec3 = vec3(0.); for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(i)); // let data: vec4 = texel(ch, tpos); // let data: vec4 = texelFetch(ch, ivec2(tpos), 0); let data: vec4 = textureLoad(ch, vec2(tpos)); let P0: particle = getParticle(data, tpos); let dx: vec2 = P0.X - P.X; let avgP: f32 = 0.5 * P0.M.x * (Pf(P.M) + Pf(P0.M)); F = F - (0.5 * G(1. * dx) * avgP * dx); avgV = avgV + (P0.M.x * G(1. * dx) * vec3(P0.V, 1.)); } } avgV.y = avgV.y / (avgV.z); avgV.x = avgV.x / (avgV.z); //viscosity F = F + (0. * P.M.x * (avgV.xy - P.V)); //gravity F = F + (P.M.x * vec2(0., -0.0004)); if (Mouse.z > 0.) { let dm: vec2 = (Mouse.xy - Mouse.zw) / 10.; let d: f32 = distance(Mouse.xy, P.X) / 20.; F = F + (0.001 * dm * exp(-d * d)); } var P1: particle = P; //integrate P1.V = P1.V + (F * dt / P1.M.x); //border let N: vec3 = bN(P1.X); let vdotN: f32 = step(N.z, border_h) * dot(-N.xy, P1.V); P1.V = P1.V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN))); P1.V = P1.V + (0. * P1.M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z)); if (N.z < 0.) { P1.V = vec2(0.); } //velocity limit let v: f32 = length(P1.V); var vv: f32; if (v > 1.) { vv = v; } else { vv = 1.; }; P1.V = P1.V / vv; return P1; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { // } // fn mainImage( U: vec4, pos: vec2) -> () { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let pos: vec2 = vec2(location); R = uni.iResolution.xy; time = uni.iTime; Mouse = uni.iMouse; let p: vec2 = location; // let data: vec4 = texel(buffer_a, pos); let data: vec4 = textureLoad(buffer_a, location); var P: particle = getParticle(data, pos); if (P.M.x != 0.) { P = Simulation(buffer_a, P, pos); } if (length(P.X - R * vec2(0.8, 0.9)) < 10.) { P.X = pos; P.V = 0.5 * Dir(-PI * 0.25 - PI * 0.5 + 0.3 * sin(0.4 * time)); P.M = mix(P.M, vec2(fluid_rho, 1.), 0.4); } if (length(P.X - R * vec2(0.2, 0.9)) < 10.) { P.X = pos; P.V = 0.5 * Dir(-PI * 0.25 + 0.3 * sin(0.3 * time)); P.M = mix(P.M, vec2(fluid_rho, 0.), 0.4); } // U = saveParticle(P, pos); textureStore(buffer_b, location, saveParticle(P, pos)); } ================================================ FILE: bin/assets/shaders/mixing_liquid/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // struct Particle { // a: vec4; // b: vec4; // }; // fn dum(x: Particle) { // let x2 = Particle(x.a, x.b); // let bah = x.a + 1.0; // return; // } // fn miam() -> Particle { // var out: Particle; // out.a = vec4(0.0); // out.b = vec4(1.0); // return out; // } // let ch0: texture_storage_2d = buffer_a; // let ch1: texture_storage_2d = buffer_a; // let ch2: texture_storage_2d = buffer_a; // let ch3: texture_storage_2d = buffer_a; // #define Bf(p) p // #define Bi(p) ivec2(p) // #define texel(a, p) texelFetch(a, Bi(p), 0) // #define pixel(a, p) texture(a, (p)/R) let PI = 3.14159265; let dt = 1.5; let border_h = 5.; var R: vec2 ; var Mouse: vec4 ; var time: f32; let mass = 1.; let fluid_rho = 0.5; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox( p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn border(p: vec2) -> f32 { let bound: f32 = -sdBox(p - R * 0.5, R * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time) * (p - R * vec2(0.5, 0.6)), R * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R * vec2(0.5, 0.7), R * vec2(1.5, 0.5)); return max(drain, min(bound, box)); } let h: f32 = 1.; fn bN(p: vec2) -> vec3 { let dx: vec3 = vec3(-h, 0.0, h); let idx: vec4 = vec4(-1./h, 0., 1./h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx); return vec3(normalize(r.xy), r.z + 1e-4); } fn pack(x: vec2) -> u32 { let x2: vec2 = 65534. * clamp(0.5 * x + 0.5, vec2(0.), vec2(1.)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw); return P; } fn saveParticle(P: particle, pos: vec2) -> vec4 { var P2: particle = particle(P.X, P.V, P.M); P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); return vec4(encode(P2.X), encode(P2.V), P2.M); } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } let dif: f32 = 1.12; fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } // don't forget to use a return value when using Reintegration fn Reintegration(ch: texture_storage_2d, pos: vec2) -> particle { //basically integral over all updated neighbor distributions //that fall inside of this pixel //this makes the tracking conservative for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(i)); // let data: vec4 = texel(ch, tpos); // let data: vec4 = texelFetch(ch, ivec2(tpos), 0); let data: vec4 = textureLoad(ch, vec2(tpos)); var P0: particle = getParticle(data, tpos); P0.X = P0.X + (P0.V * dt);//integrate position let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x); let D: vec3 = distribution(P0.X, pos, difR); //the deposited mass into this cell let m: f32 = P0.M.x * D.z; var P1: particle; // TODO: change the input particle directly using (*P).X = ... //add weighted by mass P1.X = P1.X + (D.xy * m); P1.V = P1.V + (P0.V * m); P1.M.y = P1.M.y + (P0.M.y * m); //add mass P1.M.x = P1.M.x + (m); } } //normalization if (P1.M.x != 0.) { P1.X = P1.X / (P1.M.x); P1.V = P1.V / (P1.M.x); P1.M.y = P1.M.y / (P1.M.x); } return P1; } fn Simulation(ch: texture_storage_2d, P: particle, pos: vec2) -> particle { var F: vec2 = vec2(0.); var avgV: vec3 = vec3(0.); for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(i)); // let data: vec4 = texel(ch, tpos); // let data: vec4 = texelFetch(ch, ivec2(tpos), 0); let data: vec4 = textureLoad(ch, vec2(tpos)); let P0: particle = getParticle(data, tpos); let dx: vec2 = P0.X - P.X; let avgP: f32 = 0.5 * P0.M.x * (Pf(P.M) + Pf(P0.M)); F = F - (0.5 * G(1. * dx) * avgP * dx); avgV = avgV + (P0.M.x * G(1. * dx) * vec3(P0.V, 1.)); } } avgV.y = avgV.y / (avgV.z); avgV.x = avgV.x / (avgV.z); //viscosity F = F + (0. * P.M.x * (avgV.xy - P.V)); //gravity F = F + (P.M.x * vec2(0., -0.0004)); if (Mouse.z > 0.) { let dm: vec2 = (Mouse.xy - Mouse.zw) / 10.; let d: f32 = distance(Mouse.xy, P.X) / 20.; F = F + (0.001 * dm * exp(-d * d)); } var P1: particle = P; //integrate P1.V = P1.V + (F * dt / P1.M.x); //border let N: vec3 = bN(P1.X); let vdotN: f32 = step(N.z, border_h) * dot(-N.xy, P1.V); P1.V = P1.V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN))); P1.V = P1.V + (0. * P1.M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z)); if (N.z < 0.) { P1.V = vec2(0.); } //velocity limit let v: f32 = length(P1.V); var vv: f32; if (v > 1.) { vv = v; } else { vv = 1.; }; P1.V = P1.V / vv; return P1; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { // fn mainImage( fragColor: vec4, pos: vec2) -> () { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); R = uni.iResolution.xy; time = uni.iTime; let pos = vec2(location); let p: vec2 = vec2(pos); let data: vec4 = textureLoad(buffer_a, location); var P: particle = getParticle(data, pos); // let data: vec4 = texel(ch0, pos); // let P: particle = getParticle(data, pos); var rho: vec4 = vec4(0.); for (var i: i32 = -1; i <= 1; i = i + 1) { for (var j: i32 = -1; j <= 1; j = j + 1) { let ij: vec2 = vec2(i, j); // let data: vec4 = texel(ch0, pos + ij); let data: vec4 = textureLoad(buffer_a, location + ij); var P0: particle = getParticle(data, pos + vec2(ij)); let x0: vec2 = P0.X; rho = rho + (1. * vec4(P.V, P.M) * G((pos - x0) / 0.75)); } } textureStore(buffer_c, location, rho); } ================================================ FILE: bin/assets/shaders/mixing_liquid/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // struct Particle { // a: vec4; // b: vec4; // }; // fn dum(x: Particle) { // let x2 = Particle(x.a, x.b); // let bah = x.a + 1.0; // return; // } // fn miam() -> Particle { // var out: Particle; // out.a = vec4(0.0); // out.b = vec4(1.0); // return out; // } // let ch0: texture_storage_2d = buffer_a; // let ch1: texture_storage_2d = buffer_a; // let ch2: texture_storage_2d = buffer_a; // let ch3: texture_storage_2d = buffer_a; // #define Bf(p) p // #define Bi(p) ivec2(p) // #define texel(a, p) texelFetch(a, Bi(p), 0) // #define pixel(a, p) texture(a, (p)/R) let PI = 3.14159265; let dt = 1.5; let border_h = 5.; var R: vec2 ; var Mouse: vec4 ; var time: f32; let mass = 1.; let fluid_rho = 0.5; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox( p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn border(p: vec2) -> f32 { let bound: f32 = -sdBox(p - R * 0.5, R * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time) * (p - R * vec2(0.5, 0.6)), R * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R * vec2(0.5, 0.7), R * vec2(1.5, 0.5)); return max(drain, min(bound, box)); } let h: f32 = 1.; fn bN(p: vec2) -> vec3 { let dx: vec3 = vec3(-h, 0.0, h); let idx: vec4 = vec4(-1./h, 0., 1./h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx); return vec3(normalize(r.xy), r.z + 1e-4); } fn pack(x: vec2) -> u32 { let x2: vec2 = 65534. * clamp(0.5 * x + 0.5, vec2(0.), vec2(1.)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw); return P; } fn saveParticle(P: particle, pos: vec2) -> vec4 { var P2: particle = particle(P.X, P.V, P.M); P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); return vec4(encode(P2.X), encode(P2.V), P2.M); } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } let dif: f32 = 1.12; fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } // don't forget to use a return value when using Reintegration fn Reintegration(ch: texture_storage_2d, pos: vec2) -> particle { //basically integral over all updated neighbor distributions //that fall inside of this pixel //this makes the tracking conservative for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(i)); // let data: vec4 = texel(ch, tpos); // let data: vec4 = texelFetch(ch, ivec2(tpos), 0); let data: vec4 = textureLoad(ch, vec2(tpos)); var P0: particle = getParticle(data, tpos); P0.X = P0.X + (P0.V * dt);//integrate position let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x); let D: vec3 = distribution(P0.X, pos, difR); //the deposited mass into this cell let m: f32 = P0.M.x * D.z; var P1: particle; // TODO: change the input particle directly using (*P).X = ... //add weighted by mass P1.X = P1.X + (D.xy * m); P1.V = P1.V + (P0.V * m); P1.M.y = P1.M.y + (P0.M.y * m); //add mass P1.M.x = P1.M.x + (m); } } //normalization if (P1.M.x != 0.) { P1.X = P1.X / (P1.M.x); P1.V = P1.V / (P1.M.x); P1.M.y = P1.M.y / (P1.M.x); } return P1; } fn Simulation(ch: texture_storage_2d, P: particle, pos: vec2) -> particle { var F: vec2 = vec2(0.); var avgV: vec3 = vec3(0.); for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(i)); // let data: vec4 = texel(ch, tpos); // let data: vec4 = texelFetch(ch, ivec2(tpos), 0); let data: vec4 = textureLoad(ch, vec2(tpos)); let P0: particle = getParticle(data, tpos); let dx: vec2 = P0.X - P.X; let avgP: f32 = 0.5 * P0.M.x * (Pf(P.M) + Pf(P0.M)); F = F - (0.5 * G(1. * dx) * avgP * dx); avgV = avgV + (P0.M.x * G(1. * dx) * vec3(P0.V, 1.)); } } avgV.y = avgV.y / (avgV.z); avgV.x = avgV.x / (avgV.z); //viscosity F = F + (0. * P.M.x * (avgV.xy - P.V)); //gravity F = F + (P.M.x * vec2(0., -0.0004)); if (Mouse.z > 0.) { let dm: vec2 = (Mouse.xy - Mouse.zw) / 10.; let d: f32 = distance(Mouse.xy, P.X) / 20.; F = F + (0.001 * dm * exp(-d * d)); } var P1: particle = P; //integrate P1.V = P1.V + (F * dt / P1.M.x); //border let N: vec3 = bN(P1.X); let vdotN: f32 = step(N.z, border_h) * dot(-N.xy, P1.V); P1.V = P1.V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN))); P1.V = P1.V + (0. * P1.M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z)); if (N.z < 0.) { P1.V = vec2(0.); } //velocity limit let v: f32 = length(P1.V); var vv: f32; if (v > 1.) { vv = v; } else { vv = 1.; }; P1.V = P1.V / vv; return P1; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: bin/assets/shaders/mixing_liquid/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // let color = vec4(f32(0)); // textureStore(texture, location, color); // } // struct Particle { // a: vec4; // b: vec4; // }; // fn dum(x: Particle) { // let x2 = Particle(x.a, x.b); // let bah = x.a + 1.0; // return; // } // fn miam() -> Particle { // var out: Particle; // out.a = vec4(0.0); // out.b = vec4(1.0); // return out; // } // let ch0: texture_storage_2d = buffer_a; // let ch1: texture_storage_2d = buffer_a; // let ch2: texture_storage_2d = buffer_a; // let ch3: texture_storage_2d = buffer_a; // #define Bf(p) p // #define Bi(p) ivec2(p) // #define texel(a, p) texelFetch(a, Bi(p), 0) // #define pixel(a, p) texture(a, (p)/R) let PI = 3.14159265; let dt = 1.5; let border_h = 5.; var R: vec2 ; var Mouse: vec4 ; var time: f32; let mass = 1.; let fluid_rho = 0.5; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox( p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn border(p: vec2) -> f32 { let bound: f32 = -sdBox(p - R * 0.5, R * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time) * (p - R * vec2(0.5, 0.6)), R * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R * vec2(0.5, 0.7), R * vec2(1.5, 0.5)); return max(drain, min(bound, box)); } let h: f32 = 1.; fn bN(p: vec2) -> vec3 { let dx: vec3 = vec3(-h, 0.0, h); let idx: vec4 = vec4(-1./h, 0., 1./h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx); return vec3(normalize(r.xy), r.z + 1e-4); } fn pack(x: vec2) -> u32 { let x2: vec2 = 65534. * clamp(0.5 * x + 0.5, vec2(0.), vec2(1.)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw); return P; } fn saveParticle(P: particle, pos: vec2) -> vec4 { var P2: particle = particle(P.X, P.V, P.M); P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); return vec4(encode(P2.X), encode(P2.V), P2.M); } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } let dif: f32 = 1.12; fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } // don't forget to use a return value when using Reintegration fn Reintegration(ch: texture_storage_2d, pos: vec2) -> particle { //basically integral over all updated neighbor distributions //that fall inside of this pixel //this makes the tracking conservative for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(i)); // let data: vec4 = texel(ch, tpos); // let data: vec4 = texelFetch(ch, ivec2(tpos), 0); let data: vec4 = textureLoad(ch, vec2(tpos)); var P0: particle = getParticle(data, tpos); P0.X = P0.X + (P0.V * dt);//integrate position let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x); let D: vec3 = distribution(P0.X, pos, difR); //the deposited mass into this cell let m: f32 = P0.M.x * D.z; var P1: particle; // TODO: change the input particle directly using (*P).X = ... //add weighted by mass P1.X = P1.X + (D.xy * m); P1.V = P1.V + (P0.V * m); P1.M.y = P1.M.y + (P0.M.y * m); //add mass P1.M.x = P1.M.x + (m); } } //normalization if (P1.M.x != 0.) { P1.X = P1.X / (P1.M.x); P1.V = P1.V / (P1.M.x); P1.M.y = P1.M.y / (P1.M.x); } return P1; } fn Simulation(ch: texture_storage_2d, P: particle, pos: vec2) -> particle { var F: vec2 = vec2(0.); var avgV: vec3 = vec3(0.); for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(i)); // let data: vec4 = texel(ch, tpos); // let data: vec4 = texelFetch(ch, ivec2(tpos), 0); let data: vec4 = textureLoad(ch, vec2(tpos)); let P0: particle = getParticle(data, tpos); let dx: vec2 = P0.X - P.X; let avgP: f32 = 0.5 * P0.M.x * (Pf(P.M) + Pf(P0.M)); F = F - (0.5 * G(1. * dx) * avgP * dx); avgV = avgV + (P0.M.x * G(1. * dx) * vec3(P0.V, 1.)); } } avgV.y = avgV.y / (avgV.z); avgV.x = avgV.x / (avgV.z); //viscosity F = F + (0. * P.M.x * (avgV.xy - P.V)); //gravity F = F + (P.M.x * vec2(0., -0.0004)); if (Mouse.z > 0.) { let dm: vec2 = (Mouse.xy - Mouse.zw) / 10.; let d: f32 = distance(Mouse.xy, P.X) / 20.; F = F + (0.001 * dm * exp(-d * d)); } var P1: particle = P; //integrate P1.V = P1.V + (F * dt / P1.M.x); //border let N: vec3 = bN(P1.X); let vdotN: f32 = step(N.z, border_h) * dot(-N.xy, P1.V); P1.V = P1.V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN))); P1.V = P1.V + (0. * P1.M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z)); if (N.z < 0.) { P1.V = vec2(0.); } //velocity limit let v: f32 = length(P1.V); var vv: f32; if (v > 1.) { vv = v; } else { vv = 1.; }; P1.V = P1.V / vv; return P1; } // displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a // here // fn even(uv: f32) -> f32 { // var tempo: f32 = 0.0; // let whatever = modf(uv + 1.0, &tempo); // var temp2 = 0.; // let frac = modf(tempo / 2.0, &temp2); // if (abs(frac) < 0.001) { // return 1.0; // } else { // return 0.0; // } // } fn hsv2rgb( c: vec3) -> vec3 { // var fractional: f32 = 0.0; // let m = modf(c.x * 6. + vec3(0., 4., 2.) / 6., &fractional); let v = vec3(0., 4., 2.); let fractional: vec3 = vec3(vec3( (c.x * 6. + v) / 6.0)) ; // let whatever = modf(uv + 1.0, &tempo); // var temp2 = 0.; // let frac = modf(tempo / 2.0, &temp2); let af: vec3 = abs(fractional - 3.) - 1.; var rgb: vec3 = clamp(af, vec3(0.), vec3(1.)); rgb = rgb * rgb * (3. - 2. * rgb); return c.z * mix(vec3(1.), rgb, c.y); } fn mixN(a: vec3, b: vec3, k: f32) -> vec3 { return sqrt(mix(a * a, b * b, clamp(k, 0., 1.))); } fn V(p: vec2) -> vec4 { // return pixel(ch1, p); return textureLoad(buffer_c, vec2(p )); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // var O: vec4 = textureLoad(buffer_a, location); // textureStore(texture, location, O); // } // fn mainImage( col: vec4, pos: vec2) -> () { R = uni.iResolution.xy; time = uni.iTime; // let p: vec2 = vec2(pos); // let data: vec4 = texel(ch0, pos); let p: vec2 = location; let data: vec4 = textureLoad(buffer_a, location); let pos = vec2(location); var P: particle = getParticle(data, pos); let Nb: vec3 = bN(P.X); let bord: f32 = smoothStep(2. * border_h, border_h * 0.5, border(pos)); let rho: vec4 = V(pos); let dx: vec3 = vec3(-2., 0., 2.); let grad: vec4 = -0.5 * vec4( V(pos + dx.zy).zw - V(pos + dx.xy).zw, V(pos + dx.yz).zw - V(pos + dx.yx).zw); let N: vec2 = pow(length(grad.xz), 0.2) * normalize(grad.xz + 0.00001); let specular: f32 = pow(max(dot(N, Dir(1.4)), 0.), 3.5); let specularb: f32 = G(0.4 * (Nb.zz - border_h)) * pow(max(dot(Nb.xy, Dir(1.4)), 0.), 3.); let a: f32 = pow(smoothStep(fluid_rho * 0., fluid_rho * 2., rho.z), 0.1); let b: f32 = exp(-1.7 * smoothStep(fluid_rho * 1., fluid_rho * 7.5, rho.z)); let col0: vec3 = vec3(1., 0.5, 0.); let col1: vec3 = vec3(0.1, 0.4, 1.); let fcol: vec3 = mixN(col0, col1, tanh(3. * (rho.w - 0.7)) * 0.5 + 0.5); // var col: vec4; var col: vec3 = vec3(3.); col = mixN(col.xyz, fcol.xyz * (1.5 * b + specular * 5.), a); col = mixN(col, 0. * vec3(0.5, 0.5, 1.), bord); col = tanh(col); let col4 = vec4(col, 0.3); textureStore(texture, location, rho); } ================================================ FILE: bin/assets/shaders/paint/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; type float2 = vec2; type float4 = vec4; fn hue(v: f32) -> vec4 { return (vec4(.6) + vec4(.6) * cos( vec4(6.3 * v) + vec4(0.0,23.0,21.0,0.0 ) )); } fn smoothit(v: f32) -> f32{ return smoothStep( 1.5, 0., v ); } fn sdSegment(p: vec2, a: vec2, b: vec2) -> f32 { let pa = p - a; let ba = b - a; let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.); return length(pa - ba * h); } fn sdRhombus(p: vec2, b: vec2) -> f32 { let q = abs(p); let qb = dot(q, vec2(b.x, -b.y)); let bb = dot(b, vec2(b.x, -b.y)); let h = clamp((-2. * qb + bb) / dot(b, b), -1., 1.); let d = length(q - 0.5 * b * vec2(1. - h, 1. + h)); return d * sign(q.x * b.y + q.y * b.x - b.x * b.y); } fn sdTriangleIsosceles(p: vec2, c: vec2) -> f32 { let q = vec2(abs(p.x), p.y); let a = q - c * clamp(dot(q, c) / dot(c, c), 0., 1.); let b = q - c * vec2(clamp(q.x / c.x, 0., 1.), 1.); let s = -sign(c.y); let d = min(vec2(dot(a, a), s * (q.x * c.y - q.y * c.x)), vec2(dot(b, b), s * (q.y - c.y))); return -sqrt(d.x) * sign(d.y); } fn sdStar(p: vec2, r: f32, n: u32, m: f32) ->f32 { let an = 3.141593 / f32(n); let en = 3.141593 / m; let acs = vec2(cos(an), sin(an)); let ecs = vec2(cos(en), sin(en)); let bn = (atan2(abs(p.x), p.y) % (2. * an)) - an; var q: vec2 = length(p) * vec2(cos(bn), abs(sin(bn))); q = q - r * acs; q = q + ecs * clamp(-dot(q, ecs), 0., r * acs.y / ecs.y); return length(q) * sign(q.x); } fn sdHeart(p: vec2) -> f32 { let q = vec2(abs(p.x), p.y); let w = q - vec2(0.25, 0.75); if (q.x + q.y > 1.0) { return sqrt(dot(w, w)) - sqrt(2.) / 4.; } let u = q - vec2(0., 1.0); let v = q - 0.5 * max(q.x + q.y, 0.); return sqrt(min(dot(u, u), dot(v, v))) * sign(q.x - q.y); } fn sdMoon(p: vec2, d: f32, ra: f32, rb: f32) -> f32 { let q = vec2(p.x, abs(p.y)); let a = (ra * ra - rb * rb + d * d) / (2. * d); let b = sqrt(max(ra * ra - a * a, 0.)); if (d * (q.x * b - q.y * a) > d * d * max(b - q.y, 0.)) { return length(q-vec2(a, b)); } return max((length(q) - ra), -(length(q - vec2(d, 0.)) - rb)); } fn sdCross(p: vec2, b: vec2) -> f32 { var q: vec2 = abs(p); q = select(q.xy, q.yx, q.y > q.x); let t = q - b; let k = max(t.y, t.x); let w = select(vec2(b.y - q.x, -k), t, k > 0.); return sign(k) * length(max(w, vec2(0.))); } fn sdRoundedX(p: vec2, w: f32, r: f32) -> f32 { let q = abs(p); return length(q - min(q.x + q.y, w) * 0.5) - r; } fn sdCircle(p: vec2, c: vec2, r: f32) -> f32 { let d = length(p - c); return d - r; } // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // # ifdef INIT // if (location.x == 0 && location.y == 0 ) { // textureStore(buffer_a, location, hue(4.0 / 8.0)); // } else { // // set brush color to black // let black = vec4(0.0, 0.0, 0.0, 1.0); // textureStore(buffer_a, location, black); // } // # endif // } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // the first three frames are not directed inside the update function. // The first time this function is called is on frame 4. if (i32(uni.iFrame) == 3) { // # ifdef INIT if (location.x == 0 && location.y == 0 ) { textureStore(buffer_a, location, hue(4.0 / 8.0)); } else { // set brush color to black let black = vec4(0.0, 0.0, 0.0, 1.0); textureStore(buffer_a, location, black); } // # endif } let R: float2 = uni.iResolution.xy; let U: vec2 = vec2(location) / R; let M: float2 = vec2(uni.iMouse.x, 1.0-uni.iMouse.y); var O: float4 = textureLoad(buffer_a, location); if (location.x == 0 && location.y == 0 ) { if ( uni.iMouse.x < 0.1 && uni.iMouse.w == 1.0) { // just pressed left mouse button let y: f32 = floor(9.*M.y); O = hue( y/8. ); textureStore(buffer_a, location, O); } return; } // display palette on left if ( U.x < 0.1 ) { let y: f32 = floor(9.*U.y); O = hue( y/8. ); O.w = 1.; textureStore(buffer_a, location, O); return; } // let brush_color = float4(1., 0., 0., 1.); let brush_color = textureLoad(buffer_a, vec2(0,0)); // apply paint if (uni.iMouse.z == 1.0) { let mouse_pix = vec2(uni.iMouse.x * R.x, (1.0 - uni.iMouse.y) * R.y ); let brush_sdf = sdCircle(vec2(location), mouse_pix, 10.0); let brush_d = smoothStep(0.0, 5.0, brush_sdf); O = mix(O, brush_color, (1.0-brush_d) * 0.01); } textureStore(buffer_a, location, O); } ================================================ FILE: bin/assets/shaders/paint/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: bin/assets/shaders/paint/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_c, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_c, location, vec4(0.95)); // if (uni.iTime > 1.0) { // textureStore(buffer_c, location, vec4(0.95)); // } } ================================================ FILE: bin/assets/shaders/paint/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let color = vec4(0.60); textureStore(buffer_d, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_d, location, vec4(0.7)); if (uni.iTime > 1.0) { storageBarrier(); textureStore(buffer_d, location, vec4(0.95)); } // storageBarrier(); } ================================================ FILE: bin/assets/shaders/paint/common.wgsl ================================================ // unused #define_import_path bevy_shadertoy_wgsl::assets::shaders::common struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; ================================================ FILE: bin/assets/shaders/paint/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // let color = vec4(f32(0)); // textureStore(texture, location, color); // } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var alive = true; var O: vec4 = textureLoad(buffer_a, location); textureStore(texture, location, O); } ================================================ FILE: bin/assets/shaders/paint2/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; type float2 = vec2; type float4 = vec4; fn hue(v: f32) -> vec4 { return (vec4(.6) + vec4(.6) * cos( vec4(6.3 * v) + vec4(0.0,23.0,21.0,0.0 ) )); } fn smoothit(v: f32) -> f32{ return smoothStep( 1.5, 0., v ); } fn sdSegment(p: vec2, a: vec2, b: vec2) -> f32 { let pa = p - a; let ba = b - a; let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.); return length(pa - ba * h); } fn sdRhombus(p: vec2, b: vec2) -> f32 { let q = abs(p); let qb = dot(q, vec2(b.x, -b.y)); let bb = dot(b, vec2(b.x, -b.y)); let h = clamp((-2. * qb + bb) / dot(b, b), -1., 1.); let d = length(q - 0.5 * b * vec2(1. - h, 1. + h)); return d * sign(q.x * b.y + q.y * b.x - b.x * b.y); } fn sdTriangleIsosceles(p: vec2, c: vec2) -> f32 { let q = vec2(abs(p.x), p.y); let a = q - c * clamp(dot(q, c) / dot(c, c), 0., 1.); let b = q - c * vec2(clamp(q.x / c.x, 0., 1.), 1.); let s = -sign(c.y); let d = min(vec2(dot(a, a), s * (q.x * c.y - q.y * c.x)), vec2(dot(b, b), s * (q.y - c.y))); return -sqrt(d.x) * sign(d.y); } fn sdStar(p: vec2, r: f32, n: u32, m: f32) ->f32 { let an = 3.141593 / f32(n); let en = 3.141593 / m; let acs = vec2(cos(an), sin(an)); let ecs = vec2(cos(en), sin(en)); let bn = (atan2(abs(p.x), p.y) % (2. * an)) - an; var q: vec2 = length(p) * vec2(cos(bn), abs(sin(bn))); q = q - r * acs; q = q + ecs * clamp(-dot(q, ecs), 0., r * acs.y / ecs.y); return length(q) * sign(q.x); } fn sdHeart(p: vec2) -> f32 { let q = vec2(abs(p.x), p.y); let w = q - vec2(0.25, 0.75); if (q.x + q.y > 1.0) { return sqrt(dot(w, w)) - sqrt(2.) / 4.; } let u = q - vec2(0., 1.0); let v = q - 0.5 * max(q.x + q.y, 0.); return sqrt(min(dot(u, u), dot(v, v))) * sign(q.x - q.y); } fn sdMoon(p: vec2, d: f32, ra: f32, rb: f32) -> f32 { let q = vec2(p.x, abs(p.y)); let a = (ra * ra - rb * rb + d * d) / (2. * d); let b = sqrt(max(ra * ra - a * a, 0.)); if (d * (q.x * b - q.y * a) > d * d * max(b - q.y, 0.)) { return length(q-vec2(a, b)); } return max((length(q) - ra), -(length(q - vec2(d, 0.)) - rb)); } fn sdCross(p: vec2, b: vec2) -> f32 { var q: vec2 = abs(p); q = select(q.xy, q.yx, q.y > q.x); let t = q - b; let k = max(t.y, t.x); let w = select(vec2(b.y - q.x, -k), t, k > 0.); return sign(k) * length(max(w, vec2(0.))); } fn sdRoundedX(p: vec2, w: f32, r: f32) -> f32 { let q = abs(p); return length(q - min(q.x + q.y, w) * 0.5) - r; } fn sdCircle(p: vec2, c: vec2, r: f32) -> f32 { let d = length(p - c); return d - r; } // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // # ifdef INIT // if (location.x == 0 && location.y == 0 ) { // textureStore(buffer_a, location, hue(4.0 / 8.0)); // } else { // // set brush color to black // let black = vec4(0.0, 0.0, 0.0, 1.0); // textureStore(buffer_a, location, black); // } // # endif // } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // the first three frames are not directed inside the update function. // The first time this function is called is on frame 4. if (i32(uni.iFrame) == 3) { // # ifdef INIT if (location.x == 0 && location.y == 0 ) { textureStore(buffer_a, location, hue(4.0 / 8.0)); } else { // set brush color to black let black = vec4(0.0, 0.0, 0.0, 1.0); textureStore(buffer_a, location, black); } // # endif } let R: float2 = uni.iResolution.xy; let U: vec2 = vec2(location) / R; let M: float2 = vec2(uni.iMouse.x, 1.0-uni.iMouse.y); var O: float4 = textureLoad(buffer_a, location); if (location.x == 0 && location.y == 0 ) { if ( uni.iMouse.x < 0.1 && uni.iMouse.w == 1.0) { // just pressed left mouse button let y: f32 = floor(9.*M.y); O = hue( y/8. ); textureStore(buffer_a, location, O); } return; } // display palette on left if ( U.x < 0.1 ) { let y: f32 = floor(9.*U.y); O = hue( y/8. ); O.w = 1.; textureStore(buffer_a, location, O); return; } // let brush_color = float4(1., 0., 0., 1.); let brush_color = textureLoad(buffer_a, vec2(0,0)); // apply paint if (uni.iMouse.z == 1.0) { let mouse_pix = vec2(uni.iMouse.x * R.x, (1.0 - uni.iMouse.y) * R.y ); let brush_sdf = sdCircle(vec2(location), mouse_pix, 10.0); let brush_d = smoothStep(0.0, 5.0, brush_sdf); O = mix(O, brush_color, (1.0-brush_d) * 0.01); } textureStore(buffer_a, location, O); } ================================================ FILE: bin/assets/shaders/paint2/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: bin/assets/shaders/paint2/buffer_c.wgsl ================================================ [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: bin/assets/shaders/paint2/buffer_d.wgsl ================================================ [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: bin/assets/shaders/paint2/common.wgsl ================================================ // unused #define_import_path bevy_shadertoy_wgsl::assets::shaders::common struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; ================================================ FILE: bin/assets/shaders/paint2/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // let color = vec4(f32(0)); // textureStore(texture, location, color); // } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var alive = true; var O: vec4 = textureLoad(buffer_a, location); textureStore(texture, location, O); } ================================================ FILE: bin/assets/shaders/paint2/image2.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: i32; iSampleRate: i32; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; iResolution: vec2; iMouse: vec2; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(f32(0)); textureStore(texture, location, color); } fn hash(value: u32) -> u32 { var state = value; state = state ^ 2747636419u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; return state; } fn randomFloat(value: u32) -> f32 { return f32(hash(value)) / 4294967295.0; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var alive = true; var O: vec4 = textureLoad(buffer_a, location); // let color = vec4(O.x, 0.1, 0.12, 1.0); // storageBarrier(); // textureStore(texture, location, vec4(color)); textureStore(texture, location, O); } ================================================ FILE: bin/assets/shaders/paint_streams/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // struct Particle { // a: vec4; // b: vec4; // }; // fn dum(x: Particle) { // let x2 = Particle(x.a, x.b); // let bah = x.a + 1.0; // return; // } // fn miam() -> Particle { // var out: Particle; // out.a = vec4(0.0); // out.b = vec4(1.0); // return out; // } // let ch0: texture_storage_2d = buffer_a; // let ch1: texture_storage_2d = buffer_a; // let ch2: texture_storage_2d = buffer_a; // let ch3: texture_storage_2d = buffer_a; // #define Bf(p) p // #define Bi(p) ivec2(p) // #define texel(a, p) texelFetch(a, Bi(p), 0) // #define pixel(a, p) texture(a, (p)/R) let PI = 3.14159265; let dt = 1.5; let border_h = 5.; // var R: vec2 ; // var Mouse: vec4 ; // var time: f32; let mass = 1.; let h: f32 = 1.; let fluid_rho = 0.5; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox( p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn pack(x: vec2) -> u32 { let x2: vec2 = 65534. * clamp(0.5 * x + 0.5, vec2(0.), vec2(1.)); return u32(round(x2.x)) + 65535u * u32(round(x2.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle = particle( decode(data.x) + pos, decode(data.y), data.zw ); return P; } fn saveParticle(P: particle, pos: vec2) -> vec4 { var P2: particle = particle(P.X, P.V, P.M); P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); return vec4(encode(P2.X), encode(P2.V), P2.M); } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } let dif: f32 = 1.12; fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } // don't forget to use a return value when using Reintegration fn Reintegration(ch: texture_storage_2d, pos: vec2) -> particle { //basically integral over all updated neighbor distributions //that fall inside of this pixel //this makes the tracking conservative for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(j)); // let data: vec4 = texel(ch, tpos); // let data: vec4 = texelFetch(ch, ivec2(tpos), 0); let data: vec4 = textureLoad(ch, vec2(tpos)); var P0: particle = getParticle(data, tpos); P0.X = P0.X + (P0.V * dt);//integrate position let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x); let D: vec3 = distribution(P0.X, pos, difR); //the deposited mass into this cell let m: f32 = P0.M.x * D.z; var P1: particle; // TODO: change the input particle directly using (*P).X = ... //add weighted by mass P1.X = P1.X + (D.xy * m); P1.V = P1.V + (P0.V * m); P1.M.y = P1.M.y + (P0.M.y * m); //add mass P1.M.x = P1.M.x + (m); } } //normalization if (P1.M.x != 0.) { P1.X = P1.X / (P1.M.x); P1.V = P1.V / (P1.M.x); P1.M.y = P1.M.y / (P1.M.x); } return P1; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let R2 = uni.iResolution.xy; let location = vec2(i32(invocation_id.x), i32(R2.y) - i32(invocation_id.y)); let pos: vec2 = vec2(location); // Mouse = uni.iMouse; var P: particle; // if (uni.iFrame < 4.0) { // if (Mouse.z > 0.5) { #ifdef INIT let rand: vec3 = hash32(pos); // let rand = vec3(0.2, -0.2, -0.2); if (rand.z < 0.) { P.X = pos; P.V = 0.5 * (rand.xy - 0.5) + vec2(0., 0.); P.M = vec2(mass, 0.); } else { P.X = pos; P.V = vec2(0.); P.M = vec2(0.000001); } #else P = Reintegration(buffer_b, pos); #endif textureStore(buffer_a, location, saveParticle(P, pos)); } ================================================ FILE: bin/assets/shaders/paint_streams/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // struct Particle { // a: vec4; // b: vec4; // }; // fn dum(x: Particle) { // let x2 = Particle(x.a, x.b); // let bah = x.a + 1.0; // return; // } // fn miam() -> Particle { // var out: Particle; // out.a = vec4(0.0); // out.b = vec4(1.0); // return out; // } // let ch0: texture_storage_2d = buffer_a; // let ch1: texture_storage_2d = buffer_a; // let ch2: texture_storage_2d = buffer_a; // let ch3: texture_storage_2d = buffer_a; // #define Bf(p) p // #define Bi(p) ivec2(p) // #define texel(a, p) texelFetch(a, Bi(p), 0) // #define pixel(a, p) texture(a, (p)/R) let PI = 3.14159265; let dt = 1.5; let border_h = 5.; // var R: vec2 ; // var Mouse: vec4 ; // var time: f32; let mass = 1.; let h: f32 = 1.; let fluid_rho = 0.5; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox( p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn pack(x: vec2) -> u32 { let x2: vec2 = 65534. * clamp(0.5 * x + 0.5, vec2(0.), vec2(1.)); return u32(round(x2.x)) + 65535u * u32(round(x2.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle = particle( decode(data.x) + pos, decode(data.y), data.zw ); return P; } fn saveParticle(P: particle, pos: vec2) -> vec4 { var P2: particle = particle(P.X, P.V, P.M); P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); return vec4(encode(P2.X), encode(P2.V), P2.M); } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } let dif: f32 = 1.12; fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } fn border(p: vec2, R2: vec2, time: f32) -> f32 { let bound: f32 = -sdBox(p - R2 * 0.5, R2 * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time) * (p - R2 * vec2(0.5, 0.6)), R2 * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R2 * vec2(0.5, 0.7), R2 * vec2(1.5, 0.5)); return max(drain, min(bound, box)); } fn bN(p: vec2, R2: vec2, time: f32) -> vec3 { let dx: vec3 = vec3(-h, 0.0, h); let idx: vec4 = vec4(-1./h, 0., 1./h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy, R2, time) + idx.xyw * border(p + dx.xy, R2, time) + idx.yzw * border(p + dx.yz, R2, time) + idx.yxw * border(p + dx.yx, R2, time); return vec3(normalize(r.xy), r.z + 1e-4); } fn Simulation( ch: texture_storage_2d, P: particle, pos: vec2, R2: vec2, time: f32, Mouse: vec4, ) -> particle { var F: vec2 = vec2(0.); var avgV: vec3 = vec3(0.); for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(j)); // let data: vec4 = texel(ch, tpos); // let data: vec4 = texelFetch(ch, ivec2(tpos), 0); let data: vec4 = textureLoad(ch, vec2(tpos)); let P0: particle = getParticle(data, tpos); let dx: vec2 = P0.X - P.X; let avgP: f32 = 0.5 * P0.M.x * (Pf(P.M) + Pf(P0.M)); F = F - (0.5 * G(1. * dx) * avgP * dx); avgV = avgV + (P0.M.x * G(1. * dx) * vec3(P0.V, 1.)); } } avgV.y = avgV.y / (avgV.z); avgV.x = avgV.x / (avgV.z); //viscosity F = F + (0. * P.M.x * (avgV.xy - P.V)); //gravity F = F + (P.M.x * vec2(0., -0.0004)); if (Mouse.z > 0.) { let dm: vec2 = (Mouse.xy - Mouse.zw) / 10.; let d: f32 = distance(Mouse.xy, P.X) / 20.; F = F + (0.001 * dm * exp(-d * d)); } var P1: particle = P; //integrate P1.V = P1.V + (F * dt / P1.M.x); //border let N: vec3 = bN(P1.X, R2, time); let vdotN: f32 = step(N.z, border_h) * dot(-N.xy, P1.V); P1.V = P1.V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN))); P1.V = P1.V + (0. * P1.M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z)); if (N.z < 0.) { P1.V = vec2(0.); } //velocity limit let v: f32 = length(P1.V); var vv: f32; if (v > 1.) { vv = v; } else { vv = 1.; }; P1.V = P1.V / vv; return P1; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { // } // fn mainImage( U: vec4, pos: vec2) -> () { let R2 = uni.iResolution.xy; let location = vec2(i32(invocation_id.x), i32(R2.y) - i32(invocation_id.y)); let pos: vec2 = vec2(location); let time = uni.iTime; let Mouse = uni.iMouse; let p: vec2 = location; // let data: vec4 = texel(buffer_a, pos); let data: vec4 = textureLoad(buffer_a, location); var P: particle = getParticle(data, pos); if (P.M.x != 0.) { P = Simulation(buffer_a, P, pos, R2, time, Mouse); } if (length(P.X - R2 * vec2(0.8, 0.9)) < 10.) { P.X = pos; P.V = 0.5 * Dir(-PI * 0.25 - PI * 0.5 + 0.3 * sin(0.4 * time)); P.M = mix(P.M, vec2(fluid_rho, 1.), 0.4); } if (length(P.X - R2 * vec2(0.2, 0.9)) < 10.) { P.X = pos; P.V = 0.5 * Dir(-PI * 0.25 + 0.3 * sin(0.3 * time)); P.M = mix(P.M, vec2(fluid_rho, 0.), 0.4); } // U = saveParticle(P, pos); textureStore(buffer_b, location, saveParticle(P, pos)); } ================================================ FILE: bin/assets/shaders/paint_streams/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // struct Particle { // a: vec4; // b: vec4; // }; // fn dum(x: Particle) { // let x2 = Particle(x.a, x.b); // let bah = x.a + 1.0; // return; // } // fn miam() -> Particle { // var out: Particle; // out.a = vec4(0.0); // out.b = vec4(1.0); // return out; // } // let ch0: texture_storage_2d = buffer_a; // let ch1: texture_storage_2d = buffer_a; // let ch2: texture_storage_2d = buffer_a; // let ch3: texture_storage_2d = buffer_a; // #define Bf(p) p // #define Bi(p) ivec2(p) // #define texel(a, p) texelFetch(a, Bi(p), 0) // #define pixel(a, p) texture(a, (p)/R) let PI = 3.14159265; let dt = 1.5; let border_h = 5.; // var R: vec2 ; // var Mouse: vec4 ; // var time: f32; let mass = 1.; let h: f32 = 1.; let fluid_rho = 0.5; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox( p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn pack(x: vec2) -> u32 { let x2: vec2 = 65534. * clamp(0.5 * x + 0.5, vec2(0.), vec2(1.)); return u32(round(x2.x)) + 65535u * u32(round(x2.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle = particle( decode(data.x) + pos, decode(data.y), data.zw ); return P; } fn saveParticle(P: particle, pos: vec2) -> vec4 { var P2: particle = particle(P.X, P.V, P.M); P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); return vec4(encode(P2.X), encode(P2.V), P2.M); } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } let dif: f32 = 1.12; fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { // fn mainImage( fragColor: vec4, pos: vec2) -> () { // let R = uni.iResolution.xy; let R2 = uni.iResolution.xy; let location = vec2(i32(invocation_id.x), i32(R2.y) - i32(invocation_id.y)); // R = uni.iResolution.xy; // time = uni.iTime; let pos = vec2(location); let p: vec2 = vec2(pos); let data: vec4 = textureLoad(buffer_a, location); var P: particle = getParticle(data, pos); // let data: vec4 = texel(ch0, pos); // let P: particle = getParticle(data, pos); var rho: vec4 = vec4(0.); for (var i: i32 = -1; i <= 1; i = i + 1) { for (var j: i32 = -1; j <= 1; j = j + 1) { let ij: vec2 = vec2(i, j); // let data: vec4 = texel(ch0, pos + ij); let data: vec4 = textureLoad(buffer_a, location + ij); var P0: particle = getParticle(data, pos + vec2(ij)); let x0: vec2 = P0.X; rho = rho + (1. * vec4(P.V, P.M) * G((pos - x0) / 0.75)); } } textureStore(buffer_c, location, rho); } ================================================ FILE: bin/assets/shaders/paint_streams/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; // struct Particle { // a: vec4; // b: vec4; // }; // fn dum(x: Particle) { // let x2 = Particle(x.a, x.b); // let bah = x.a + 1.0; // return; // } // fn miam() -> Particle { // var out: Particle; // out.a = vec4(0.0); // out.b = vec4(1.0); // return out; // } // let ch0: texture_storage_2d = buffer_a; // let ch1: texture_storage_2d = buffer_a; // let ch2: texture_storage_2d = buffer_a; // let ch3: texture_storage_2d = buffer_a; // #define Bf(p) p // #define Bi(p) ivec2(p) // #define texel(a, p) texelFetch(a, Bi(p), 0) // #define pixel(a, p) texture(a, (p)/R) let PI = 3.14159265; let dt = 1.5; let border_h = 5.; // var R: vec2 ; // var Mouse: vec4 ; // var time: f32; let mass = 1.; let h: f32 = 1.; let fluid_rho = 0.5; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox( p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn pack(x: vec2) -> u32 { let x2: vec2 = 65534. * clamp(0.5 * x + 0.5, vec2(0.), vec2(1.)); return u32(round(x2.x)) + 65535u * u32(round(x2.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle = particle( decode(data.x) + pos, decode(data.y), data.zw ); return P; } fn saveParticle(P: particle, pos: vec2) -> vec4 { var P2: particle = particle(P.X, P.V, P.M); P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); return vec4(encode(P2.X), encode(P2.V), P2.M); } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } let dif: f32 = 1.12; fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: bin/assets/shaders/paint_streams/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // let color = vec4(f32(0)); // textureStore(texture, location, color); // } // struct Particle { // a: vec4; // b: vec4; // }; // fn dum(x: Particle) { // let x2 = Particle(x.a, x.b); // let bah = x.a + 1.0; // return; // } // fn miam() -> Particle { // var out: Particle; // out.a = vec4(0.0); // out.b = vec4(1.0); // return out; // } // let ch0: texture_storage_2d = buffer_a; // let ch1: texture_storage_2d = buffer_a; // let ch2: texture_storage_2d = buffer_a; // let ch3: texture_storage_2d = buffer_a; // #define Bf(p) p // #define Bi(p) ivec2(p) // #define texel(a, p) texelFetch(a, Bi(p), 0) // #define pixel(a, p) texture(a, (p)/R) let PI = 3.14159265; let dt = 1.5; let border_h = 5.; // var R: vec2 ; // var Mouse: vec4 ; // var time: f32; let mass = 1.; let h: f32 = 1.; let fluid_rho = 0.5; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox( p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn pack(x: vec2) -> u32 { let x2: vec2 = 65534. * clamp(0.5 * x + 0.5, vec2(0.), vec2(1.)); return u32(round(x2.x)) + 65535u * u32(round(x2.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle = particle( decode(data.x) + pos, decode(data.y), data.zw ); return P; } fn saveParticle(P: particle, pos: vec2) -> vec4 { var P2: particle = particle(P.X, P.V, P.M); P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); return vec4(encode(P2.X), encode(P2.V), P2.M); } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } let dif: f32 = 1.12; fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } // fn hsv2rgb( c: vec3) -> vec3 { // // var fractional: f32 = 0.0; // // let m = modf(c.x * 6. + vec3(0., 4., 2.) / 6., &fractional); // let v = vec3(0., 4., 2.); // let fractional: vec3 = vec3(vec3( (c.x * 6. + v) / 6.0)) ; // // let whatever = modf(uv + 1.0, &tempo); // // var temp2 = 0.; // // let frac = modf(tempo / 2.0, &temp2); // let af: vec3 = abs(fractional - 3.) - 1.; // var rgb: vec3 = clamp(af, vec3(0.), vec3(1.)); // rgb = rgb * rgb * (3. - 2. * rgb); // return c.z * mix(vec3(1.), rgb, c.y); // } fn mixN(a: vec3, b: vec3, k: f32) -> vec3 { return sqrt(mix(a * a, b * b, clamp(k, 0., 1.))); } fn V(p: vec2) -> vec4 { // return pixel(ch1, p); return textureLoad(buffer_c, vec2(p )); } fn border(p: vec2, R2: vec2, time: f32) -> f32 { let bound: f32 = -sdBox(p - R2 * 0.5, R2 * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time) * (p - R2 * vec2(0.5, 0.6)), R2 * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R2 * vec2(0.5, 0.7), R2 * vec2(1.5, 0.5)); return max(drain, min(bound, box)); } fn bN(p: vec2, R2: vec2, time: f32) -> vec3 { let dx: vec3 = vec3(-h, 0.0, h); let idx: vec4 = vec4(-1./h, 0., 1./h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy, R2, time) + idx.xyw * border(p + dx.xy, R2, time) + idx.yzw * border(p + dx.yz, R2, time) + idx.yxw * border(p + dx.yx, R2, time); return vec3(normalize(r.xy), r.z + 1e-4); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { // var O: vec4 = textureLoad(buffer_a, location); // textureStore(texture, location, O); // } // fn mainImage( col: vec4, pos: vec2) -> () { let R2 = uni.iResolution.xy; let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let time = uni.iTime; // let p: vec2 = vec2(pos); // let data: vec4 = texel(ch0, pos); // let p: vec2 = vec2(location.x, i32(R2.y) - location.y); let data: vec4 = textureLoad(buffer_a, i32(R2.y) - location); let pos = vec2(f32(location.x), R2.y - f32(location.y)); var P: particle = getParticle(data, pos); let Nb: vec3 = bN(P.X, R2, time); let bord: f32 = smoothStep(2. * border_h, border_h * 0.5, border(pos, R2, time)); let rho: vec4 = V(pos); let dx: vec3 = vec3(-2., 0., 2.); let grad: vec4 = -0.5 * vec4( V(pos + dx.zy).zw - V(pos + dx.xy).zw, V(pos + dx.yz).zw - V(pos + dx.yx).zw); let N: vec2 = pow(length(grad.xz), 0.2) * normalize(grad.xz + 0.00001); let specular: f32 = pow(max(dot(N, Dir(1.4)), 0.), 3.5); let specularb: f32 = G(0.4 * (Nb.zz - border_h)) * pow(max(dot(Nb.xy, Dir(1.4)), 0.), 3.); let a: f32 = pow(smoothStep(fluid_rho * 0., fluid_rho * 2., rho.z), 0.1); let b: f32 = exp(-1.7 * smoothStep(fluid_rho * 1., fluid_rho * 7.5, rho.z)); let col0: vec3 = vec3(1., 0.5, 0.); let col1: vec3 = vec3(0.1, 0.4, 1.); let fcol: vec3 = mixN(col0, col1, tanh(3. * (rho.w - 0.7)) * 0.5 + 0.5); // var col: vec4; var col: vec3 = vec3(3.); col = mixN(col.xyz, fcol.xyz * (1.5 * b + specular * 5.), a); col = mixN(col, 0. * vec3(0.5, 0.5, 1.), bord); col = tanh(col); let col4 = vec4(col, 1.0); // let grey = vec4(0.8); textureStore(texture, location, col4); // textureStore(texture, location, data); } ================================================ FILE: bin/assets/shaders/preludes/image_prelude ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iResolution: vec2; iMouse: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; // change to vec4 when possible }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; {{IMAGE_CODE}} ================================================ FILE: bin/assets/shaders/simplest_detailed_fluid/buffer_a.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_a, location, color); } // https://www.shadertoy.com/view/7t3SDf fn t(i: vec2, location: vec2) -> vec4 { let O: vec4 = textureLoad(buffer_a, i + location ); return O; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { var location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // location = location + vec2(10); var r: vec4 = vec4(0.); for (var i: vec2 = vec2(-7); i.x < 7; i.x = i.x + 1 ) { for (i.y = -7; i.y < 7; i.y = i.y + 1 ) { let ii = i + 1; let a = 0; let v: vec2 = t(ii , location + a ).xy; let what = t(ii, location + a).z ; let fi = vec2(ii); r = r + ( what * exp(-dot(v+fi, v+fi)) / 3.14 * vec4(mix(v+v+fi , v, t(ii, location + a ).z), 1., 1.) ); } } r.x = r.x / (r.z+0.000001); r.y = r.y / (r.z+0.000001); if (i32(uni.iFrame) % 500 == 1) { let u = vec2(location +0) ; let m: vec2 = 4.*u/vec2(uni.iResolution.xy) - 2.; r = r + (vec4(m, 1., 0.)*exp(-dot(m, m))); } textureStore(buffer_a, location , r); } ================================================ FILE: bin/assets/shaders/simplest_detailed_fluid/buffer_b.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_b, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_b, location, vec4(0.85)); // if (uni.iTime > 1.0) { // textureStore(buffer_b, location, vec4(0.95)); // } } ================================================ FILE: bin/assets/shaders/simplest_detailed_fluid/buffer_c.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let color = vec4(0.0); textureStore(buffer_c, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_c, location, vec4(0.95)); // if (uni.iTime > 1.0) { // textureStore(buffer_c, location, vec4(0.95)); // } } ================================================ FILE: bin/assets/shaders/simplest_detailed_fluid/buffer_d.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let color = vec4(0.60); textureStore(buffer_d, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // textureStore(buffer_d, location, vec4(0.7)); if (uni.iTime > 1.0) { storageBarrier(); textureStore(buffer_d, location, vec4(0.95)); } // storageBarrier(); } ================================================ FILE: bin/assets/shaders/simplest_detailed_fluid/image.wgsl ================================================ struct CommonUniform { iTime: f32; iTimeDelta: f32; iFrame: f32; iSampleRate: f32; iMouse: vec4; iResolution: vec2; iChannelTime: vec4; iChannelResolution: vec4; iDate: vec4; }; [[group(0), binding(0)]] var uni: CommonUniform; [[group(0), binding(1)]] var buffer_a: texture_storage_2d; [[group(0), binding(2)]] var buffer_b: texture_storage_2d; [[group(0), binding(3)]] var buffer_c: texture_storage_2d; [[group(0), binding(4)]] var buffer_d: texture_storage_2d; [[group(0), binding(5)]] var texture: texture_storage_2d; fn hash(value: u32) -> u32 { var state = value; state = state ^ 2747636419u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; state = state ^ state >> 16u; state = state * 2654435769u; return state; } fn randomFloat(value: u32) -> f32 { return f32(hash(value)) / 4294967295.0; } [[stage(compute), workgroup_size(8, 8, 1)]] fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); let randomNumber = randomFloat(invocation_id.y * num_workgroups.x + invocation_id.x); let alive = randomNumber > 0.9; let color = vec4(f32(alive)); textureStore(texture, location, color); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // var alive = true; // let value: vec4 = textureLoad(buffer_a, vec2(0,1)); // if (value.x > 0.79) { // alive = false; // } let r = 1.- textureLoad(buffer_a, location ).zzzz; storageBarrier(); textureStore(texture, location, r); // textureStore(texture, location, vec4(f32(alive))); } ================================================ FILE: bin/examples/minimal/buffer_a.wgsl ================================================ [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let color = vec4(0.5); textureStore(buffer_a, location, color); } ================================================ FILE: bin/examples/minimal/buffer_b.wgsl ================================================ [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: bin/examples/minimal/buffer_c.wgsl ================================================ [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: bin/examples/minimal/buffer_d.wgsl ================================================ [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: bin/examples/minimal/common.wgsl ================================================ ================================================ FILE: bin/examples/minimal/image.wgsl ================================================ // displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a // here [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var O: vec4 = textureLoad(buffer_a, location); textureStore(texture, location, O); } ================================================ FILE: bin/examples/mixing_liquid/buffer_a.wgsl ================================================ [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let color = vec4(0.5); // textureStore(buffer_a, location, color); // } // fn mainImage( U: vec4, pos: vec2) -> () { let pos: vec2 = vec2(location); R = uni.iResolution.xy; time = uni.iTime; Mouse = uni.iMouse; let p: vec2 = location; // let data: vec4 = texel(ch0, pos); // buffer_b is set as the channel 0 in Buffer A of the paint // streams inside shadertoy let data: vec4 = textureLoad(buffer_b, location); var P: particle = Reintegration(buffer_b, pos); // if (uni.iFrame < 4.0) { # ifdef INIT let rand: vec3 = hash32(pos); if (rand.z < 0.) { P.X = pos; P.V = 0.5 * (rand.xy - 0.5) + vec2(0., 0.); P.M = vec2(mass, 0.); } else { P.X = pos; P.V = vec2(0.); P.M = vec2(0.000001); } # endif // } textureStore(buffer_a, location, saveParticle(P, pos)); } ================================================ FILE: bin/examples/mixing_liquid/buffer_b.wgsl ================================================ [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { // } // fn mainImage( U: vec4, pos: vec2) -> () { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let pos: vec2 = vec2(location); R = uni.iResolution.xy; time = uni.iTime; Mouse = uni.iMouse; let p: vec2 = location; // let data: vec4 = texel(buffer_a, pos); let data: vec4 = textureLoad(buffer_a, location); var P: particle = getParticle(data, pos); if (P.M.x != 0.) { P = Simulation(buffer_a, P, pos); } if (length(P.X - R * vec2(0.8, 0.9)) < 10.) { P.X = pos; P.V = 0.5 * Dir(-PI * 0.25 - PI * 0.5 + 0.3 * sin(0.4 * time)); P.M = mix(P.M, vec2(fluid_rho, 1.), 0.4); } if (length(P.X - R * vec2(0.2, 0.9)) < 10.) { P.X = pos; P.V = 0.5 * Dir(-PI * 0.25 + 0.3 * sin(0.3 * time)); P.M = mix(P.M, vec2(fluid_rho, 0.), 0.4); } // U = saveParticle(P, pos); textureStore(buffer_b, location, saveParticle(P, pos)); } ================================================ FILE: bin/examples/mixing_liquid/buffer_c.wgsl ================================================ [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { // fn mainImage( fragColor: vec4, pos: vec2) -> () { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); R = uni.iResolution.xy; time = uni.iTime; let pos = vec2(location); let p: vec2 = vec2(pos); let data: vec4 = textureLoad(buffer_a, location); var P: particle = getParticle(data, pos); // let data: vec4 = texel(ch0, pos); // let P: particle = getParticle(data, pos); var rho: vec4 = vec4(0.); for (var i: i32 = -1; i <= 1; i = i + 1) { for (var j: i32 = -1; j <= 1; j = j + 1) { let ij: vec2 = vec2(i, j); // let data: vec4 = texel(ch0, pos + ij); let data: vec4 = textureLoad(buffer_a, location + ij); var P0: particle = getParticle(data, pos + vec2(ij)); let x0: vec2 = P0.X; rho = rho + (1. * vec4(P.V, P.M) * G((pos - x0) / 0.75)); } } textureStore(buffer_c, location, rho); } ================================================ FILE: bin/examples/mixing_liquid/buffer_d.wgsl ================================================ [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: bin/examples/mixing_liquid/common.wgsl ================================================ // struct Particle { // a: vec4; // b: vec4; // }; // fn dum(x: Particle) { // let x2 = Particle(x.a, x.b); // let bah = x.a + 1.0; // return; // } // fn miam() -> Particle { // var out: Particle; // out.a = vec4(0.0); // out.b = vec4(1.0); // return out; // } // let ch0: texture_storage_2d = buffer_a; // let ch1: texture_storage_2d = buffer_a; // let ch2: texture_storage_2d = buffer_a; // let ch3: texture_storage_2d = buffer_a; // #define Bf(p) p // #define Bi(p) ivec2(p) // #define texel(a, p) texelFetch(a, Bi(p), 0) // #define pixel(a, p) texture(a, (p)/R) let PI = 3.14159265; let dt = 1.5; let border_h = 5.; var R: vec2 ; var Mouse: vec4 ; var time: f32; let mass = 1.; let fluid_rho = 0.5; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox( p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn border(p: vec2) -> f32 { let bound: f32 = -sdBox(p - R * 0.5, R * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time) * (p - R * vec2(0.5, 0.6)), R * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R * vec2(0.5, 0.7), R * vec2(1.5, 0.5)); return max(drain, min(bound, box)); } let h: f32 = 1.; fn bN(p: vec2) -> vec3 { let dx: vec3 = vec3(-h, 0.0, h); let idx: vec4 = vec4(-1./h, 0., 1./h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy) + idx.xyw * border(p + dx.xy) + idx.yzw * border(p + dx.yz) + idx.yxw * border(p + dx.yx); return vec3(normalize(r.xy), r.z + 1e-4); } fn pack(x: vec2) -> u32 { let x2: vec2 = 65534. * clamp(0.5 * x + 0.5, vec2(0.), vec2(1.)); return u32(round(x.x)) + 65535u * u32(round(x.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle = particle(decode(data.x) + pos, decode(data.y), data.zw); return P; } fn saveParticle(P: particle, pos: vec2) -> vec4 { var P2: particle = particle(P.X, P.V, P.M); P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); return vec4(encode(P2.X), encode(P2.V), P2.M); } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } let dif: f32 = 1.12; fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } // don't forget to use a return value when using Reintegration fn Reintegration(ch: texture_storage_2d, pos: vec2) -> particle { //basically integral over all updated neighbor distributions //that fall inside of this pixel //this makes the tracking conservative for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(i)); // let data: vec4 = texel(ch, tpos); // let data: vec4 = texelFetch(ch, ivec2(tpos), 0); let data: vec4 = textureLoad(ch, vec2(tpos)); var P0: particle = getParticle(data, tpos); P0.X = P0.X + (P0.V * dt);//integrate position let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x); let D: vec3 = distribution(P0.X, pos, difR); //the deposited mass into this cell let m: f32 = P0.M.x * D.z; var P1: particle; // TODO: change the input particle directly using (*P).X = ... //add weighted by mass P1.X = P1.X + (D.xy * m); P1.V = P1.V + (P0.V * m); P1.M.y = P1.M.y + (P0.M.y * m); //add mass P1.M.x = P1.M.x + (m); } } //normalization if (P1.M.x != 0.) { P1.X = P1.X / (P1.M.x); P1.V = P1.V / (P1.M.x); P1.M.y = P1.M.y / (P1.M.x); } return P1; } fn Simulation(ch: texture_storage_2d, P: particle, pos: vec2) -> particle { var F: vec2 = vec2(0.); var avgV: vec3 = vec3(0.); for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(i)); // let data: vec4 = texel(ch, tpos); // let data: vec4 = texelFetch(ch, ivec2(tpos), 0); let data: vec4 = textureLoad(ch, vec2(tpos)); let P0: particle = getParticle(data, tpos); let dx: vec2 = P0.X - P.X; let avgP: f32 = 0.5 * P0.M.x * (Pf(P.M) + Pf(P0.M)); F = F - (0.5 * G(1. * dx) * avgP * dx); avgV = avgV + (P0.M.x * G(1. * dx) * vec3(P0.V, 1.)); } } avgV.y = avgV.y / (avgV.z); avgV.x = avgV.x / (avgV.z); //viscosity F = F + (0. * P.M.x * (avgV.xy - P.V)); //gravity F = F + (P.M.x * vec2(0., -0.0004)); if (Mouse.z > 0.) { let dm: vec2 = (Mouse.xy - Mouse.zw) / 10.; let d: f32 = distance(Mouse.xy, P.X) / 20.; F = F + (0.001 * dm * exp(-d * d)); } var P1: particle = P; //integrate P1.V = P1.V + (F * dt / P1.M.x); //border let N: vec3 = bN(P1.X); let vdotN: f32 = step(N.z, border_h) * dot(-N.xy, P1.V); P1.V = P1.V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN))); P1.V = P1.V + (0. * P1.M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z)); if (N.z < 0.) { P1.V = vec2(0.); } //velocity limit let v: f32 = length(P1.V); var vv: f32; if (v > 1.) { vv = v; } else { vv = 1.; }; P1.V = P1.V / vv; return P1; } ================================================ FILE: bin/examples/mixing_liquid/image.wgsl ================================================ // displays a gray screen by setting the color in buffer_a.wglsl and loading buffer_a // here // fn even(uv: f32) -> f32 { // var tempo: f32 = 0.0; // let whatever = modf(uv + 1.0, &tempo); // var temp2 = 0.; // let frac = modf(tempo / 2.0, &temp2); // if (abs(frac) < 0.001) { // return 1.0; // } else { // return 0.0; // } // } fn hsv2rgb( c: vec3) -> vec3 { // var fractional: f32 = 0.0; // let m = modf(c.x * 6. + vec3(0., 4., 2.) / 6., &fractional); let v = vec3(0., 4., 2.); let fractional: vec3 = vec3(vec3( (c.x * 6. + v) / 6.0)) ; // let whatever = modf(uv + 1.0, &tempo); // var temp2 = 0.; // let frac = modf(tempo / 2.0, &temp2); let af: vec3 = abs(fractional - 3.) - 1.; var rgb: vec3 = clamp(af, vec3(0.), vec3(1.)); rgb = rgb * rgb * (3. - 2. * rgb); return c.z * mix(vec3(1.), rgb, c.y); } fn mixN(a: vec3, b: vec3, k: f32) -> vec3 { return sqrt(mix(a * a, b * b, clamp(k, 0., 1.))); } fn V(p: vec2) -> vec4 { // return pixel(ch1, p); return textureLoad(buffer_c, vec2(p )); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // var O: vec4 = textureLoad(buffer_a, location); // textureStore(texture, location, O); // } // fn mainImage( col: vec4, pos: vec2) -> () { R = uni.iResolution.xy; time = uni.iTime; // let p: vec2 = vec2(pos); // let data: vec4 = texel(ch0, pos); let p: vec2 = location; let data: vec4 = textureLoad(buffer_a, location); let pos = vec2(location); var P: particle = getParticle(data, pos); let Nb: vec3 = bN(P.X); let bord: f32 = smoothStep(2. * border_h, border_h * 0.5, border(pos)); let rho: vec4 = V(pos); let dx: vec3 = vec3(-2., 0., 2.); let grad: vec4 = -0.5 * vec4( V(pos + dx.zy).zw - V(pos + dx.xy).zw, V(pos + dx.yz).zw - V(pos + dx.yx).zw); let N: vec2 = pow(length(grad.xz), 0.2) * normalize(grad.xz + 0.00001); let specular: f32 = pow(max(dot(N, Dir(1.4)), 0.), 3.5); let specularb: f32 = G(0.4 * (Nb.zz - border_h)) * pow(max(dot(Nb.xy, Dir(1.4)), 0.), 3.); let a: f32 = pow(smoothStep(fluid_rho * 0., fluid_rho * 2., rho.z), 0.1); let b: f32 = exp(-1.7 * smoothStep(fluid_rho * 1., fluid_rho * 7.5, rho.z)); let col0: vec3 = vec3(1., 0.5, 0.); let col1: vec3 = vec3(0.1, 0.4, 1.); let fcol: vec3 = mixN(col0, col1, tanh(3. * (rho.w - 0.7)) * 0.5 + 0.5); // var col: vec4; var col: vec3 = vec3(3.); col = mixN(col.xyz, fcol.xyz * (1.5 * b + specular * 5.), a); col = mixN(col, 0. * vec3(0.5, 0.5, 1.), bord); col = tanh(col); let col4 = vec4(col, 0.3); textureStore(texture, location, rho); } ================================================ FILE: bin/examples/paint/buffer_a.wgsl ================================================ type float2 = vec2; type float4 = vec4; fn hue(v: f32) -> vec4 { return (vec4(.6) + vec4(.6) * cos( vec4(6.3 * v) + vec4(0.0,23.0,21.0,0.0 ) )); } fn smoothit(v: f32) -> f32{ return smoothStep( 1.5, 0., v ); } fn sdSegment(p: vec2, a: vec2, b: vec2) -> f32 { let pa = p - a; let ba = b - a; let h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.); return length(pa - ba * h); } fn sdRhombus(p: vec2, b: vec2) -> f32 { let q = abs(p); let qb = dot(q, vec2(b.x, -b.y)); let bb = dot(b, vec2(b.x, -b.y)); let h = clamp((-2. * qb + bb) / dot(b, b), -1., 1.); let d = length(q - 0.5 * b * vec2(1. - h, 1. + h)); return d * sign(q.x * b.y + q.y * b.x - b.x * b.y); } fn sdTriangleIsosceles(p: vec2, c: vec2) -> f32 { let q = vec2(abs(p.x), p.y); let a = q - c * clamp(dot(q, c) / dot(c, c), 0., 1.); let b = q - c * vec2(clamp(q.x / c.x, 0., 1.), 1.); let s = -sign(c.y); let d = min(vec2(dot(a, a), s * (q.x * c.y - q.y * c.x)), vec2(dot(b, b), s * (q.y - c.y))); return -sqrt(d.x) * sign(d.y); } fn sdStar(p: vec2, r: f32, n: u32, m: f32) ->f32 { let an = 3.141593 / f32(n); let en = 3.141593 / m; let acs = vec2(cos(an), sin(an)); let ecs = vec2(cos(en), sin(en)); let bn = (atan2(abs(p.x), p.y) % (2. * an)) - an; var q: vec2 = length(p) * vec2(cos(bn), abs(sin(bn))); q = q - r * acs; q = q + ecs * clamp(-dot(q, ecs), 0., r * acs.y / ecs.y); return length(q) * sign(q.x); } fn sdHeart(p: vec2) -> f32 { let q = vec2(abs(p.x), p.y); let w = q - vec2(0.25, 0.75); if (q.x + q.y > 1.0) { return sqrt(dot(w, w)) - sqrt(2.) / 4.; } let u = q - vec2(0., 1.0); let v = q - 0.5 * max(q.x + q.y, 0.); return sqrt(min(dot(u, u), dot(v, v))) * sign(q.x - q.y); } fn sdMoon(p: vec2, d: f32, ra: f32, rb: f32) -> f32 { let q = vec2(p.x, abs(p.y)); let a = (ra * ra - rb * rb + d * d) / (2. * d); let b = sqrt(max(ra * ra - a * a, 0.)); if (d * (q.x * b - q.y * a) > d * d * max(b - q.y, 0.)) { return length(q-vec2(a, b)); } return max((length(q) - ra), -(length(q - vec2(d, 0.)) - rb)); } fn sdCross(p: vec2, b: vec2) -> f32 { var q: vec2 = abs(p); q = select(q.xy, q.yx, q.y > q.x); let t = q - b; let k = max(t.y, t.x); let w = select(vec2(b.y - q.x, -k), t, k > 0.); return sign(k) * length(max(w, vec2(0.))); } fn sdRoundedX(p: vec2, w: f32, r: f32) -> f32 { let q = abs(p); return length(q - min(q.x + q.y, w) * 0.5) - r; } fn sdCircle(p: vec2, c: vec2, r: f32) -> f32 { let d = length(p - c); return d - r; } // [[stage(compute), workgroup_size(8, 8, 1)]] // fn init([[builtin(global_invocation_id)]] invocation_id: vec3, [[builtin(num_workgroups)]] num_workgroups: vec3) { // let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // let location_f32 = vec2(f32(invocation_id.x), f32(invocation_id.y)); // # ifdef INIT // if (location.x == 0 && location.y == 0 ) { // textureStore(buffer_a, location, hue(4.0 / 8.0)); // } else { // // set brush color to black // let black = vec4(0.0, 0.0, 0.0, 1.0); // textureStore(buffer_a, location, black); // } // # endif // } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); // the first three frames are not directed inside the update function. // The first time this function is called is on frame 4. if (i32(uni.iFrame) == 3) { // # ifdef INIT if (location.x == 0 && location.y == 0 ) { textureStore(buffer_a, location, hue(4.0 / 8.0)); } else { // set brush color to black let black = vec4(0.0, 0.0, 0.0, 1.0); textureStore(buffer_a, location, black); } // # endif } let R: float2 = uni.iResolution.xy; let U: vec2 = vec2(location) / R; let M: float2 = vec2(uni.iMouse.x, 1.0-uni.iMouse.y); var O: float4 = textureLoad(buffer_a, location); if (location.x == 0 && location.y == 0 ) { if ( uni.iMouse.x < 0.1 && uni.iMouse.w == 1.0) { // just pressed left mouse button let y: f32 = floor(9.*M.y); O = hue( y/8. ); textureStore(buffer_a, location, O); } return; } // display palette on left if ( U.x < 0.1 ) { let y: f32 = floor(9.*U.y); O = hue( y/8. ); O.w = 1.; textureStore(buffer_a, location, O); return; } // let brush_color = float4(1., 0., 0., 1.); let brush_color = textureLoad(buffer_a, vec2(0,0)); // apply paint if (uni.iMouse.z == 1.0) { let mouse_pix = vec2(uni.iMouse.x * R.x, (1.0 - uni.iMouse.y) * R.y ); let brush_sdf = sdCircle(vec2(location), mouse_pix, 10.0); let brush_d = smoothStep(0.0, 5.0, brush_sdf); O = mix(O, brush_color, (1.0-brush_d) * 0.01); } textureStore(buffer_a, location, O); } ================================================ FILE: bin/examples/paint/buffer_b.wgsl ================================================ [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: bin/examples/paint/buffer_c.wgsl ================================================ [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: bin/examples/paint/buffer_d.wgsl ================================================ [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: bin/examples/paint/common.wgsl ================================================ ================================================ FILE: bin/examples/paint/image.wgsl ================================================ [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); var alive = true; var O: vec4 = textureLoad(buffer_a, location); textureStore(texture, location, O); } ================================================ FILE: bin/examples/paint_streams/buffer_a.wgsl ================================================ // don't forget to use a return value when using Reintegration fn Reintegration(ch: texture_storage_2d, pos: vec2) -> particle { //basically integral over all updated neighbor distributions //that fall inside of this pixel //this makes the tracking conservative for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(j)); // let data: vec4 = texel(ch, tpos); // let data: vec4 = texelFetch(ch, ivec2(tpos), 0); let data: vec4 = textureLoad(ch, vec2(tpos)); var P0: particle = getParticle(data, tpos); P0.X = P0.X + (P0.V * dt);//integrate position let difR: f32 = 0.9 + 0.21 * smoothStep(fluid_rho * 0., fluid_rho * 0.333, P0.M.x); let D: vec3 = distribution(P0.X, pos, difR); //the deposited mass into this cell let m: f32 = P0.M.x * D.z; var P1: particle; // TODO: change the input particle directly using (*P).X = ... //add weighted by mass P1.X = P1.X + (D.xy * m); P1.V = P1.V + (P0.V * m); P1.M.y = P1.M.y + (P0.M.y * m); //add mass P1.M.x = P1.M.x + (m); } } //normalization if (P1.M.x != 0.) { P1.X = P1.X / (P1.M.x); P1.V = P1.V / (P1.M.x); P1.M.y = P1.M.y / (P1.M.x); } return P1; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { let R2 = uni.iResolution.xy; let location = vec2(i32(invocation_id.x), i32(R2.y) - i32(invocation_id.y)); let pos: vec2 = vec2(location); // Mouse = uni.iMouse; var P: particle; // if (uni.iFrame < 4.0) { // if (Mouse.z > 0.5) { #ifdef INIT let rand: vec3 = hash32(pos); // let rand = vec3(0.2, -0.2, -0.2); if (rand.z < 0.) { P.X = pos; P.V = 0.5 * (rand.xy - 0.5) + vec2(0., 0.); P.M = vec2(mass, 0.); } else { P.X = pos; P.V = vec2(0.); P.M = vec2(0.000001); } #else P = Reintegration(buffer_b, pos); #endif textureStore(buffer_a, location, saveParticle(P, pos)); } ================================================ FILE: bin/examples/paint_streams/buffer_b.wgsl ================================================ fn border(p: vec2, R2: vec2, time: f32) -> f32 { let bound: f32 = -sdBox(p - R2 * 0.5, R2 * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time) * (p - R2 * vec2(0.5, 0.6)), R2 * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R2 * vec2(0.5, 0.7), R2 * vec2(1.5, 0.5)); return max(drain, min(bound, box)); } fn bN(p: vec2, R2: vec2, time: f32) -> vec3 { let dx: vec3 = vec3(-h, 0.0, h); let idx: vec4 = vec4(-1./h, 0., 1./h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy, R2, time) + idx.xyw * border(p + dx.xy, R2, time) + idx.yzw * border(p + dx.yz, R2, time) + idx.yxw * border(p + dx.yx, R2, time); return vec3(normalize(r.xy), r.z + 1e-4); } fn Simulation( ch: texture_storage_2d, P: particle, pos: vec2, R2: vec2, time: f32, Mouse: vec4, ) -> particle { var F: vec2 = vec2(0.); var avgV: vec3 = vec3(0.); for (var i: i32 = -2; i <= 2; i = i + 1) { for (var j: i32 = -2; j <= 2; j = j + 1) { let tpos: vec2 = pos + vec2(f32(i), f32(j)); // let data: vec4 = texel(ch, tpos); // let data: vec4 = texelFetch(ch, ivec2(tpos), 0); let data: vec4 = textureLoad(ch, vec2(tpos)); let P0: particle = getParticle(data, tpos); let dx: vec2 = P0.X - P.X; let avgP: f32 = 0.5 * P0.M.x * (Pf(P.M) + Pf(P0.M)); F = F - (0.5 * G(1. * dx) * avgP * dx); avgV = avgV + (P0.M.x * G(1. * dx) * vec3(P0.V, 1.)); } } avgV.y = avgV.y / (avgV.z); avgV.x = avgV.x / (avgV.z); //viscosity F = F + (0. * P.M.x * (avgV.xy - P.V)); //gravity F = F + (P.M.x * vec2(0., -0.0004)); if (Mouse.z > 0.) { let dm: vec2 = (Mouse.xy - Mouse.zw) / 10.; let d: f32 = distance(Mouse.xy, P.X) / 20.; F = F + (0.001 * dm * exp(-d * d)); } var P1: particle = P; //integrate P1.V = P1.V + (F * dt / P1.M.x); //border let N: vec3 = bN(P1.X, R2, time); let vdotN: f32 = step(N.z, border_h) * dot(-N.xy, P1.V); P1.V = P1.V + (0.5 * (N.xy * vdotN + N.xy * abs(vdotN))); P1.V = P1.V + (0. * P1.M.x * N.xy * step(abs(N.z), border_h) * exp(-N.z)); if (N.z < 0.) { P1.V = vec2(0.); } //velocity limit let v: f32 = length(P1.V); var vv: f32; if (v > 1.) { vv = v; } else { vv = 1.; }; P1.V = P1.V / vv; return P1; } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { // } // fn mainImage( U: vec4, pos: vec2) -> () { let R2 = uni.iResolution.xy; let location = vec2(i32(invocation_id.x), i32(R2.y) - i32(invocation_id.y)); let pos: vec2 = vec2(location); let time = uni.iTime; let Mouse = uni.iMouse; let p: vec2 = location; // let data: vec4 = texel(buffer_a, pos); let data: vec4 = textureLoad(buffer_a, location); var P: particle = getParticle(data, pos); if (P.M.x != 0.) { P = Simulation(buffer_a, P, pos, R2, time, Mouse); } if (length(P.X - R2 * vec2(0.8, 0.9)) < 10.) { P.X = pos; P.V = 0.5 * Dir(-PI * 0.25 - PI * 0.5 + 0.3 * sin(0.4 * time)); P.M = mix(P.M, vec2(fluid_rho, 1.), 0.4); } if (length(P.X - R2 * vec2(0.2, 0.9)) < 10.) { P.X = pos; P.V = 0.5 * Dir(-PI * 0.25 + 0.3 * sin(0.3 * time)); P.M = mix(P.M, vec2(fluid_rho, 0.), 0.4); } // U = saveParticle(P, pos); textureStore(buffer_b, location, saveParticle(P, pos)); } ================================================ FILE: bin/examples/paint_streams/buffer_c.wgsl ================================================ [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { // fn mainImage( fragColor: vec4, pos: vec2) -> () { // let R = uni.iResolution.xy; let R2 = uni.iResolution.xy; let location = vec2(i32(invocation_id.x), i32(R2.y) - i32(invocation_id.y)); // R = uni.iResolution.xy; // time = uni.iTime; let pos = vec2(location); let p: vec2 = vec2(pos); let data: vec4 = textureLoad(buffer_a, location); var P: particle = getParticle(data, pos); // let data: vec4 = texel(ch0, pos); // let P: particle = getParticle(data, pos); var rho: vec4 = vec4(0.); for (var i: i32 = -1; i <= 1; i = i + 1) { for (var j: i32 = -1; j <= 1; j = j + 1) { let ij: vec2 = vec2(i, j); // let data: vec4 = texel(ch0, pos + ij); let data: vec4 = textureLoad(buffer_a, location + ij); var P0: particle = getParticle(data, pos + vec2(ij)); let x0: vec2 = P0.X; rho = rho + (1. * vec4(P.V, P.M) * G((pos - x0) / 0.75)); } } textureStore(buffer_c, location, rho); } ================================================ FILE: bin/examples/paint_streams/buffer_d.wgsl ================================================ [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { } ================================================ FILE: bin/examples/paint_streams/common.wgsl ================================================ // struct Particle { // a: vec4; // b: vec4; // }; // fn dum(x: Particle) { // let x2 = Particle(x.a, x.b); // let bah = x.a + 1.0; // return; // } // fn miam() -> Particle { // var out: Particle; // out.a = vec4(0.0); // out.b = vec4(1.0); // return out; // } // let ch0: texture_storage_2d = buffer_a; // let ch1: texture_storage_2d = buffer_a; // let ch2: texture_storage_2d = buffer_a; // let ch3: texture_storage_2d = buffer_a; // #define Bf(p) p // #define Bi(p) ivec2(p) // #define texel(a, p) texelFetch(a, Bi(p), 0) // #define pixel(a, p) texture(a, (p)/R) let PI = 3.14159265; let dt = 1.5; let border_h = 5.; // var R: vec2 ; // var Mouse: vec4 ; // var time: f32; let mass = 1.; let h: f32 = 1.; let fluid_rho = 0.5; fn Pf(rho: vec2) -> f32 { let GF: f32 = 1.; return mix(0.5 * rho.x, 0.04 * rho.x * (rho.x / fluid_rho - 1.), GF); } fn Rot(ang: f32) -> mat2x2 { return mat2x2(cos(ang), -sin(ang), sin(ang), cos(ang)); } fn Dir(ang: f32) -> vec2 { return vec2(cos(ang), sin(ang)); } fn sdBox( p: vec2, b: vec2) -> f32 { let d: vec2 = abs(p) - b; return length(max(d, vec2(0.))) + min(max(d.x, d.y), 0.); } fn pack(x: vec2) -> u32 { let x2: vec2 = 65534. * clamp(0.5 * x + 0.5, vec2(0.), vec2(1.)); return u32(round(x2.x)) + 65535u * u32(round(x2.y)); } fn unpack(a: u32) -> vec2 { var x: vec2 = vec2(f32(a % 65535u), f32(a / 65535u)); return clamp(x / 65534., vec2(0.), vec2(1.)) * 2. - 1.; } fn decode(x: f32) -> vec2 { var X: u32 = u32(x); return unpack(X); } fn encode(x: vec2) -> f32 { var X: u32 = pack(x); return f32(X); } struct particle { X: vec2; V: vec2; M: vec2; }; fn getParticle(data: vec4, pos: vec2) -> particle { var P: particle = particle( decode(data.x) + pos, decode(data.y), data.zw ); return P; } fn saveParticle(P: particle, pos: vec2) -> vec4 { var P2: particle = particle(P.X, P.V, P.M); P2.X = clamp(P2.X - pos, vec2(-0.5), vec2(0.5)); return vec4(encode(P2.X), encode(P2.V), P2.M); } fn hash32(p: vec2) -> vec3 { var p3: vec3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973)); p3 = p3 + (dot(p3, p3.yxz + 33.33)); return fract((p3.xxy + p3.yzz) * p3.zyx); } fn G(x: vec2) -> f32 { return exp(-dot(x, x)); } fn G0(x: vec2) -> f32 { return exp(-length(x)); } let dif: f32 = 1.12; fn distribution(x: vec2, p: vec2, K: f32) -> vec3 { let omin: vec2 = clamp(x - K * 0.5, p - 0.5, p + 0.5); let omax: vec2 = clamp(x + K * 0.5, p - 0.5, p + 0.5); return vec3(0.5 * (omin + omax), (omax.x - omin.x) * (omax.y - omin.y) / (K * K)); } ================================================ FILE: bin/examples/paint_streams/image.wgsl ================================================ // fn hsv2rgb( c: vec3) -> vec3 { // // var fractional: f32 = 0.0; // // let m = modf(c.x * 6. + vec3(0., 4., 2.) / 6., &fractional); // let v = vec3(0., 4., 2.); // let fractional: vec3 = vec3(vec3( (c.x * 6. + v) / 6.0)) ; // // let whatever = modf(uv + 1.0, &tempo); // // var temp2 = 0.; // // let frac = modf(tempo / 2.0, &temp2); // let af: vec3 = abs(fractional - 3.) - 1.; // var rgb: vec3 = clamp(af, vec3(0.), vec3(1.)); // rgb = rgb * rgb * (3. - 2. * rgb); // return c.z * mix(vec3(1.), rgb, c.y); // } fn mixN(a: vec3, b: vec3, k: f32) -> vec3 { return sqrt(mix(a * a, b * b, clamp(k, 0., 1.))); } fn V(p: vec2) -> vec4 { // return pixel(ch1, p); return textureLoad(buffer_c, vec2(p )); } fn border(p: vec2, R2: vec2, time: f32) -> f32 { let bound: f32 = -sdBox(p - R2 * 0.5, R2 * vec2(0.5, 0.5)); let box: f32 = sdBox(Rot(0. * time) * (p - R2 * vec2(0.5, 0.6)), R2 * vec2(0.05, 0.01)); let drain: f32 = -sdBox(p - R2 * vec2(0.5, 0.7), R2 * vec2(1.5, 0.5)); return max(drain, min(bound, box)); } fn bN(p: vec2, R2: vec2, time: f32) -> vec3 { let dx: vec3 = vec3(-h, 0.0, h); let idx: vec4 = vec4(-1./h, 0., 1./h, 0.25); let r: vec3 = idx.zyw * border(p + dx.zy, R2, time) + idx.xyw * border(p + dx.xy, R2, time) + idx.yzw * border(p + dx.yz, R2, time) + idx.yxw * border(p + dx.yx, R2, time); return vec3(normalize(r.xy), r.z + 1e-4); } [[stage(compute), workgroup_size(8, 8, 1)]] fn update([[builtin(global_invocation_id)]] invocation_id: vec3) { // var O: vec4 = textureLoad(buffer_a, location); // textureStore(texture, location, O); // } // fn mainImage( col: vec4, pos: vec2) -> () { let R2 = uni.iResolution.xy; let location = vec2(i32(invocation_id.x), i32(invocation_id.y)); let time = uni.iTime; // let p: vec2 = vec2(pos); // let data: vec4 = texel(ch0, pos); // let p: vec2 = vec2(location.x, i32(R2.y) - location.y); let data: vec4 = textureLoad(buffer_a, i32(R2.y) - location); let pos = vec2(f32(location.x), R2.y - f32(location.y)); var P: particle = getParticle(data, pos); let Nb: vec3 = bN(P.X, R2, time); let bord: f32 = smoothStep(2. * border_h, border_h * 0.5, border(pos, R2, time)); let rho: vec4 = V(pos); let dx: vec3 = vec3(-2., 0., 2.); let grad: vec4 = -0.5 * vec4( V(pos + dx.zy).zw - V(pos + dx.xy).zw, V(pos + dx.yz).zw - V(pos + dx.yx).zw); let N: vec2 = pow(length(grad.xz), 0.2) * normalize(grad.xz + 0.00001); let specular: f32 = pow(max(dot(N, Dir(1.4)), 0.), 3.5); let specularb: f32 = G(0.4 * (Nb.zz - border_h)) * pow(max(dot(Nb.xy, Dir(1.4)), 0.), 3.); let a: f32 = pow(smoothStep(fluid_rho * 0., fluid_rho * 2., rho.z), 0.1); let b: f32 = exp(-1.7 * smoothStep(fluid_rho * 1., fluid_rho * 7.5, rho.z)); let col0: vec3 = vec3(1., 0.5, 0.); let col1: vec3 = vec3(0.1, 0.4, 1.); let fcol: vec3 = mixN(col0, col1, tanh(3. * (rho.w - 0.7)) * 0.5 + 0.5); // var col: vec4; var col: vec3 = vec3(3.); col = mixN(col.xyz, fcol.xyz * (1.5 * b + specular * 5.), a); col = mixN(col, 0. * vec3(0.5, 0.5, 1.), bord); col = tanh(col); let col4 = vec4(col, 1.0); // let grey = vec4(0.8); textureStore(texture, location, col4); // textureStore(texture, location, data); } ================================================ FILE: bin/main.rs ================================================ use bevy::{ core_pipeline::node::MAIN_PASS_DEPENDENCIES, diagnostic::{Diagnostics, FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, prelude::*, reflect::TypeUuid, render::{ render_asset::RenderAssets, render_graph::{self, RenderGraph}, // render_resource::*, render_resource::{std140::AsStd140, *}, renderer::{RenderContext, RenderDevice, RenderQueue}, RenderApp, RenderStage, }, window::{PresentMode, WindowResized}, }; use std::borrow::Cow; use std::fs; // not compatible with WASM --> mod texture_a; use texture_a::*; mod texture_b; use texture_b::*; mod texture_c; use texture_c::*; mod texture_d; use texture_d::{extract_texture_d, queue_bind_group_d, TextureD, TextureDNode, TextureDPipeline}; pub const SIZE: (u32, u32) = (1280, 720); pub const WORKGROUP_SIZE: u32 = 8; pub const NUM_PARTICLES: u32 = 256; // const COMMON: &'static str = include_str!("common.wgsl"); // const IMAGE_SHADER: &'static str = include_str!("templates/image_template.wgsl"); // const IMAGE_CORE_SCRIPT: &'static str = include_str!("templates/image.wgsl"); // pub const IMAGE_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64( // bevy::render::render_resource::Shader::TYPE_UUID, // 192598017680025719, // ); // const TEXTURE_A_SHADER: &'static str = include_str!("templates/texture_a_template.wgsl"); // const TEXTURE_A_CORE_SCRIPT: &'static str = include_str!("templates/texture_a.wgsl"); // pub const TEXTURE_A_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64( // bevy::render::render_resource::Shader::TYPE_UUID, // 986988749367675188, // ); // const TEXTURE_B_SHADER: &'static str = include_str!("templates/texture_b_template.wgsl"); // const TEXTURE_B_CORE_SCRIPT: &'static str = include_str!("templates/texture_b.wgsl"); // pub const TEXTURE_B_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64( // bevy::render::render_resource::Shader::TYPE_UUID, // 808999425257967014, // ); // const TEXTURE_C_SHADER: &'static str = include_str!("templates/texture_c_template.wgsl"); // const TEXTURE_C_CORE_SCRIPT: &'static str = include_str!("templates/texture_c.wgsl"); // pub const TEXTURE_C_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64( // bevy::render::render_resource::Shader::TYPE_UUID, // 819348234244712380, // ); // const TEXTURE_D_SHADER: &'static str = include_str!("templates/texture_d_template.wgsl"); // const TEXTURE_D_CORE_SCRIPT: &'static str = include_str!("templates/texture_d.wgsl"); // pub const TEXTURE_D_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64( // bevy::render::render_resource::Shader::TYPE_UUID, // 193535259211504032, // ); fn main() { // // not sure this works on wasm // let mut wgpu_options = WgpuLimits::default(); // wgpu_options.max_bind_groups = 5; // wgpu_options.max_storage_buffers_per_shader_stage = 5; // wgpu_options.max_storage_textures_per_shader_stage = 5; // wgpu_options.max_inter_stage_shader_components = 5; let mut app = App::new(); // app.insert_resource(wgpu_options) app.insert_resource(ClearColor(Color::BLACK)) .insert_resource(WindowDescriptor { present_mode: PresentMode::Immediate, // uncomment for unthrottled FPS ..default() }) .add_plugins(DefaultPlugins) .add_system(bevy::input::system::exit_on_esc_system) .add_plugin(ShadertoyPlugin) .add_plugin(FrameTimeDiagnosticsPlugin::default()) .add_plugin(LogDiagnosticsPlugin::default()) .add_startup_system(setup) .add_system(update_common_uniform) .run(); } fn setup( mut commands: Commands, mut images: ResMut>, // mut shaders: ResMut>, asset_server: Res, windows: Res, ) { commands.spawn_bundle(OrthographicCameraBundle::new_2d()); let mut image = Image::new_fill( Extent3d { width: SIZE.0, height: SIZE.1, depth_or_array_layers: 1, }, TextureDimension::D2, &[0, 0, 0, 0], TextureFormat::Rgba8Unorm, ); image.texture_descriptor.usage = TextureUsages::COPY_DST | TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING; let image = images.add(image); commands.insert_resource(MainImage(image.clone())); commands.spawn_bundle(SpriteBundle { sprite: Sprite { custom_size: Some(Vec2::new(SIZE.0 as f32, SIZE.1 as f32)), ..default() }, texture: image.clone(), ..default() }); let window = windows.primary(); let mut common_uniform = CommonUniform::default(); common_uniform.i_resolution.x = window.width(); common_uniform.i_resolution.y = window.height(); commands.insert_resource(common_uniform); // // // // Texture A: equivalent of Buffer A in Shadertoy let mut texture_a = Image::new_fill( Extent3d { width: SIZE.0, height: SIZE.1, depth_or_array_layers: 1, }, TextureDimension::D2, // &[255, 255, 255, 255], &[0, 0, 0, 0], TextureFormat::Rgba8Unorm, ); texture_a.texture_descriptor.usage = TextureUsages::COPY_DST | TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING; let texture_a = images.add(texture_a); commands.insert_resource(TextureA(texture_a)); // // // // Texture B: equivalent of Buffer B in Shadertoy let mut texture_b = Image::new_fill( Extent3d { width: SIZE.0, height: SIZE.1, depth_or_array_layers: 1, }, TextureDimension::D2, // &[255, 255, 255, 255], &[0, 0, 0, 0], TextureFormat::Rgba8Unorm, ); texture_b.texture_descriptor.usage = TextureUsages::COPY_DST | TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING; let texture_b = images.add(texture_b); commands.insert_resource(TextureB(texture_b)); // // // // Texture C: equivalent of Buffer C in Shadertoy let mut texture_c = Image::new_fill( Extent3d { width: SIZE.0, height: SIZE.1, depth_or_array_layers: 1, }, TextureDimension::D2, // &[255, 255, 255, 255], &[0, 0, 0, 0], TextureFormat::Rgba8Unorm, ); texture_c.texture_descriptor.usage = TextureUsages::COPY_DST | TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING; let texture_c = images.add(texture_c); commands.insert_resource(TextureC(texture_c)); // // // // Texture D: equivalent of Buffer D in Shadertoy let mut texture_d = Image::new_fill( Extent3d { width: SIZE.0, height: SIZE.1, depth_or_array_layers: 1, }, TextureDimension::D2, // &[255, 255, 255, 255], &[0, 0, 0, 0], TextureFormat::Rgba8Unorm, ); texture_d.texture_descriptor.usage = TextureUsages::COPY_DST | TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING; let texture_d = images.add(texture_d); commands.insert_resource(TextureD(texture_d)); // // // // import shaders // // let image_shader_handle = import_shader( // IMAGE_SHADER, // IMAGE_SHADER_HANDLE, // &mut shaders, // IMAGE_CORE_SCRIPT, // "{{IMAGE}}", // ); // // let image_shader = Shader::from_wgsl(Cow::from(IMAGE_SHADER)); // // shaders.set_untracked(IMAGE_SHADER_HANDLE.clone(), image_shader); // // let image_handle: Handle = IMAGE_SHADER_HANDLE.clone().typed(); // let texture_a_shader_handle = import_shader( // TEXTURE_A_SHADER, // TEXTURE_A_SHADER_HANDLE, // &mut shaders, // TEXTURE_A_CORE_SCRIPT, // "{{TEXTURE_A}}", // ); // let texture_b_shader_handle = import_shader( // TEXTURE_B_SHADER, // TEXTURE_B_SHADER_HANDLE, // &mut shaders, // TEXTURE_B_CORE_SCRIPT, // "{{TEXTURE_B}}", // ); // let texture_c_shader_handle = import_shader( // TEXTURE_C_SHADER, // TEXTURE_C_SHADER_HANDLE, // &mut shaders, // TEXTURE_C_CORE_SCRIPT, // "{{TEXTURE_C}}", // ); // let texture_d_shader_handle = import_shader( // TEXTURE_D_SHADER, // TEXTURE_D_SHADER_HANDLE, // &mut shaders, // TEXTURE_D_CORE_SCRIPT, // "{{TEXTURE_D}}", // ); // let example = "minimal"; // let example = "paint"; // let example = "mixing_liquid"; let example = "paint_streams"; // let example = "simplest_detailed_fluid"; // let example = "interactive_fluid_simulation"; // let example = "liquid"; https://www.shadertoy.com/view/WtfyDj let all_shader_handles: ShaderHandles = make_and_load_shaders2(example, &asset_server); commands.insert_resource(all_shader_handles); } pub fn make_and_load_shaders(example: &str, asset_server: &Res) -> ShaderHandles { let image_shader_handle = asset_server.load(&format!("shaders/{}/image.wgsl", example)); let texture_a_shader = asset_server.load(&format!("shaders/{}/buffer_a.wgsl", example)); let texture_b_shader = asset_server.load(&format!("shaders/{}/buffer_b.wgsl", example)); let texture_c_shader = asset_server.load(&format!("shaders/{}/buffer_c.wgsl", example)); let texture_d_shader = asset_server.load(&format!("shaders/{}/buffer_d.wgsl", example)); ShaderHandles { image_shader: image_shader_handle, texture_a_shader, texture_b_shader, texture_c_shader, texture_d_shader, } } pub fn make_and_load_shaders2(example: &str, asset_server: &Res) -> ShaderHandles { // let image_shader_handle = asset_server.load(&format!("shaders/{}/image.wgsl", example)); // let example_string = example.to_string(); // format_and_save_shader(example, "image"); format_and_save_shader(example, "buffer_a"); format_and_save_shader(example, "buffer_b"); format_and_save_shader(example, "buffer_c"); format_and_save_shader(example, "buffer_d"); let image_shader_handle = asset_server.load(&format!("shaders/{}/image.wgsl", example)); let texture_a_shader = asset_server.load(&format!("shaders/{}/buffer_a.wgsl", example)); let texture_b_shader = asset_server.load(&format!("shaders/{}/buffer_b.wgsl", example)); let texture_c_shader = asset_server.load(&format!("shaders/{}/buffer_c.wgsl", example)); let texture_d_shader = asset_server.load(&format!("shaders/{}/buffer_d.wgsl", example)); ShaderHandles { image_shader: image_shader_handle, texture_a_shader, texture_b_shader, texture_c_shader, texture_d_shader, } } // This function uses the std library and isn't compatible with wasm fn format_and_save_shader(example: &str, buffer_type: &str) { let common_prelude = include_str!("templates/common_prelude.wgsl"); let template = match buffer_type { "image" => include_str!("templates/image_template.wgsl"), "buffer_a" => include_str!("templates/buffer_a_template.wgsl"), "buffer_b" => include_str!("templates/buffer_b_template.wgsl"), "buffer_c" => include_str!("templates/buffer_c_template.wgsl"), "buffer_d" => include_str!("templates/buffer_d_template.wgsl"), _ => include_str!("templates/buffer_d_template.wgsl"), }; let mut shader_content = template.replace("{{COMMON_PRELUDE}}", common_prelude); let path_to_code_block = format!("examples/{}/{}.wgsl", example, buffer_type); let path_to_common = format!("examples/{}/common.wgsl", example); let common = fs::read_to_string(path_to_common).expect("could not read file."); let image_main = fs::read_to_string(path_to_code_block).expect("could not read file."); let mut shader_content = shader_content.replace("{{COMMON}}", &common); shader_content = shader_content.replace("{{CODE_BLOCK}}", &image_main); let folder = format!("assets/shaders/{}", example); let path = format!("{}/{}.wgsl", folder, buffer_type); println!("{}", path); let _ = fs::create_dir(folder); fs::write(path, shader_content).expect("Unable to write file"); } // fn import_shader( // shader_skeleton: &str, // shader_handle_untyped: HandleUntyped, // shaders: &mut Assets, // shader_core_script: &str, // signature: &str, // ) -> Handle { // // // // insert common code in every shader // let shader_prelude = // let mut image_source = shader_skeleton.replace("{{COMMON}}", &COMMON); // image_source = image_source.replace(signature, shader_core_script); // let image_shader = Shader::from_wgsl(Cow::from(image_source)); // shaders.set_untracked(shader_handle_untyped.clone(), image_shader.clone()); // shader_handle_untyped.typed() // } // Copied from Shadertoy.com : // uniform vec3 iResolution; // viewport resolution (in pixels) // uniform float iTime; // shader playback time (in seconds) // uniform float iTimeDelta; // render time (in seconds) // uniform int iFrame; // shader playback frame // uniform float iChannelTime[4]; // channel playback time (in seconds) // uniform vec3 iChannelResolution[4]; // channel resolution (in pixels) // uniform vec4 iMouse; // mouse pixel coords. xy: current (if MLB down), zw: click // uniform samplerXX iChannel0..3; // input channel. XX = 2D/Cube // uniform vec4 iDate; // (year, month, day, time in seconds) // uniform float iSampleRate; // sound sample rate (i.e., 44100) #[derive(Component, Default, Clone, AsStd140)] pub struct CommonUniform { pub i_time: f32, pub i_time_delta: f32, pub i_frame: f32, pub i_sample_rate: f32, // sound sample rate pub i_mouse: Vec4, pub i_resolution: Vec2, pub i_channel_time: Vec4, pub i_channel_resolution: Vec4, pub i_date: [i32; 4], } pub struct CommonUniformMeta { buffer: Buffer, } // TODO: update date, channel time, channe l_resolution, sample_rate fn update_common_uniform( mut common_uniform: ResMut, mut window_resize_event: EventReader, windows: Res, time: Res