Skip to content

Commit

Permalink
refine shadertui example, add additional shaders - roundrect1 & 2, sh…
Browse files Browse the repository at this point in the history
…apes, boat
  • Loading branch information
austinvhuang committed Jul 11, 2024
1 parent fb56cf0 commit ecda921
Show file tree
Hide file tree
Showing 7 changed files with 303 additions and 10 deletions.
102 changes: 102 additions & 0 deletions examples/shadertui/boat.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// A boat rocking on water at night, by Claude 3.5 Sonnet

@group(0) @binding(0) var<storage, read_write> out: array<f32>;
@group(0) @binding(1) var<uniform> params: Params;

struct Params {
time: f32,
screenwidth: u32,
screenheight: u32,
};

fn sdf_box(p: vec2<f32>, center: vec2<f32>, size: vec2<f32>) -> f32 {
let d = abs(p - center) - size;
return length(max(d, vec2<f32>(0.0))) + min(max(d.x, d.y), 0.0);
}

fn sdf_triangle(p: vec2<f32>, p0: vec2<f32>, p1: vec2<f32>, p2: vec2<f32>) -> f32 {
let e0 = p1 - p0;
let e1 = p2 - p1;
let e2 = p0 - p2;
let v0 = p - p0;
let v1 = p - p1;
let v2 = p - p2;
let pq0 = v0 - e0 * clamp(dot(v0, e0) / dot(e0, e0), 0.0, 1.0);
let pq1 = v1 - e1 * clamp(dot(v1, e1) / dot(e1, e1), 0.0, 1.0);
let pq2 = v2 - e2 * clamp(dot(v2, e2) / dot(e2, e2), 0.0, 1.0);
let s = sign(e0.x * e2.y - e0.y * e2.x);
let d = min(min(vec2<f32>(dot(pq0, pq0), s * (v0.x * e0.y - v0.y * e0.x)),
vec2<f32>(dot(pq1, pq1), s * (v1.x * e1.y - v1.y * e1.x))),
vec2<f32>(dot(pq2, pq2), s * (v2.x * e2.y - v2.y * e2.x)));
return -sqrt(d.x) * sign(d.y);
}

fn sdf_boat(p: vec2<f32>, center: vec2<f32>, size: f32) -> f32 {
let hull = sdf_box(p, center + vec2<f32>(0.0, -0.15) * size, vec2<f32>(0.4, 0.1) * size);
let sail1 = sdf_triangle(p,
center + vec2<f32>(-0.1, -0.05) * size,
center + vec2<f32>(0.1, -0.05) * size,
center + vec2<f32>(0.0, 0.4) * size);
let sail2 = sdf_triangle(p,
center + vec2<f32>(0.1, -0.05) * size,
center + vec2<f32>(0.3, -0.05) * size,
center + vec2<f32>(0.2, 0.3) * size);
return min(min(hull, sail1), sail2);
}

fn wave(x: f32, time: f32) -> f32 {
return 0.05 * sin(x * 3.0 + time) +
0.03 * sin(x * 5.0 - time * 0.8) +
0.02 * sin(x * 8.0 + time * 1.5);
}

