#wgpu #post-processing #graphics #shadertoy #audio-video

tweak_shader

A simple wgpu helper library for building flexible screen shaders

7 releases

0.2.3 Mar 20, 2024
0.2.2 Mar 13, 2024
0.2.1 Nov 28, 2023
0.1.2 Nov 2, 2023

#169 in Graphics APIs

Download history 6/week @ 2024-02-24 86/week @ 2024-03-09 173/week @ 2024-03-16 14/week @ 2024-03-23 34/week @ 2024-03-30 2/week @ 2024-04-06 75/week @ 2024-04-13

132 downloads per month
Used in tweak_runner

MIT license

405KB
4K SLoC

Lib Tweak Shader

The Tweak Shader Library provides a rendering and bookkeeping context for an interactive screen shader format. It allows users to create shaders reminiscent of ShaderToy or ISF shaders with custom uniforms that can be tweaked at runtime. The library features support for video, image, and audio inputs, as well as various other types, including colors, floats, integers, 2D points, and more. The design and functionality of this library were inspired by the ISF (Interactive Shader Format) project.

Usage

use tweak_shader::RenderContext;
use wgpu::TextureFormat;

let src =  r#"
#version 450
#pragma tweak_shader(version=1.0)

layout(location = 0) out vec4 out_color;

#pragma input(float, name="foo", default=0.0, min=0.0, max=1.0)
#pragma input(float, name="bar")
#pragma input(float, name="baz", default=0.5)
layout(set = 0, binding = 0) uniform Inputs {
   float foo;
   float bar;
   float baz;
};

void main()
{
   out_color = vec4(foo, bar, baz, 1.0);
}
"#;

let format = TextureFormat::Rgba8UnormSrgb;
let device = // your wgpu::Device here;
let queue = // your wgpu::Queue here;

let render_context = RenderContext::new(isf_shader_source, format, &device, &queue).unwrap();

// Congratulations! You now have a 255x255 blue square.
let output = render_context.render_to_vec(&queue, &device, 255, 255);

The valid document pragmas are as follows.

Utility Blocks

The Tweak Shader Library allows you to utilize utility blocks to access specific uniform or push constant fields efficiently. Here's an example of how to use utility blocks:

#pragma utility_block(ShaderInputs)
layout(push_constant) uniform ShaderInputs {
   float time;       // shader playback time (in seconds)
   float time_delta; // elapsed time since the last frame in seconds
   float frame_rate; // estimated number of frames per second
   uint frame_index; // frame count
   vec4 mouse;       // ShaderToy mouse scheme
   vec4 date;        // [year, month, day, seconds]
   vec3 resolution;  // viewport resolution in pixels, [width, height, aspect ratio]
   uint pass_index;   // updated to reflect the current render pass index
};

You can use the #pragma utility_block to access members from the specialized utility functions, such as RenderContext::update_time and RenderContext::update_resolution. The field names may vary between uses safely.

Input Types

Input pragmas provide information about shader inputs, including type, name, and optional attributes such as default values, minimum and maximum bounds, labels, and valid values. Here are some examples of input types:

  • Float Input:
#pragma input(float, name="foo", default=0.0, min=0.0, max=1.0)
  • Integer Input with Labels:
#pragma input(int, name="mode", default=0, values=[0, 1, 2], labels=["A", "B", "C"])
  • Image Input:
#pragma input(image, name="input_image", path="./demo.png")
layout(set=1, binding=1) uniform sampler default_sampler;
layout(set=1, binding=2) uniform texture2D input_image;
  • Audio Input:
#pragma input(audio, name="audio_tex")
layout(set=1, binding=3) uniform texture2D audio_tex;
  • AudioFFT Input:
#pragma input(audiofft, name="audio_fft_tex")
layout(set=1, binding=4) uniform texture2D audio_fft_tex;

Each input pragma corresponds to a uniform variable in the shader code, with the name field specifying the matching struct field in the global uniform value or the texture name that maps to the input.

Additional Render Passes and Persistent Buffers

You can define additional render passes and specify output targets for each pass using the #pragma pass pragma. Here's an example of how to create an additional pass:

#pragma pass(0, persistent, target="single_pixel", height=1, width=1)
layout(set=0, binding=1) uniform sampler default_sampler;
layout(set=0, binding=2) uniform texture2D single_pixel;

The #pragma pass pragma allows you to add passes that run in the order specified by their index before the main pass. If a target is specified, the pass will write to a context-managed texture mapped to the specified variable. You can also specify custom height and width for the output texture; otherwise, it defaults to the render target's size.

Please refer to the official documentation for more details and examples on using the Tweak Shader Library in your Rust project.

GitHub Repository

Dependencies

~8–46MB
~682K SLoC