Merge 7996d5126e
into 877d278785
This commit is contained in:
commit
99ddf518d8
11
Cargo.toml
11
Cargo.toml
@ -2865,6 +2865,17 @@ description = "A custom shader that builds on the standard material"
|
|||||||
category = "Shaders"
|
category = "Shaders"
|
||||||
wasm = true
|
wasm = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "stochastic_sampling"
|
||||||
|
path = "examples/shader/stochastic_sampling.rs"
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[package.metadata.example.stochastic_sampling]
|
||||||
|
name = "Stochastic Sampling"
|
||||||
|
description = "A custom shader that avoids repetition artifacts when tiling a texture"
|
||||||
|
category = "Shaders"
|
||||||
|
wasm = true
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "shader_prepass"
|
name = "shader_prepass"
|
||||||
path = "examples/shader/shader_prepass.rs"
|
path = "examples/shader/shader_prepass.rs"
|
||||||
|
87
assets/shaders/stochastic_sampling.wgsl
Normal file
87
assets/shaders/stochastic_sampling.wgsl
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
#import bevy_sprite::mesh2d_vertex_output::VertexOutput
|
||||||
|
#import bevy_sprite::mesh2d_view_bindings::globals
|
||||||
|
#import bevy_sprite::mesh2d_functions
|
||||||
|
|
||||||
|
fn permute_3_(x: vec3<f32>) -> vec3<f32> {
|
||||||
|
return (((x * 34.) + 1.) * x) % vec3(289.);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Noise implementation from https://github.com/johanhelsing/noisy_bevy/blob/v0.8.0/assets/noisy_bevy.wgsl
|
||||||
|
fn simplex_noise_2d(v: vec2<f32>) -> f32 {
|
||||||
|
let C = vec4(
|
||||||
|
0.211324865405187, // (3.0 - sqrt(3.0)) / 6.0
|
||||||
|
0.366025403784439, // 0.5 * (sqrt(3.0) - 1.0)
|
||||||
|
-0.577350269189626, // -1.0 + 2.0 * C.x
|
||||||
|
0.024390243902439 // 1.0 / 41.0
|
||||||
|
);
|
||||||
|
|
||||||
|
// first corner
|
||||||
|
var i = floor(v + dot(v, C.yy));
|
||||||
|
let x0 = v - i + dot(i, C.xx);
|
||||||
|
|
||||||
|
// other corners
|
||||||
|
var i1 = select(vec2(0., 1.), vec2(1., 0.), x0.x > x0.y);
|
||||||
|
var x12 = x0.xyxy + C.xxzz - vec4(i1, 0., 0.);
|
||||||
|
|
||||||
|
// permutations
|
||||||
|
i = i % vec2(289.);
|
||||||
|
|
||||||
|
let p = permute_3_(permute_3_(i.y + vec3(0., i1.y, 1.)) + i.x + vec3(0., i1.x, 1.));
|
||||||
|
var m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), vec3(0.));
|
||||||
|
m *= m;
|
||||||
|
m *= m;
|
||||||
|
|
||||||
|
// gradients: 41 points uniformly over a line, mapped onto a diamond
|
||||||
|
// the ring size, 17*17 = 289, is close to a multiple of 41 (41*7 = 287)
|
||||||
|
let x = 2. * fract(p * C.www) - 1.;
|
||||||
|
let h = abs(x) - 0.5;
|
||||||
|
let ox = floor(x + 0.5);
|
||||||
|
let a0 = x - ox;
|
||||||
|
|
||||||
|
// normalize gradients implicitly by scaling m
|
||||||
|
// approximation of: m *= inversesqrt(a0 * a0 + h * h);
|
||||||
|
m = m * (1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h));
|
||||||
|
|
||||||
|
// compute final noise value at P
|
||||||
|
let g = vec3(a0.x * x0.x + h.x * x0.y, a0.yz * x12.xz + h.yz * x12.yw);
|
||||||
|
return 130. * dot(m, g);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sum(v: vec4<f32>) -> f32 {
|
||||||
|
return v.x+v.y+v.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stochastic sampling method from https://iquilezles.org/articles/texturerepetition/
|
||||||
|
fn stochastic_sampling(uv: vec2<f32>, dx: vec2<f32>, dy: vec2<f32>, s: f32) -> vec4<f32> {
|
||||||
|
|
||||||
|
// sample variation pattern
|
||||||
|
let frequency_scale = 5.0;
|
||||||
|
let amplitude_scale = 0.3;
|
||||||
|
let k = simplex_noise_2d(uv.xy / frequency_scale) * amplitude_scale;
|
||||||
|
|
||||||
|
// compute index from 0-7
|
||||||
|
let index = k * 8.0;
|
||||||
|
let i = floor(index);
|
||||||
|
let f = fract(index);
|
||||||
|
|
||||||
|
// offsets for the different virtual patterns from 0 to 7
|
||||||
|
let offa = sin(vec2<f32>(3.0,7.0)*(i+0.0)); // can replace with any other hash
|
||||||
|
let offb = sin(vec2<f32>(3.0,7.0)*(i+1.0)); // can replace with any other hash
|
||||||
|
|
||||||
|
// sample the two closest virtual patterns
|
||||||
|
let cola = textureSampleGrad(texture, texture_sampler, uv + s * offa, dx, dy);
|
||||||
|
let colb = textureSampleGrad(texture, texture_sampler, uv + s * offb, dx, dy);
|
||||||
|
|
||||||
|
// interpolate between the two virtual patterns
|
||||||
|
return mix(cola, colb, smoothstep(0.2,0.8,f - 0.1*sum(cola-colb)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@group(2) @binding(1) var texture: texture_2d<f32>;
|
||||||
|
@group(2) @binding(2) var texture_sampler: sampler;
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
|
let speed = 0.5;
|
||||||
|
let s = smoothstep(0.4, 0.6, sin(globals.time * speed));
|
||||||
|
return stochastic_sampling(in.uv, dpdx(in.uv), dpdy(in.uv), s);
|
||||||
|
}
|
BIN
assets/textures/rocks.png
Normal file
BIN
assets/textures/rocks.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 99 KiB |
@ -476,6 +476,7 @@ Example | Description
|
|||||||
[Post Processing - Custom Render Pass](../examples/shader/custom_post_processing.rs) | A custom post processing effect, using a custom render pass that runs after the main pass
|
[Post Processing - Custom Render Pass](../examples/shader/custom_post_processing.rs) | A custom post processing effect, using a custom render pass that runs after the main pass
|
||||||
[Shader Defs](../examples/shader/shader_defs.rs) | A shader that uses "shaders defs" (a bevy tool to selectively toggle parts of a shader)
|
[Shader Defs](../examples/shader/shader_defs.rs) | A shader that uses "shaders defs" (a bevy tool to selectively toggle parts of a shader)
|
||||||
[Specialized Mesh Pipeline](../examples/shader/specialized_mesh_pipeline.rs) | Demonstrates how to write a specialized mesh pipeline
|
[Specialized Mesh Pipeline](../examples/shader/specialized_mesh_pipeline.rs) | Demonstrates how to write a specialized mesh pipeline
|
||||||
|
[Stochastic Sampling](../examples/shader/stochastic_sampling.rs) | A custom shader that avoids repetition artifacts when tiling a texture
|
||||||
[Storage Buffer](../examples/shader/storage_buffer.rs) | A shader that shows how to bind a storage buffer using a custom material.
|
[Storage Buffer](../examples/shader/storage_buffer.rs) | A shader that shows how to bind a storage buffer using a custom material.
|
||||||
[Texture Binding Array (Bindless Textures)](../examples/shader/texture_binding_array.rs) | A shader that shows how to bind and sample multiple textures as a binding array (a.k.a. bindless textures).
|
[Texture Binding Array (Bindless Textures)](../examples/shader/texture_binding_array.rs) | A shader that shows how to bind and sample multiple textures as a binding array (a.k.a. bindless textures).
|
||||||
|
|
||||||
|
75
examples/shader/stochastic_sampling.rs
Normal file
75
examples/shader/stochastic_sampling.rs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
//! Demonstrates using a custom extension to the `StandardMaterial` to create a repeating texture that avoids seams
|
||||||
|
//! by using stochastic sampling. This example uses a custom shader to achieve the effect.
|
||||||
|
use bevy::image::{ImageAddressMode, ImageSamplerDescriptor};
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy::render::mesh::VertexAttributeValues;
|
||||||
|
use bevy::render::render_resource::{AsBindGroup, ShaderRef};
|
||||||
|
use bevy::sprite::{Material2d, Material2dPlugin};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
App::new()
|
||||||
|
.add_plugins(DefaultPlugins.set(ImagePlugin {
|
||||||
|
default_sampler: ImageSamplerDescriptor {
|
||||||
|
address_mode_u: ImageAddressMode::Repeat,
|
||||||
|
address_mode_v: ImageAddressMode::Repeat,
|
||||||
|
address_mode_w: ImageAddressMode::Repeat,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
.add_plugins(Material2dPlugin::<CustomMaterial>::default())
|
||||||
|
.add_systems(Startup, setup)
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup(
|
||||||
|
mut commands: Commands,
|
||||||
|
asset_server: Res<AssetServer>,
|
||||||
|
mut materials: ResMut<Assets<CustomMaterial>>,
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
) {
|
||||||
|
commands.spawn(Camera2d);
|
||||||
|
let texture = asset_server.load("textures/rocks.png");
|
||||||
|
commands.spawn((
|
||||||
|
Mesh2d(meshes.add(repeating_quad(10.0))),
|
||||||
|
MeshMaterial2d(materials.add(CustomMaterial {
|
||||||
|
texture: Some(texture),
|
||||||
|
})),
|
||||||
|
Transform::default(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This struct defines the data that will be passed to your shader
|
||||||
|
#[derive(Asset, TypePath, AsBindGroup, Debug, Clone)]
|
||||||
|
struct CustomMaterial {
|
||||||
|
#[texture(1)]
|
||||||
|
#[sampler(2)]
|
||||||
|
texture: Option<Handle<Image>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This example uses a shader source file from the assets subdirectory
|
||||||
|
const SHADER_ASSET_PATH: &str = "shaders/stochastic_sampling.wgsl";
|
||||||
|
|
||||||
|
/// The Material trait is very configurable, but comes with sensible defaults for all methods.
|
||||||
|
/// You only need to implement functions for features that need non-default behavior. See the Material api docs for details!
|
||||||
|
impl Material2d for CustomMaterial {
|
||||||
|
fn fragment_shader() -> ShaderRef {
|
||||||
|
SHADER_ASSET_PATH.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a quad where the texture repeats n times in both directions.
|
||||||
|
fn repeating_quad(n: f32) -> Mesh {
|
||||||
|
let mut mesh: Mesh = Rectangle::from_length(1000.0).into();
|
||||||
|
let uv_attribute = mesh.attribute_mut(Mesh::ATTRIBUTE_UV_0).unwrap();
|
||||||
|
// The format of the UV coordinates should be Float32x2.
|
||||||
|
let VertexAttributeValues::Float32x2(uv_attribute) = uv_attribute else {
|
||||||
|
panic!("Unexpected vertex format, expected Float32x2.");
|
||||||
|
};
|
||||||
|
// The default `Rectangle`'s texture coordinates are in the range of `0..=1`. Values outside
|
||||||
|
// this range cause the texture to repeat.
|
||||||
|
for uv_coord in uv_attribute.iter_mut() {
|
||||||
|
uv_coord[0] *= n;
|
||||||
|
uv_coord[1] *= n;
|
||||||
|
}
|
||||||
|
mesh
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user