summaryrefslogtreecommitdiff
path: root/assets/final/shaders
diff options
context:
space:
mode:
Diffstat (limited to 'assets/final/shaders')
-rw-r--r--assets/final/shaders/circle_mask_compute.wgsl33
-rw-r--r--assets/final/shaders/circle_mask_render.wgsl35
-rw-r--r--assets/final/shaders/masked_cube.wgsl159
3 files changed, 227 insertions, 0 deletions
diff --git a/assets/final/shaders/circle_mask_compute.wgsl b/assets/final/shaders/circle_mask_compute.wgsl
new file mode 100644
index 0000000..610ee67
--- /dev/null
+++ b/assets/final/shaders/circle_mask_compute.wgsl
@@ -0,0 +1,33 @@
+// Circle mask compute shader
+// Generates a circular mask (1.0 inside, 0.0 outside)
+
+struct Uniforms {
+ radius: f32,
+ aspect_ratio: f32,
+ width: f32,
+ height: f32,
+};
+
+@group(0) @binding(0) var<uniform> uniforms: Uniforms;
+
+struct VSOutput {
+ @builtin(position) position: vec4<f32>,
+};
+
+@vertex fn vs_main(@builtin(vertex_index) i: u32) -> VSOutput {
+ var pos = array<vec2<f32>, 3>(
+ vec2<f32>(-1, -1), vec2<f32>(3, -1), vec2<f32>(-1, 3));
+ return VSOutput(vec4<f32>(pos[i], 0.0, 1.0));
+}
+
+@fragment fn fs_main(@builtin(position) p: vec4<f32>) -> @location(0) vec4<f32> {
+ let uv = p.xy / vec2<f32>(uniforms.width, uniforms.height);
+ let center = vec2<f32>(0.5, 0.5);
+ let aspect_corrected_uv = (uv - center) * vec2<f32>(uniforms.aspect_ratio, 1.0);
+ let dist = length(aspect_corrected_uv);
+
+ let edge_width = 0.01;
+ let mask = smoothstep(uniforms.radius + edge_width, uniforms.radius - edge_width, dist);
+
+ return vec4<f32>(mask, mask, mask, 1.0);
+}
diff --git a/assets/final/shaders/circle_mask_render.wgsl b/assets/final/shaders/circle_mask_render.wgsl
new file mode 100644
index 0000000..902600e
--- /dev/null
+++ b/assets/final/shaders/circle_mask_render.wgsl
@@ -0,0 +1,35 @@
+// Circle mask render shader
+// Samples mask and draws green outside the circle
+
+@group(0) @binding(0) var mask_tex: texture_2d<f32>;
+@group(0) @binding(1) var mask_sampler: sampler;
+
+struct Uniforms {
+ width: f32,
+ height: f32,
+ _pad1: f32,
+ _pad2: f32,
+};
+
+@group(0) @binding(2) var<uniform> uniforms: Uniforms;
+
+struct VSOutput {
+ @builtin(position) position: vec4<f32>,
+};
+
+@vertex fn vs_main(@builtin(vertex_index) i: u32) -> VSOutput {
+ var pos = array<vec2<f32>, 3>(
+ vec2<f32>(-1, -1), vec2<f32>(3, -1), vec2<f32>(-1, 3));
+ return VSOutput(vec4<f32>(pos[i], 0.0, 1.0));
+}
+
+@fragment fn fs_main(@builtin(position) p: vec4<f32>) -> @location(0) vec4<f32> {
+ let uv = p.xy / vec2<f32>(uniforms.width, uniforms.height);
+ let mask_value = textureSample(mask_tex, mask_sampler, uv).r;
+
+ if (mask_value > 0.5) {
+ discard;
+ }
+
+ return vec4<f32>(0.0, 1.0, 0.0, 1.0);
+}
diff --git a/assets/final/shaders/masked_cube.wgsl b/assets/final/shaders/masked_cube.wgsl
new file mode 100644
index 0000000..5e673a3
--- /dev/null
+++ b/assets/final/shaders/masked_cube.wgsl
@@ -0,0 +1,159 @@
+// Masked cube shader - based on renderer_3d.wgsl with mask sampling
+#include "common_uniforms"
+#include "math/common_utils"
+#include "math/sdf_utils"
+
+@group(0) @binding(0) var<uniform> globals: GlobalUniforms;
+@group(0) @binding(1) var<storage, read> object_data: ObjectsBuffer;
+@group(0) @binding(3) var noise_tex: texture_2d<f32>;
+@group(0) @binding(4) var noise_sampler: sampler;
+
+@group(1) @binding(0) var mask_tex: texture_2d<f32>;
+@group(1) @binding(1) var mask_sampler: sampler;
+
+struct VertexOutput {
+ @builtin(position) position: vec4<f32>,
+ @location(0) local_pos: vec3<f32>,
+ @location(1) color: vec4<f32>,
+ @location(2) @interpolate(flat) instance_index: u32,
+ @location(3) world_pos: vec3<f32>,
+ @location(4) transformed_normal: vec3<f32>,
+};
+
+@vertex
+fn vs_main(@builtin(vertex_index) vertex_index: u32,
+ @builtin(instance_index) instance_index: u32) -> VertexOutput {
+ var pos = array<vec3<f32>, 36>(
+ vec3(-1.0, -1.0, 1.0), vec3( 1.0, -1.0, 1.0), vec3( 1.0, 1.0, 1.0),
+ vec3(-1.0, -1.0, 1.0), vec3( 1.0, 1.0, 1.0), vec3(-1.0, 1.0, 1.0),
+ vec3(-1.0, -1.0, -1.0), vec3(-1.0, 1.0, -1.0), vec3( 1.0, 1.0, -1.0),
+ vec3(-1.0, -1.0, -1.0), vec3( 1.0, 1.0, -1.0), vec3( 1.0, -1.0, -1.0),
+ vec3(-1.0, 1.0, -1.0), vec3(-1.0, 1.0, 1.0), vec3( 1.0, 1.0, 1.0),
+ vec3(-1.0, 1.0, -1.0), vec3( 1.0, 1.0, 1.0), vec3( 1.0, 1.0, -1.0),
+ vec3(-1.0, -1.0, -1.0), vec3( 1.0, -1.0, -1.0), vec3( 1.0, -1.0, 1.0),
+ vec3(-1.0, -1.0, -1.0), vec3( 1.0, -1.0, 1.0), vec3(-1.0, -1.0, 1.0),
+ vec3( 1.0, -1.0, -1.0), vec3( 1.0, 1.0, -1.0), vec3( 1.0, 1.0, 1.0),
+ vec3( 1.0, -1.0, -1.0), vec3( 1.0, 1.0, 1.0), vec3( 1.0, -1.0, 1.0),
+ vec3(-1.0, -1.0, -1.0), vec3(-1.0, -1.0, 1.0), vec3(-1.0, 1.0, 1.0),
+ vec3(-1.0, -1.0, -1.0), vec3(-1.0, 1.0, 1.0), vec3(-1.0, 1.0, -1.0)
+ );
+
+ var p = pos[vertex_index];
+ let obj = object_data.objects[instance_index];
+ let world_pos = obj.model * vec4<f32>(p, 1.0);
+ let clip_pos = globals.view_proj * world_pos;
+
+ var out: VertexOutput;
+ out.position = clip_pos;
+ out.local_pos = p;
+ out.color = obj.color;
+ out.instance_index = instance_index;
+ out.world_pos = world_pos.xyz;
+ out.transformed_normal = normalize(vec3<f32>(0.0, 1.0, 0.0));
+
+ return out;
+}
+
+#include "render/scene_query_mode"
+#include "render/shadows"
+#include "render/lighting_utils"
+#include "ray_box"
+
+struct FragmentOutput {
+ @location(0) color: vec4<f32>,
+ @builtin(frag_depth) depth: f32,
+};
+
+@fragment
+fn fs_main(in: VertexOutput) -> FragmentOutput {
+ let screen_uv = in.position.xy / globals.resolution;
+ let mask_value = textureSample(mask_tex, mask_sampler, screen_uv).r;
+
+ if (mask_value < 0.5) {
+ discard;
+ }
+
+ let obj = object_data.objects[in.instance_index];
+ let obj_type = obj.params.x;
+
+ var p: vec3<f32>;
+ var normal: vec3<f32>;
+ var base_color = in.color.rgb;
+ let light_dir = normalize(vec3<f32>(1.0, 1.0, 1.0));
+
+ let ray_origin = globals.camera_pos_time.xyz;
+ let ray_dir = normalize(in.world_pos - ray_origin);
+ let inv_model = obj.inv_model;
+
+ let local_origin = (inv_model * vec4<f32>(ray_origin, 1.0)).xyz;
+ let local_dir = normalize((inv_model * vec4<f32>(ray_dir, 0.0)).xyz);
+
+ let bounds = ray_box_intersection(local_origin, local_dir, vec3<f32>(1.0));
+ if (!bounds.hit) {
+ discard;
+ }
+
+ let t_start = bounds.t_entry;
+ let t_end = bounds.t_exit;
+
+ var t_march = t_start;
+ let max_steps = 128;
+ var hit = false;
+ var local_p = vec3<f32>(0.0);
+
+ for (var step = 0; step < max_steps; step++) {
+ local_p = local_origin + t_march * local_dir;
+ let d = sdBox(local_p, vec3<f32>(1.0));
+
+ if (d < 0.001) {
+ hit = true;
+ break;
+ }
+
+ t_march += max(d * 0.5, 0.001);
+ if (t_march > t_end) {
+ break;
+ }
+ }
+
+ if (!hit) {
+ discard;
+ }
+
+ p = local_p;
+ let eps = 0.001;
+ normal = normalize(vec3<f32>(
+ sdBox(p + vec3<f32>(eps, 0.0, 0.0), vec3<f32>(1.0)) -
+ sdBox(p - vec3<f32>(eps, 0.0, 0.0), vec3<f32>(1.0)),
+ sdBox(p + vec3<f32>(0.0, eps, 0.0), vec3<f32>(1.0)) -
+ sdBox(p - vec3<f32>(0.0, eps, 0.0), vec3<f32>(1.0)),
+ sdBox(p + vec3<f32>(0.0, 0.0, eps), vec3<f32>(1.0)) -
+ sdBox(p - vec3<f32>(0.0, 0.0, eps), vec3<f32>(1.0))
+ ));
+
+ let world_p = (obj.model * vec4<f32>(p, 1.0)).xyz;
+ let world_normal = normalize((obj.model * vec4<f32>(normal, 0.0)).xyz);
+
+ let bump_strength = 0.3;
+ let bump_scale = 4.0;
+ let noise_uv = world_p.xy * bump_scale;
+ let noise_val = textureSample(noise_tex, noise_sampler, noise_uv).r;
+ let bump_offset = (noise_val - 0.5) * bump_strength;
+
+ let bumped_normal = normalize(world_normal + vec3<f32>(bump_offset));
+
+ let diffuse = max(dot(bumped_normal, light_dir), 0.0);
+ let ambient = 0.3;
+ let lighting = ambient + diffuse * 0.7;
+
+ let final_color = base_color * lighting;
+
+ let clip_p = globals.view_proj * vec4<f32>(world_p, 1.0);
+ let depth = clip_p.z / clip_p.w;
+
+ var out: FragmentOutput;
+ out.color = vec4<f32>(final_color, 1.0);
+ out.depth = depth;
+
+ return out;
+}