|
| 1 | +//! Custom WGSL shaders for Pascal Editor effects. |
| 2 | +//! |
| 3 | +//! These are hand-ported equivalents of the Three.js TSL (Texture Shading Language) |
| 4 | +//! node materials used in the Pascal Editor: |
| 5 | +//! - Wall cutaway dot pattern |
| 6 | +//! - Zone gradient |
| 7 | +//! - Item preview shimmer |
| 8 | +//! |
| 9 | +//! In the browser, these are defined as JavaScript function calls (TSL nodes) that |
| 10 | +//! compile to WGSL at runtime. Since we compile natively, we write the WGSL directly. |
| 11 | +
|
| 12 | +/// Wall cutaway dot pattern — shows dots that fade with height when a wall |
| 13 | +/// is in "cutaway" mode. Replaces the TSL `Fn(() => { ... fract ... step ... })`. |
| 14 | +pub const WALL_CUTAWAY_SHADER: &str = " |
| 15 | +struct CutawayParams { |
| 16 | + dot_scale: vec4<f32>, // [scale, dot_size, fade_height, opacity] |
| 17 | + base_color: vec4<f32>, // rgba |
| 18 | +}; |
| 19 | +
|
| 20 | +@group(0) @binding(0) var<uniform> params: CutawayParams; |
| 21 | +
|
| 22 | +struct VertexOutput { |
| 23 | + @builtin(position) clip_position: vec4<f32>, |
| 24 | + @location(0) local_pos: vec3<f32>, |
| 25 | + @location(1) color: vec4<f32>, |
| 26 | +}; |
| 27 | +
|
| 28 | +@fragment |
| 29 | +fn fs_wall_cutaway(in: VertexOutput) -> @location(0) vec4<f32> { |
| 30 | + let scale = params.dot_scale.x; |
| 31 | + let dot_size = params.dot_scale.y; |
| 32 | + let fade_height = params.dot_scale.z; |
| 33 | +
|
| 34 | + // Create repeating dot grid |
| 35 | + let uv = vec2<f32>(in.local_pos.x, in.local_pos.y) / scale; |
| 36 | + let grid_uv = fract(uv); |
| 37 | + let dist = length(grid_uv - vec2<f32>(0.5)); |
| 38 | + let dots = step(dist, dot_size * 0.5); |
| 39 | +
|
| 40 | + // Vertical fade (transparent near bottom, opaque at top) |
| 41 | + let y_fade = 1.0 - smoothstep(0.0, fade_height, in.local_pos.y); |
| 42 | +
|
| 43 | + let alpha = dots * y_fade * params.dot_scale.w; |
| 44 | + if (alpha < 0.01) { discard; } |
| 45 | +
|
| 46 | + return vec4<f32>(params.base_color.rgb * in.color.rgb, alpha); |
| 47 | +} |
| 48 | +"; |
| 49 | + |
| 50 | +/// Zone gradient — vertical gradient for zone visualization walls. |
| 51 | +/// Replaces the TSL `uv().y → mul(opacity)` with uniform. |
| 52 | +pub const ZONE_GRADIENT_SHADER: &str = " |
| 53 | +struct ZoneParams { |
| 54 | + base_color: vec4<f32>, // rgba |
| 55 | + opacity: vec4<f32>, // [max_opacity, 0, 0, 0] |
| 56 | +}; |
| 57 | +
|
| 58 | +@group(0) @binding(0) var<uniform> zone_params: ZoneParams; |
| 59 | +
|
| 60 | +struct VertexOutput { |
| 61 | + @builtin(position) clip_position: vec4<f32>, |
| 62 | + @location(0) uv: vec2<f32>, |
| 63 | + @location(1) color: vec4<f32>, |
| 64 | +}; |
| 65 | +
|
| 66 | +@fragment |
| 67 | +fn fs_zone_gradient(in: VertexOutput) -> @location(0) vec4<f32> { |
| 68 | + // Gradient: fully opaque at bottom, transparent at top |
| 69 | + let gradient_t = in.uv.y; |
| 70 | + let alpha = zone_params.opacity.x * (1.0 - gradient_t) * 0.6; |
| 71 | + return vec4<f32>(zone_params.base_color.rgb, alpha); |
| 72 | +} |
| 73 | +"; |
| 74 | + |
| 75 | +/// Item preview shimmer — animated shimmer effect for item placement preview. |
| 76 | +/// Replaces the TSL `positionLocal.y + time → fract → smoothstep`. |
| 77 | +pub const PREVIEW_SHIMMER_SHADER: &str = " |
| 78 | +struct ShimmerParams { |
| 79 | + time: vec4<f32>, // [time, speed, 0, 0] |
| 80 | + base_color: vec4<f32>, // rgba |
| 81 | +}; |
| 82 | +
|
| 83 | +@group(0) @binding(0) var<uniform> shimmer_params: ShimmerParams; |
| 84 | +
|
| 85 | +struct VertexOutput { |
| 86 | + @builtin(position) clip_position: vec4<f32>, |
| 87 | + @location(0) local_pos: vec3<f32>, |
| 88 | + @location(1) color: vec4<f32>, |
| 89 | +}; |
| 90 | +
|
| 91 | +@fragment |
| 92 | +fn fs_preview_shimmer(in: VertexOutput) -> @location(0) vec4<f32> { |
| 93 | + let time = shimmer_params.time.x; |
| 94 | + let speed = shimmer_params.time.y; |
| 95 | +
|
| 96 | + // Scrolling shimmer band |
| 97 | + let shimmer_y = fract((in.local_pos.y + time * speed) * 10.0); |
| 98 | + let shimmer = smoothstep(0.0, 0.1, shimmer_y) * smoothstep(0.3, 0.2, shimmer_y); |
| 99 | +
|
| 100 | + let base = shimmer_params.base_color; |
| 101 | + let brightness = 1.0 + shimmer * 0.3; |
| 102 | + return vec4<f32>(base.rgb * brightness, base.a * 0.7); |
| 103 | +} |
| 104 | +"; |
0 commit comments