@compute @workgroup_size(16, 16, 1)
fn main(@builtin(global_invocation_id) globalID : vec3<u32>) {
let resolution = vec2<f32>(f32(params.screenwidth), f32(params.screenheight));
let uv = (vec2<f32>(globalID.xy) + 0.5) / resolution;
let aspect = resolution.x / resolution.y;
let p = vec2<f32>(uv.x * aspect, uv.y);

let t = params.time;

// Water
let water_level = 0.5;
let water_base = 0.6;
let water_distance = p.y - water_level - wave(p.x, t);

// Boat
let boat_size = 0.6;
let boat_center = vec2<f32>(0.5 * aspect, water_level + 0.1 + 0.05 * sin(t * 0.5));
let boat_rotation = 0.1 * sin(t * 0.4);
let rotated_p = vec2<f32>(
cos(boat_rotation) * (p.x - boat_center.x) - sin(boat_rotation) * (p.y - boat_center.y),
sin(boat_rotation) * (p.x - boat_center.x) + cos(boat_rotation) * (p.y - boat_center.y)
) + boat_center;
let boat_distance = sdf_boat(rotated_p, boat_center, boat_size);

// Coloring
var intensity = 0.05; // Dark night sky

if (water_distance < 0.0) {
intensity = water_base - 0.2 * (1.0 + wave(p.x, t));
}

if (boat_distance < 0.0) {
intensity = 0.2; // Dark boat silhouette
}

// Add stars
if (intensity == 0.05 && fract(sin(dot(p, vec2<f32>(12.9898, 78.233))) * 43758.5453) > 0.998) {
intensity = 1.0;
}

// Moon
let moon_center = vec2<f32>(0.8 * aspect, 0.8);
let moon_distance = length(p - moon_center) - 0.05;
if (moon_distance < 0.0) {
intensity = 0.9;
}

let idx = (params.screenheight - globalID.y) * params.screenwidth + globalID.x;
out[idx] = intensity;
}
31 changes: 31 additions & 0 deletions examples/shadertui/default.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
@group(0) @binding(0) var<storage, read_write> out: array<f32>;
@group(0) @binding(1) var<uniform> params: Params;

struct Params {
time: f32,
screenwidth: u32,
screenheight: u32,
};

