Skip to content

Commit

Permalink
add some more pipelined-rendering shader examples (#3041)
Browse files Browse the repository at this point in the history
based on #3031 

Adds some examples showing of how to use the new pipelined rendering for custom shaders.

- a minimal shader example which doesn't use render assets
- the same but using glsl
- an example showing how to render instanced data
- a shader which uses the seconds since startup to animate some textures


Instancing shader:
![grafik](https://user-images.githubusercontent.com/22177966/139299294-e176b62a-53d1-4287-9a66-02fb55affc02.png)
Animated shader:
![animate_shader](https://user-images.githubusercontent.com/22177966/139299718-2940c0f3-8480-4ee0-98d7-b6ba40dc1472.gif)
(the gif makes it look a bit ugly)

Co-authored-by: Carter Anderson <[email protected]>
  • Loading branch information
jakobhellermann and cart committed Jan 5, 2022
1 parent f3fba09 commit b147601
Show file tree
Hide file tree
Showing 13 changed files with 1,070 additions and 26 deletions.
17 changes: 17 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ anyhow = "1.0.4"
rand = "0.8.0"
ron = "0.7.0"
serde = { version = "1", features = ["derive"] }
bytemuck = "1.7"
# Needed to poll Task examples
futures-lite = "1.11.3"

Expand Down Expand Up @@ -418,6 +419,22 @@ path = "examples/shader/shader_defs.rs"
name = "shader_material"
path = "examples/shader/shader_material.rs"

[[example]]
name = "shader_material_glsl"
path = "examples/shader/shader_material_glsl.rs"

[[example]]
name = "shader_instancing"
path = "examples/shader/shader_instancing.rs"

[[example]]
name = "animate_shader"
path = "examples/shader/animate_shader.rs"

[[example]]
name = "compute_shader_game_of_life"
path = "examples/shader/compute_shader_game_of_life.rs"

# Tools
[[example]]
name = "bevymark"
Expand Down
72 changes: 72 additions & 0 deletions assets/shaders/animate_shader.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#import bevy_pbr::mesh_view_bind_group
#import bevy_pbr::mesh_struct

[[group(1), binding(0)]]
var<uniform> mesh: Mesh;

struct Vertex {
[[location(0)]] position: vec3<f32>;
[[location(1)]] normal: vec3<f32>;
[[location(2)]] uv: vec2<f32>;
};

struct VertexOutput {
[[builtin(position)]] clip_position: vec4<f32>;
[[location(0)]] uv: vec2<f32>;
};

[[stage(vertex)]]
fn vertex(vertex: Vertex) -> VertexOutput {
let world_position = mesh.model * vec4<f32>(vertex.position, 1.0);

var out: VertexOutput;
out.clip_position = view.view_proj * world_position;
out.uv = vertex.uv;
return out;
}


struct Time {
time_since_startup: f32;
};
[[group(2), binding(0)]]
var<uniform> time: Time;


fn oklab_to_linear_srgb(c: vec3<f32>) -> vec3<f32> {
let L = c.x;
let a = c.y;
let b = c.z;

let l_ = L + 0.3963377774 * a + 0.2158037573 * b;
let m_ = L - 0.1055613458 * a - 0.0638541728 * b;
let s_ = L - 0.0894841775 * a - 1.2914855480 * b;

let l = l_*l_*l_;
let m = m_*m_*m_;
let s = s_*s_*s_;

return vec3<f32>(
4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
-0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s,
);
}

[[stage(fragment)]]
fn fragment(in: VertexOutput) -> [[location(0)]] vec4<f32> {
let speed = 2.0;
let t_1 = sin(time.time_since_startup * speed) * 0.5 + 0.5;
let t_2 = cos(time.time_since_startup * speed);

let distance_to_center = distance(in.uv, vec2<f32>(0.5)) * 1.4;

// blending is done in a perceptual color space: https://bottosson.github.io/posts/oklab/
let red = vec3<f32>(0.627955, 0.224863, 0.125846);
let green = vec3<f32>(0.86644, -0.233887, 0.179498);
let blue = vec3<f32>(0.701674, 0.274566, -0.169156);
let white = vec3<f32>(1.0, 0.0, 0.0);
let mixed = mix(mix(red, blue, t_1), mix(green, white, t_2), distance_to_center);

return vec4<f32>(oklab_to_linear_srgb(mixed), 1.0);
}
11 changes: 11 additions & 0 deletions assets/shaders/custom_material.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#version 450

layout(location = 0) out vec4 o_Target;

layout(set = 1, binding = 0) uniform CustomMaterial {
vec4 Color;
};

void main() {
o_Target = Color;
}
26 changes: 26 additions & 0 deletions assets/shaders/custom_material.vert
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#version 450

layout(location = 0) in vec3 Vertex_Position;
layout(location = 1) in vec3 Vertex_Normal;
layout(location = 2) in vec2 Vertex_Uv;

layout(set = 0, binding = 0) uniform CameraViewProj {
mat4 ViewProj;
mat4 InverseView;
mat4 Projection;
vec3 WorldPosition;
float near;
float far;
float width;
float height;
};

layout(set = 2, binding = 0) uniform Mesh {
mat4 Model;
mat4 InverseTransposeModel;
uint flags;
};

void main() {
gl_Position = ViewProj * Model * vec4(Vertex_Position, 1.0);
}
67 changes: 67 additions & 0 deletions assets/shaders/game_of_life.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
[[group(0), binding(0)]]
var texture: texture_storage_2d<rgba8unorm, read_write>;

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<u32>, [[builtin(num_workgroups)]] num_workgroups: vec3<u32>) {
let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));
let location_f32 = vec2<f32>(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>(f32(alive));

textureStore(texture, location, color);
}


fn get(location: vec2<i32>, offset_x: i32, offset_y: i32) -> i32 {
let value: vec4<f32> = textureLoad(texture, location + vec2<i32>(offset_x, offset_y));
return i32(value.x);
}

fn count_alive(location: vec2<i32>) -> 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<u32>) {
let location = vec2<i32>(i32(invocation_id.x), i32(invocation_id.y));

let n_alive = count_alive(location);
let color = vec4<f32>(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;
}

storageBarrier();

textureStore(texture, location, vec4<f32>(f32(alive)));
}
11 changes: 0 additions & 11 deletions assets/shaders/hot.frag

