diff options
| -rw-r--r-- | common/shaders/math/sdf_shapes.wgsl | 32 | ||||
| -rw-r--r-- | common/shaders/render/raymarching.wgsl | 4 | ||||
| -rw-r--r-- | workspaces/main/beat_test.track | 44 | ||||
| -rw-r--r-- | workspaces/main/pop_punk_drums.track | 2 | ||||
| -rw-r--r-- | workspaces/main/shaders/scene1.wgsl | 81 | ||||
| -rw-r--r-- | workspaces/main/workspace.cfg | 3 |
6 files changed, 116 insertions, 50 deletions
diff --git a/common/shaders/math/sdf_shapes.wgsl b/common/shaders/math/sdf_shapes.wgsl index 64df4fc..4dcfdd6 100644 --- a/common/shaders/math/sdf_shapes.wgsl +++ b/common/shaders/math/sdf_shapes.wgsl @@ -23,34 +23,8 @@ fn sdBox2D(p: vec2<f32>, b: vec2<f32>) -> f32 { return length(max(d, vec2<f32>(0.0))) + min(max(d.x, d.y), 0.0); } +// Approximate fn sdEllipse(p: vec2<f32>, ab: vec2<f32>) -> f32 { - var p_abs = abs(p); - if (p_abs.x > p_abs.y) { - p_abs = vec2<f32>(p_abs.y, p_abs.x); - } - let l = ab.y * ab.y - ab.x * ab.x; - let m = ab.x * p_abs.x / l; - let n = ab.y * p_abs.y / l; - let m2 = m * m; - let n2 = n * n; - let c = (m2 + n2 - 1.0) / 3.0; - let c3 = c * c * c; - let d = c3 + m2 * n2; - let g = m + m * n2; - var co: f32; - if (d < 0.0) { - let h = acos((c3 + m2 * n2 * 2.0) / c3) / 3.0; - let s = cos(h); - let t = sin(h) * sqrt(3.0); - co = (sqrt(-c * (s + t * 2.0) + m2) + sign(l) * sqrt(-c * (s - t * 2.0) + m2) + abs(g) / (sqrt(-c * (s + t * 2.0) + m2) * sqrt(-c * (s - t * 2.0) + m2)) - m) / 2.0; - } else { - let h = 2.0 * m * n * sqrt(d); - let s = sign(c3 + m2 * n2 + h) * pow(abs(c3 + m2 * n2 + h), 1.0 / 3.0); - let u = sign(c3 + m2 * n2 - h) * pow(abs(c3 + m2 * n2 - h), 1.0 / 3.0); - let rx = -s - u + m2 * 2.0; - let ry = (s - u) * sqrt(3.0); - co = (ry / sqrt(sqrt(rx * rx + ry * ry) - rx) + 2.0 * g / sqrt(rx * rx + ry * ry) - m) / 2.0; - } - let si = sqrt(max(0.0, 1.0 - co * co)); - return length(p_abs - vec2<f32>(ab.x * co, ab.y * si)) * sign(p_abs.y * ab.x * co - p_abs.x * ab.y * si); + let d = length(p / ab); + return length(p) * (1.0 - 1.0 / d); } diff --git a/common/shaders/render/raymarching.wgsl b/common/shaders/render/raymarching.wgsl index 3adec8d..7d05528 100644 --- a/common/shaders/render/raymarching.wgsl +++ b/common/shaders/render/raymarching.wgsl @@ -26,8 +26,8 @@ fn normal(pos: vec3<f32>) -> vec3<f32> { // Performs the raymarching operation. // Returns the distance along the ray to the surface, or MAX_RAY_LENGTH if no surface is hit. -fn rayMarch(ro: vec3<f32>, rd: vec3<f32>, initt: f32) -> f32 { - var t = initt; +fn rayMarch(ro: vec3<f32>, rd: vec3<f32>, tmin: f32) -> f32 { + var t = tmin; for (var i = 0; i < MAX_RAY_MARCHES; i++) { if (t > MAX_RAY_LENGTH) { t = MAX_RAY_LENGTH; diff --git a/workspaces/main/beat_test.track b/workspaces/main/beat_test.track new file mode 100644 index 0000000..1b7f9b1 --- /dev/null +++ b/workspaces/main/beat_test.track @@ -0,0 +1,44 @@ +# Pop-Punk High-Energy Drum Track +# Converted from track.md drum sequence +# 4/4 time signature, 16th note resolution + +BPM 90 + +# Drum samples (General MIDI mapping) +SAMPLE ASSET_KICK_1 +SAMPLE ASSET_SNARE_1 + +# Pattern A: Main Driving Groove (bars 1-3) +# 1 unit = 4 beats, 16th notes = 0.0625 units apart +PATTERN main_groove LENGTH 1.0 + # Snare: beats 2 and 4 (strong) + 0.2500, ASSET_SNARE_1, 1.0, 0.0 + 0.7500, ASSET_SNARE_1, 1.0, 0.0 + # Kick: syncopated pattern (galloping) + 0.0000, ASSET_KICK_1, 1.0, 0.0 + 0.5000, ASSET_KICK_1, 1.0, 0.0 + # Crash on beat 1 + 0.0000, ASSET_CRASH_1, 0.9, 0.0 + + +# Score +SCORE + 0.0, main_groove_crash + 1.0, main_groove_crash + 2.0, main_groove_crash + 3.0, main_groove_crash + + 4.0, main_groove_crash + 5.0, main_groove_crash + 6.0, main_groove_crash + 7.0, main_groove_crash + + 8.0, main_groove_crash + 9.0, main_groove_crash + 10.0, main_groove_crash + 11.0, main_groove_crash + + 12.0, main_groove_crash + 13.0, main_groove_crash + 14.0, main_groove_crash + 15.0, main_groove_crash diff --git a/workspaces/main/pop_punk_drums.track b/workspaces/main/pop_punk_drums.track index f54bf9d..236b79f 100644 --- a/workspaces/main/pop_punk_drums.track +++ b/workspaces/main/pop_punk_drums.track @@ -1,6 +1,6 @@ # Pop-Punk High-Energy Drum Track # Converted from track.md drum sequence -# 165 BPM, 4/4 time signature, 16th note resolution +# 4/4 time signature, 16th note resolution BPM 90 diff --git a/workspaces/main/shaders/scene1.wgsl b/workspaces/main/shaders/scene1.wgsl index 2723b66..8d5d5db 100644 --- a/workspaces/main/shaders/scene1.wgsl +++ b/workspaces/main/shaders/scene1.wgsl @@ -50,19 +50,22 @@ fn render0(ro: vec3<f32>, rd: vec3<f32>) -> vec3<f32> { return clamp(col, vec3<f32>(0.0), vec3<f32>(10.0)); } +const OBJ_BACKGROUND: f32 = 0.0; +const OBJ_CUBE: f32 = 1.0; +const OBJ_SPHERE: f32 = 2.0; +const OBJ_PLANE: f32 = 3.0; + fn df(p_in: vec3<f32>) -> f32 { var p = p_in; p.x = p_in.x * g_rot0[0][0] + p_in.z * g_rot0[0][1]; p.z = p_in.x * g_rot0[1][0] + p_in.z * g_rot0[1][1]; // Cube - var pc = p; - pc -= vec3<f32>(-1.9, 0.0, 0.0); + var pc = p - vec3<f32>(-1.9, 0.0, 0.0); let dCube = sdBox(pc, vec3<f32>(1.6)); // Sphere - var ps = p; - ps -= vec3<f32>(1.3, 0.0, 0.0); + var ps = p - vec3<f32>(1.3, 0.0, 0.0); let dSphere = sdSphere(ps, 1.2); // Ground plane @@ -75,6 +78,41 @@ fn df(p_in: vec3<f32>) -> f32 { return d; } +fn dfWithID(p_in: vec3<f32>) -> RayMarchResult { + var p = p_in; + p.x = p_in.x * g_rot0[0][0] + p_in.z * g_rot0[0][1]; + p.z = p_in.x * g_rot0[1][0] + p_in.z * g_rot0[1][1]; + + // Cube + var pc = p - vec3<f32>(-1.9, 0.0, 0.0); + let dCube = sdBox(pc, vec3<f32>(1.6)); + + // Sphere + var ps = p - vec3<f32>(1.3, 0.0, 0.0); + let dSphere = sdSphere(ps, 1.2); + + // Ground plane + let dPlane = p.y + 1.0; + + // Find closest object + var result: RayMarchResult; + result.distance = dCube; + result.object_id = OBJ_CUBE; + + if (dSphere < result.distance) { + result.distance = dSphere; + result.object_id = OBJ_SPHERE; + } + + if (dPlane < result.distance) { + result.distance = dPlane; + result.object_id = OBJ_PLANE; + } + + result.distance_max = result.distance; + return result; +} + fn boxCol(col: vec3<f32>, nsp: vec3<f32>, rd: vec3<f32>, nnor: vec3<f32>, nrcol: vec3<f32>, nshd1: f32, nshd2: f32) -> vec3<f32> { var nfre = 1.0 + dot(rd, nnor); nfre *= nfre; @@ -102,24 +140,35 @@ fn render1(ro: vec3<f32>, rd: vec3<f32>) -> vec3<f32> { let skyCol_local = render0(ro, rd); var col = skyCol_local; - let nt = rayMarch(ro, rd, 0.0); - if (nt < MAX_RAY_LENGTH) { - let nsp = ro + rd * nt; - let nnor = normal(nsp); + var init: RayMarchResult; + init.distance = 0.0; + init.distance_max = 0.0; + init.object_id = OBJ_BACKGROUND; + + let result = rayMarchWithID(ro, rd, init); + if (result.distance < MAX_RAY_LENGTH) { + let nsp = reconstructPosition(ro, rd, result); + let nnor = normalWithID(nsp); let nref = reflect(rd, nnor); - let nrt = rayMarch(nsp, nref, 0.2); + var refl_init: RayMarchResult; + refl_init.distance = 0.2; + refl_init.distance_max = 0.2; + refl_init.object_id = OBJ_BACKGROUND; + let nrt_result = rayMarchWithID(nsp, nref, refl_init); var nrcol = render0(nsp, nref); - if (nrt < MAX_RAY_LENGTH) { - let nrsp = nsp + nref * nrt; - let nrnor = normal(nrsp); + if (nrt_result.distance < MAX_RAY_LENGTH) { + let nrsp = reconstructPosition(nsp, nref, nrt_result); + let nrnor = normalWithID(nrsp); let nrref = reflect(nref, nrnor); nrcol = boxCol(nrcol, nrsp, nref, nrnor, render0(nrsp, nrref), 1.0, 1.0); } - let nshd1 = mix(0.0, 1.0, shadow(nsp, normalize(lightPos1 - nsp), 0.1, distance(lightPos1, nsp))); - let nshd2 = mix(0.0, 1.0, shadow(nsp, normalize(lightPos2 - nsp), 0.1, distance(lightPos2, nsp))); + let light_dist1 = distance(lightPos1, nsp); + let light_dist2 = distance(lightPos2, nsp); + let nshd1 = mix(0.0, 1.0, shadowWithStoredDistance(nsp, normalize(lightPos1 - nsp), light_dist1)); + let nshd2 = mix(0.0, 1.0, shadowWithStoredDistance(nsp, normalize(lightPos2 - nsp), light_dist2)); col = boxCol(col, nsp, rd, nnor, nrcol, nshd1, nshd2); } @@ -146,9 +195,7 @@ fn effect(p: vec2<f32>) -> vec3<f32> { #include "render/fullscreen_vs" @fragment fn fs_main(@builtin(position) p: vec4<f32>) -> @location(0) vec4<f32> { - // Flip Y to match ShaderToy convention (origin at bottom-left) - let flipped = vec2<f32>(p.x, uniforms.resolution.y - p.y); - let q = flipped / uniforms.resolution; + let q = p.xy / uniforms.resolution; var coord = -1.0 + 2.0 * q; coord.x *= uniforms.resolution.x / uniforms.resolution.y; var col = effect(coord); diff --git a/workspaces/main/workspace.cfg b/workspaces/main/workspace.cfg index 1c2f4c0..5eff423 100644 --- a/workspaces/main/workspace.cfg +++ b/workspaces/main/workspace.cfg @@ -6,7 +6,8 @@ version = "1.0" [build] target = "demo64k" timeline = "timeline.seq" -music = "pop_punk_drums.track" +# music = "pop_punk_drums.track" +music = "beat_test.track" assets = "assets.txt" asset_dirs = ["music/", "weights/", "obj/"] shader_dirs = ["shaders/"] |
