diff options
| -rw-r--r-- | common/shaders/combined_postprocess.wgsl | 15 | ||||
| -rw-r--r-- | common/shaders/gaussian_blur.wgsl | 15 | ||||
| -rw-r--r-- | common/shaders/heptagon.wgsl | 15 | ||||
| -rw-r--r-- | common/shaders/passthrough.wgsl | 15 | ||||
| -rw-r--r-- | common/shaders/render/fullscreen_uv_vs.wgsl | 15 | ||||
| -rw-r--r-- | common/shaders/skybox.wgsl | 20 | ||||
| -rw-r--r-- | src/effects/shaders.cc | 2 | ||||
| -rw-r--r-- | src/gpu/shader_composer.cc | 42 | ||||
| -rw-r--r-- | workspaces/main/assets.txt | 1 | ||||
| -rw-r--r-- | workspaces/test/assets.txt | 1 |
10 files changed, 64 insertions, 77 deletions
diff --git a/common/shaders/combined_postprocess.wgsl b/common/shaders/combined_postprocess.wgsl index d56386e..bf43d6e 100644 --- a/common/shaders/combined_postprocess.wgsl +++ b/common/shaders/combined_postprocess.wgsl @@ -3,25 +3,12 @@ #include "sequence_uniforms" #include "postprocess_inline" +#include "render/fullscreen_uv_vs" // <- VertexOutput + vs_main @group(0) @binding(0) var input_sampler: sampler; @group(0) @binding(1) var input_texture: texture_2d<f32>; @group(0) @binding(2) var<uniform> uniforms: UniformsSequenceParams; -struct VertexOutput { - @builtin(position) position: vec4<f32>, - @location(0) uv: vec2<f32>, -}; - -@vertex fn vs_main(@builtin(vertex_index) vid: u32) -> VertexOutput { - var out: VertexOutput; - let x = f32((vid & 1u) << 1u); - let y = f32((vid & 2u)); - out.position = vec4<f32>(x * 2.0 - 1.0, 1.0 - y * 2.0, 0.0, 1.0); - out.uv = vec2<f32>(x, y); - return out; -} - @fragment fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> { // Sample base color var color = textureSample(input_texture, input_sampler, in.uv); diff --git a/common/shaders/gaussian_blur.wgsl b/common/shaders/gaussian_blur.wgsl index 293977f..551d522 100644 --- a/common/shaders/gaussian_blur.wgsl +++ b/common/shaders/gaussian_blur.wgsl @@ -1,5 +1,6 @@ // Gaussian blur shader for Sequence v2 #include "sequence_uniforms" +#include "render/fullscreen_uv_vs" // <- VertexOutput + vs_main @group(0) @binding(0) var input_sampler: sampler; @group(0) @binding(1) var input_texture: texture_2d<f32>; @@ -12,20 +13,6 @@ struct GaussianBlurParams { }; @group(0) @binding(3) var<uniform> params: GaussianBlurParams; -struct VertexOutput { - @builtin(position) position: vec4<f32>, - @location(0) uv: vec2<f32>, -}; - -@vertex fn vs_main(@builtin(vertex_index) vid: u32) -> VertexOutput { - var out: VertexOutput; - let x = f32((vid & 1u) << 1u); - let y = f32((vid & 2u)); - out.position = vec4<f32>(x * 2.0 - 1.0, 1.0 - y * 2.0, 0.0, 1.0); - out.uv = vec2<f32>(x, y); - return out; -} - @fragment fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> { let texel_size = 1.0 / uniforms.resolution; let offset = params.direction * texel_size; diff --git a/common/shaders/heptagon.wgsl b/common/shaders/heptagon.wgsl index 078978a..519dce5 100644 --- a/common/shaders/heptagon.wgsl +++ b/common/shaders/heptagon.wgsl @@ -1,23 +1,10 @@ // Heptagon shader for Sequence v2 #include "sequence_uniforms" +#include "render/fullscreen_uv_vs" // <- VertexOutput + vs_main // Standard v2 post-process layout (bindings 0,1 unused for scene effects) @group(0) @binding(2) var<uniform> uniforms: UniformsSequenceParams; -struct VertexOutput { - @builtin(position) position: vec4<f32>, - @location(0) uv: vec2<f32>, -}; - -@vertex fn vs_main(@builtin(vertex_index) vid: u32) -> VertexOutput { - var out: VertexOutput; - let x = f32((vid & 1u) << 1u); - let y = f32((vid & 2u)); - out.position = vec4<f32>(x * 2.0 - 1.0, 1.0 - y * 2.0, 0.0, 1.0); - out.uv = vec2<f32>(x, y); - return out; -} - fn sdf_heptagon(p: vec2<f32>, r: f32) -> f32 { let an = 3.141593 / 7.0; // PI/7 for heptagon let acs = vec2<f32>(cos(an), sin(an)); diff --git a/common/shaders/passthrough.wgsl b/common/shaders/passthrough.wgsl index 9fb0bdc..265082a 100644 --- a/common/shaders/passthrough.wgsl +++ b/common/shaders/passthrough.wgsl @@ -1,24 +1,11 @@ // Passthrough shader for Sequence v2 #include "sequence_uniforms" +#include "render/fullscreen_uv_vs" // <- VertexOutput + vs_main @group(0) @binding(0) var input_sampler: sampler; @group(0) @binding(1) var input_texture: texture_2d<f32>; @group(0) @binding(2) var<uniform> uniforms: UniformsSequenceParams; -struct VertexOutput { - @builtin(position) position: vec4<f32>, - @location(0) uv: vec2<f32>, -}; - -@vertex fn vs_main(@builtin(vertex_index) vid: u32) -> VertexOutput { - var out: VertexOutput; - let x = f32((vid & 1u) << 1u); - let y = f32((vid & 2u)); - out.position = vec4<f32>(x * 2.0 - 1.0, 1.0 - y * 2.0, 0.0, 1.0); - out.uv = vec2<f32>(x, y); - return out; -} - @fragment fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> { return textureSample(input_texture, input_sampler, in.uv); } diff --git a/common/shaders/render/fullscreen_uv_vs.wgsl b/common/shaders/render/fullscreen_uv_vs.wgsl new file mode 100644 index 0000000..42d87c3 --- /dev/null +++ b/common/shaders/render/fullscreen_uv_vs.wgsl @@ -0,0 +1,15 @@ +// Common vertex shader for fullscreen post-processing effects. +// Draws a single triangle that covers the entire screen, with uv +// coordinates in [0..1] +struct VertexOutput { + @builtin(position) position: vec4<f32>, + @location(0) uv: vec2<f32>, +}; + +@vertex fn vs_main(@builtin(vertex_index) i: u32) -> VertexOutput { + let pos = array<vec4f, 3>(vec4f(-1, -1, 0, 1.), vec4f(3, -1, 2., 1.), vec4f(-1, 3, 0, -1)); + var out: VertexOutput; + out.position = vec4f(pos[i].xy, 0.0, 1.0); + out.uv = pos[i].zw; + return out; +} diff --git a/common/shaders/skybox.wgsl b/common/shaders/skybox.wgsl index 31bea3b..d280390 100644 --- a/common/shaders/skybox.wgsl +++ b/common/shaders/skybox.wgsl @@ -1,29 +1,11 @@ #include "common_uniforms" #include "math/common_utils" +#include "render/fullscreen_uv_vs" // <- VertexOutput + vs_main @group(0) @binding(0) var sky_tex: texture_2d<f32>; @group(0) @binding(1) var sky_sampler: sampler; @group(0) @binding(2) var<uniform> globals: GlobalUniforms; -struct VertexOutput { - @builtin(position) position: vec4<f32>, - @location(0) uv: vec2<f32>, -}; - -@vertex -fn vs_main(@builtin(vertex_index) vertex_index: u32) -> VertexOutput { - var pos = array<vec2<f32>, 3>( - vec2<f32>(-1.0, -1.0), - vec2<f32>( 3.0, -1.0), - vec2<f32>(-1.0, 3.0) - ); - - var out: VertexOutput; - out.position = vec4<f32>(pos[vertex_index], 0.0, 1.0); - out.uv = vec2<f32>(pos[vertex_index].x * 0.5 + 0.5, 1.0 - (pos[vertex_index].y * 0.5 + 0.5)); - return out; -} - @fragment fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> { // Convert UV to NDC diff --git a/src/effects/shaders.cc b/src/effects/shaders.cc index 3ba00bc..7e32aa6 100644 --- a/src/effects/shaders.cc +++ b/src/effects/shaders.cc @@ -53,6 +53,8 @@ void InitShaderComposer() { register_if_exists("render/fullscreen_vs", AssetId::ASSET_SHADER_RENDER_FULLSCREEN_VS); + register_if_exists("render/fullscreen_uv_vs", + AssetId::ASSET_SHADER_RENDER_FULLSCREEN_UV_VS); register_if_exists("math/color", AssetId::ASSET_SHADER_MATH_COLOR); register_if_exists("math/utils", AssetId::ASSET_SHADER_MATH_UTILS); register_if_exists("render/raymarching", diff --git a/src/gpu/shader_composer.cc b/src/gpu/shader_composer.cc index fce6de4..be311dd 100644 --- a/src/gpu/shader_composer.cc +++ b/src/gpu/shader_composer.cc @@ -2,6 +2,7 @@ // It implements the ShaderComposer class. #include "gpu/shader_composer.h" +#include <cassert> #include <set> #include <sstream> @@ -44,6 +45,27 @@ void ShaderComposer::ResolveRecursive(const std::string& source, ss << "// --- End Include: " << name << " ---\n"; } else { ss << "// ERROR: Snippet not found: " << name << "\n"; +#if !defined(STRIP_ALL) + // Find suggestions: registered snippets whose basename matches. + std::string suggestion; + for (const auto& [sname, _] : snippets_) { + auto slash = sname.rfind('/'); + std::string basename = + (slash == std::string::npos) ? sname : sname.substr(slash + 1); + if (basename == name) { + suggestion = sname; + break; + } + } + fprintf(stderr, + "FATAL: #include \"%s\" - snippet not registered.\n", + name.c_str()); + if (!suggestion.empty()) { + fprintf(stderr, " Fix: use #include \"%s\"\n", + suggestion.c_str()); + } + assert(false && "Unresolved shader #include"); +#endif } } } @@ -111,10 +133,26 @@ void ShaderComposer::VerifyIncludes() const { } } if (!missing.empty()) { - fprintf(stderr, "WARNING: Unregistered shader snippets:\n"); + fprintf(stderr, "ERROR: Unregistered shader snippets referenced in #include:\n"); for (const auto& name : missing) { - fprintf(stderr, " - %s\n", name.c_str()); + std::string suggestion; + for (const auto& [sname, _] : snippets_) { + auto slash = sname.rfind('/'); + std::string basename = + (slash == std::string::npos) ? sname : sname.substr(slash + 1); + if (basename == name) { + suggestion = sname; + break; + } + } + if (!suggestion.empty()) { + fprintf(stderr, " - \"%s\" (did you mean \"%s\"?)\n", name.c_str(), + suggestion.c_str()); + } else { + fprintf(stderr, " - \"%s\"\n", name.c_str()); + } } + assert(false && "Unregistered shader snippets - fix #include paths"); } #endif } diff --git a/workspaces/main/assets.txt b/workspaces/main/assets.txt index 61d65d0..ba28b04 100644 --- a/workspaces/main/assets.txt +++ b/workspaces/main/assets.txt @@ -68,6 +68,7 @@ SHADER_MESH, NONE, shaders/mesh_render.wgsl, "Mesh Rasterization Shader" MESH_CUBE, NONE, obj/test_mesh.obj, "A simple cube mesh" DODECAHEDRON, NONE, obj/dodecahedron.obj, "A dodecahedron mesh" SHADER_RENDER_FULLSCREEN_VS, NONE, ../../common/shaders/render/fullscreen_vs.wgsl, "Fullscreen Vertex Shader" +SHADER_RENDER_FULLSCREEN_UV_VS, NONE, ../../common/shaders/render/fullscreen_uv_vs.wgsl, "Fullscreen Vertex Shader + UV" SHADER_MATH_COLOR, NONE, ../../common/shaders/math/color.wgsl, "Color Functions" SHADER_MATH_UTILS, NONE, ../../common/shaders/math/utils.wgsl, "Math Utilities" SHADER_RENDER_RAYMARCHING, NONE, ../../common/shaders/render/raymarching.wgsl, "Raymarching Functions" diff --git a/workspaces/test/assets.txt b/workspaces/test/assets.txt index a2d3002..7835cf8 100644 --- a/workspaces/test/assets.txt +++ b/workspaces/test/assets.txt @@ -55,6 +55,7 @@ SHADER_MESH, NONE, shaders/mesh_render.wgsl, "Mesh Rasterization Shader" MESH_CUBE, NONE, obj/test_mesh.obj, "A simple cube mesh" DODECAHEDRON, NONE, obj/dodecahedron.obj, "A dodecahedron mesh" SHADER_RENDER_FULLSCREEN_VS, NONE, ../../common/shaders/render/fullscreen_vs.wgsl, "Fullscreen Vertex Shader" +SHADER_RENDER_FULLSCREEN_UV_VS, NONE, ../../common/shaders/render/fullscreen_uv_vs.wgsl, "Fullscreen Vertex Shader + UV" SHADER_MATH_COLOR, NONE, ../../common/shaders/math/color.wgsl, "Color Functions" SHADER_MATH_UTILS, NONE, ../../common/shaders/math/utils.wgsl, "Math Utilities" SHADER_RENDER_RAYMARCHING, NONE, ../../common/shaders/render/raymarching.wgsl, "Raymarching Functions" |