This file was deleted.

15 changes: 0 additions & 15 deletions assets/shaders/hot.vert

This file was deleted.

35 changes: 35 additions & 0 deletions assets/shaders/instancing.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#import bevy_pbr::mesh_view_bind_group
#import bevy_pbr::mesh_struct

[[group(1), binding(0)]]
var<uniform> mesh: Mesh;

struct Vertex {
[[location(0)]] position: vec3<f32>;
[[location(1)]] normal: vec3<f32>;
[[location(2)]] uv: vec2<f32>;

[[location(3)]] i_pos_scale: vec4<f32>;
[[location(4)]] i_color: vec4<f32>;
};

struct VertexOutput {
[[builtin(position)]] clip_position: vec4<f32>;
[[location(0)]] color: vec4<f32>;
};

[[stage(vertex)]]
fn vertex(vertex: Vertex) -> VertexOutput {
let position = vertex.position * vertex.i_pos_scale.w + vertex.i_pos_scale.xyz;
let world_position = mesh.model * vec4<f32>(position, 1.0);

var out: VertexOutput;
out.clip_position = view.view_proj * world_position;
out.color = vertex.i_color;
return out;
}

[[stage(fragment)]]
fn fragment(in: VertexOutput) -> [[location(0)]] vec4<f32> {
return in.color;
}
4 changes: 4 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ Example | File | Description
Example | File | Description
--- | --- | ---
`shader_material` | [`shader/shader_material.rs`](./shader/shader_material.rs) | Illustrates creating a custom material and a shader that uses it
`shader_material_glsl` | [`shader/shader_material_glsl.rs`](./shader/shader_material_glsl.rs) | A custom shader using the GLSL shading language.
`shader_instancing` | [`shader/shader_instancing.rs`](./shader/shader_instancing.rs) | A custom shader showing off rendering a mesh multiple times in one draw call.
`animate_shader` | [`shader/animate_shader.rs`](./shader/animate_shader.rs) | Shows how to pass changing data like the time since startup into a shader.
`compute_shader_game_of_life` | [`shader/compute_shader_game_of_life.rs`](./shader/compute_shader_game_of_life.rs) | A compute shader simulating Conway's Game of Life
`shader_defs` | [`shader/shader_defs.rs`](./shader/shader_defs.rs) | Demonstrates creating a custom material that uses "shaders defs" (a tool to selectively toggle parts of a shader)

## Tests
Expand Down
Loading

0 comments on commit b147601

Please sign in to comment.