fn sdf(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {
// Signed distance function (SDF) for a circle
// See https://iquilezles.org/articles/distfunctions2d/
return length(p - c) - r;
}

@compute @workgroup_size(16, 16, 1)
fn main(@builtin(global_invocation_id) globalID : vec3<u32>) {

// Normalize xy coordinates
let xy: vec2<f32> =
vec2<f32>(f32(globalID.x) / f32(params.screenwidth),
f32(globalID.y) / f32(params.screenheight));

// 1-D index into the output GPU buffer
let idx = globalID.y * params.screenwidth + globalID.x;

// Draw a circle, oscillating with time
let position = vec2<f32>(0.5, 0.5 + 0.1 * sin(3.0 * params.time));
out[idx] = 0.3 - min(5 * abs(sdf(xy, position, 0.2)), 0.3);

}
26 changes: 26 additions & 0 deletions examples/shadertui/roundrect1.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@group(0) @binding(0) var<storage, read_write> out: array<f32>;
@group(0) @binding(1) var<uniform> params: Params;

struct Params {
time: f32,
screenwidth: u32,
screenheight: u32,
};

fn sdf_rounded_rectangle(p: vec2<f32>, c: vec2<f32>, size: vec2<f32>, radius: f32) -> f32 {
let d = abs(p - c) - size + vec2<f32>(radius);
return length(max(d, vec2<f32>(0.0))) + min(max(d.x, d.y), 0.0) - radius;
}

@compute @workgroup_size(16, 16, 1)
fn main(@builtin(global_invocation_id) globalID : vec3<u32>) {
let xy: vec2<f32> =
vec2<f32>(f32(globalID.x) / f32(params.screenwidth),
f32(globalID.y) / f32(params.screenheight));
let t: f32 = params.time / 1.0;
let idx = globalID.y * params.screenwidth + globalID.x;
let center = vec2<f32>(0.5, 0.5 + 0.3 * sin(3.0 * t));
let size = vec2<f32>(0.2, 0.1); // Width and height of the rectangle
let corner_radius = 0.05; // Radius of the rounded corners
out[idx] = 0.3 - min(5.0 * abs(sdf_rounded_rectangle(xy, center, size, corner_radius)), 0.3);
}
42 changes: 42 additions & 0 deletions examples/shadertui/roundrect2.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
@group(0) @binding(0) var<storage, read_write> out: array<f32>;
@group(0) @binding(1) var<uniform> params: Params;

struct Params {
time: f32,
screenwidth: u32,
screenheight: u32,
};

fn sdf_rounded_rectangle(p: vec2<f32>, c: vec2<f32>, size: vec2<f32>, radius: f32) -> f32 {
let d = abs(p - c) - size + vec2<f32>(radius);
return length(max(d, vec2<f32>(0.0))) + min(max(d.x, d.y), 0.0) - radius;
}

fn rotate2d(angle: f32) -> mat2x2<f32> {
let s = sin(angle);
let c = cos(angle);
return mat2x2<f32>(c, -s, s, c);
}

@compute @workgroup_size(16, 16, 1)
fn main(@builtin(global_invocation_id) globalID : vec3<u32>) {
let xy: vec2<f32> =
vec2<f32>(f32(globalID.x) / f32(params.screenwidth),
f32(globalID.y) / f32(params.screenheight));
let t: f32 = params.time / 1.0;
let idx = globalID.y * params.screenwidth + globalID.x;

let center = vec2<f32>(0.5, 0.5 + 0.3 * sin(3.0 * t));
let size = vec2<f32>(0.2, 0.1); // Width and height of the rectangle
let corner_radius = 0.05; // Radius of the rounded corners

// Rotation
let rotation_speed = 2.0; // Adjust this to change rotation speed
let rotation_angle = t * rotation_speed;
let rotation_matrix = rotate2d(rotation_angle);

// Apply rotation to the point
let rotated_point = (rotation_matrix * (xy - center)) + center;

out[idx] = 0.3 - min(5.0 * abs(sdf_rounded_rectangle(rotated_point, center, size, corner_radius)), 0.3);
}
11 changes: 8 additions & 3 deletions examples/shadertui/run.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ using namespace gpu;
template <size_t rows, size_t cols>
void rasterize(const std::array<float, rows * cols> &values,
std::array<char, rows *(cols + 1)> &raster) {
// Can experiment with the rasterization characters here but fewer characters
// looks better by imposing temporal coherence whereas more characters can
// start to look like noise.
// static const char intensity[] = " `.-':_,^=;><+!ngrc*/z?sLTv)J7(|Fi{C}fI31tlu[neoZ5Yxjya]2ESwqkP6h9d4VpOGbUAKXHm8RD#$Bg0MNWQ%&@";
static const char intensity[] = " .`'^-+=*x17X$8#%@";
for (size_t i = 0; i < rows; ++i) {
for (size_t j = 0; j < cols; ++j) {
Expand Down Expand Up @@ -53,8 +57,8 @@ void loadShaderCode(const std::string &filename, std::string &codeString) {
int main() {

Context ctx = createContext();
static constexpr size_t kRows = 40;
static constexpr size_t kCols = 70;
static constexpr size_t kRows = 50;
static constexpr size_t kCols = 90;

LOG(kDefLog, kInfo, "Creating screen tensor");

Expand Down Expand Up @@ -116,7 +120,8 @@ int main() {
std::chrono::duration<float> frameElapsed = frameEnd - frameStart;
elapsed = frameEnd - start;
std::this_thread::sleep_for(std::chrono::milliseconds(20) - frameElapsed);
printf("\033[H\033[J%s\nReloaded file %zu times\n", raster.data(), ticks);
printf("\033[H\033[J%s\nRender loop running ...\nEdit and save shader.wgsl to see changes here.\nReloaded shader.wgsl %zu times\n", raster.data(), ticks);
fflush(stdout);
}

LOG(kDefLog, kInfo, "Done");
Expand Down
18 changes: 11 additions & 7 deletions examples/shadertui/shader.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,24 @@ struct Params {
};

fn sdf(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {
// Signed distance function (SDF) for a circle
// See https://iquilezles.org/articles/distfunctions2d/
return length(p - c) - r;
}

@compute @workgroup_size(16, 16, 1)
fn main(@builtin(global_invocation_id) globalID : vec3<u32>) {

// Normalize xy coordinates
let xy: vec2<f32> =
vec2<f32>(f32(globalID.x) / f32(params.screenwidth),
f32(globalID.y) / f32(params.screenheight));
let t: f32 = params.time / 1.0;

// 1-D index into the output GPU buffer
let idx = globalID.y * params.screenwidth + globalID.x;
let center = vec2<f32>(0.5, 0.5 + 0.3 * sin(3.0 * t));
let center2 = vec2<f32>(0.5 + 0.2 * cos(3.0 * t), 0.5);
// out[idx] += 0.4 - min(5 * abs(sdf(xy, center, 0.2)), 0.4) + 0.5 * cos(xy.y + t) + 0.5 * sin(xy.x);
out[idx] = 0.3 - min(5 * abs(sdf(xy, center, 0.2)), 0.3);
out[idx] += 0.3 - min(5 * abs(sdf(xy, center2, 0.2)), 0.3);
out[idx] += 0.4 * sin(xy.y +t);

// Draw a circle, oscillating with time
let position = vec2<f32>(0.5, 0.5 + 0.1 * sin(3.0 * params.time));
out[idx] = 0.3 - min(5 * abs(sdf(xy, position, 0.2)), 0.3);

}
83 changes: 83 additions & 0 deletions examples/shadertui/shapes.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
@group(0) @binding(0) var<storage, read_write> out: array<f32>;
@group(0) @binding(1) var<uniform> params: Params;

struct Params {
time: f32,
screenwidth: u32,
screenheight: u32,
};

fn sdf_rounded_rectangle(p: vec2<f32>, c: vec2<f32>, size: vec2<f32>, radius: f32) -> f32 {
let d = abs(p - c) - size + vec2<f32>(radius);
return length(max(d, vec2<f32>(0.0))) + min(max(d.x, d.y), 0.0) - radius;
}

fn sdf_circle(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {
return length(p - c) - r;
}

fn sdf_triangle(p: vec2<f32>, c: vec2<f32>, r: f32) -> f32 {
let k = sqrt(3.0);
let q = p - c;
let p_mod = vec2<f32>(abs(q.x) - r, q.y + r / k);
let p_final = select(
p_mod,
vec2<f32>(p_mod.x - k * p_mod.y, -k * p_mod.x - p_mod.y) / 2.0,
p_mod.x + k * p_mod.y > 0.0
);
let x_clamped = clamp(p_final.x, -2.0 * r, 0.0);
return -length(vec2<f32>(p_final.x - x_clamped, p_final.y)) * sign(p_final.y);
}

fn rotate2d(angle: f32) -> mat2x2<f32> {
let s = sin(angle);
let c = cos(angle);
return mat2x2<f32>(c, -s, s, c);
}

@compute @workgroup_size(16, 16, 1)
fn main(@builtin(global_invocation_id) globalID : vec3<u32>) {
let xy: vec2<f32> =
vec2<f32>(f32(globalID.x) / f32(params.screenwidth),
f32(globalID.y) / f32(params.screenheight));
let t: f32 = params.time / 1.0;
let idx = globalID.y * params.screenwidth + globalID.x;

let orbit_center = vec2<f32>(0.5, 0.5);
let orbit_radius = 0.3; // Increased orbit radius
let orbit_speed = 0.5;
let rotation_speed = 2.0;

// Calculate positions of the three shapes
let angle1 = t * orbit_speed;
let angle2 = angle1 + 2.0 * 3.14159 / 3.0;
let angle3 = angle2 + 2.0 * 3.14159 / 3.0;
let center1 = orbit_center + orbit_radius * vec2<f32>(cos(angle1), sin(angle1));
let center2 = orbit_center + orbit_radius * vec2<f32>(cos(angle2), sin(angle2));
let center3 = orbit_center + orbit_radius * vec2<f32>(cos(angle3), sin(angle3));

// Increased sizes for all shapes
let rect_size = vec2<f32>(0.12, 0.06); // Larger rectangle
let rect_corner_radius = 0.015; // Slightly larger corner radius
let circle_radius = 0.08; // Larger circle
let triangle_radius = 0.09; // Larger triangle

// Rotation
let rotation_angle = t * rotation_speed;
let rotation_matrix = rotate2d(rotation_angle);

// Apply rotation to the points
let rotated_point1 = (rotation_matrix * (xy - center1)) + center1;
let rotated_point2 = (rotation_matrix * (xy - center2)) + center2;
let rotated_point3 = (rotation_matrix * (xy - center3)) + center3;

// Calculate SDFs for each shape
let sdf1 = sdf_rounded_rectangle(rotated_point1, center1, rect_size, rect_corner_radius);
let sdf2 = sdf_circle(rotated_point2, center2, circle_radius);
let sdf3 = sdf_triangle(rotated_point3, center3, triangle_radius);

// Combine the SDFs
let combined_sdf = min(sdf1, min(sdf2, sdf3));

out[idx] = 0.3 - min(5.0 * abs(combined_sdf), 0.3);
}

0 comments on commit ecda921

Please sign in to comment.