diff --git a/shaders/slang/imgui/scene.slang b/shaders/slang/imgui/scene.slang new file mode 100644 index 00000000..5757b95c --- /dev/null +++ b/shaders/slang/imgui/scene.slang @@ -0,0 +1,57 @@ +/* Copyright (c) 2025, Sascha Willems + * + * SPDX-License-Identifier: MIT + * + */ + +struct VSInput +{ + float3 Pos; + float3 Normal; + float3 Color; +}; + +struct VSOutput +{ + float4 Pos : SV_POSITION; + float3 Normal; + float3 Color; + float3 ViewVec; + float3 LightVec; +}; + +struct UBO +{ + float4x4 projection; + float4x4 model; + float4 lightPos; +}; +ConstantBuffer ubo; + +[shader("vertex")] +VSOutput vertexMain(VSInput input) +{ + VSOutput output; + output.Normal = input.Normal; + output.Color = input.Color; + output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0))); + + float4 pos = mul(ubo.model, float4(input.Pos, 1.0)); + output.Normal = mul((float4x3)ubo.model, input.Normal).xyz; + float3 lPos = mul((float4x3)ubo.model, ubo.lightPos.xyz).xyz; + output.LightVec = lPos - pos.xyz; + output.ViewVec = -pos.xyz; + return output; +} + +[shader("fragment")] +float4 fragmentMain(VSOutput input) +{ + float3 N = normalize(input.Normal); + float3 L = normalize(input.LightVec); + float3 V = normalize(input.ViewVec); + float3 R = reflect(-L, N); + float diffuse = max(dot(N, L), 0.0); + float3 specular = pow(max(dot(R, V), 0.0), 16.0) * float3(0.75, 0.75, 0.75); + return float4(diffuse * input.Color + specular, 1.0); +} \ No newline at end of file diff --git a/shaders/slang/imgui/ui.slang b/shaders/slang/imgui/ui.slang new file mode 100644 index 00000000..603799e4 --- /dev/null +++ b/shaders/slang/imgui/ui.slang @@ -0,0 +1,37 @@ +/* Copyright (c) 2025, Sascha Willems + * + * SPDX-License-Identifier: MIT + * + */ + +struct VSInput +{ + float2 Pos; + float2 UV; + float4 Color; +}; + +struct VSOutput +{ + float4 Pos : SV_POSITION; + float2 UV; + float4 Color; +}; + +Sampler2D fontSampler; + +[shader("vertex")] +VSOutput vertexMain(VSInput input, uniform float2 scale, uniform float2 translate) +{ + VSOutput output; + output.UV = input.UV; + output.Color = input.Color; + output.Pos = float4(input.Pos * scale + translate, 0.0, 1.0); + return output; +} + +[shader("fragment")] +float4 fragmentMain(VSOutput input) +{ + return input.Color * fontSampler.Sample(input.UV); +} \ No newline at end of file diff --git a/shaders/slang/indirectdraw/ground.slang b/shaders/slang/indirectdraw/ground.slang new file mode 100644 index 00000000..ac8624ac --- /dev/null +++ b/shaders/slang/indirectdraw/ground.slang @@ -0,0 +1,44 @@ +/* Copyright (c) 2025, Sascha Willems + * + * SPDX-License-Identifier: MIT + * + */ + +struct VSInput +{ + float4 Pos; + float3 Normal; + float2 UV; + float3 Color; +}; + +struct VSOutput +{ + float4 Pos : SV_POSITION; + float2 UV; +}; + +struct UBO +{ + float4x4 projection; + float4x4 modelview; +}; +ConstantBuffer ubo; + +[[vk::binding(2,0)]] Sampler2D samplerColor; + +[shader("vertex")] +VSOutput vertexMain(VSInput input) +{ + VSOutput output; + output.UV = input.UV * 32.0; + output.Pos = mul(ubo.projection, mul(ubo.modelview, float4(input.Pos.xyz, 1.0))); + return output; +} + +[shader("fragment")] +float4 fragmentMain(VSOutput input) +{ + float4 color = samplerColor.Sample(input.UV); + return float4(color.rgb, 1.0); +} \ No newline at end of file diff --git a/shaders/slang/indirectdraw/indirectdraw.slang b/shaders/slang/indirectdraw/indirectdraw.slang new file mode 100644 index 00000000..8c35d5e4 --- /dev/null +++ b/shaders/slang/indirectdraw/indirectdraw.slang @@ -0,0 +1,104 @@ +/* Copyright (c) 2025, Sascha Willems + * + * SPDX-License-Identifier: MIT + * + */ + +struct VSInput +{ + float4 Pos; + float3 Normal; + float2 UV; + float3 Color; + float3 instancePos; + float3 instanceRot; + float instanceScale; + int instanceTexIndex; +}; + +struct VSOutput +{ + float4 Pos : SV_POSITION; + float3 Normal; + float3 Color; + float3 UV; + float3 ViewVec; + float3 LightVec; +}; + +struct UBO +{ + float4x4 projection; + float4x4 modelview; +}; +ConstantBuffer ubo; + +Sampler2DArray samplerArray; + +[shader("vertex")] +VSOutput vertexMain(VSInput input) +{ + VSOutput output; + output.Color = input.Color; + output.UV = float3(input.UV, input.instanceTexIndex); + + float4x4 mx, my, mz; + + // rotate around x + float s = sin(input.instanceRot.x); + float c = cos(input.instanceRot.x); + + mx[0] = float4(c, s, 0.0, 0.0); + mx[1] = float4(-s, c, 0.0, 0.0); + mx[2] = float4(0.0, 0.0, 1.0, 0.0); + mx[3] = float4(0.0, 0.0, 0.0, 1.0); + + // rotate around y + s = sin(input.instanceRot.y); + c = cos(input.instanceRot.y); + + my[0] = float4(c, 0.0, s, 0.0); + my[1] = float4(0.0, 1.0, 0.0, 0.0); + my[2] = float4(-s, 0.0, c, 0.0); + my[3] = float4(0.0, 0.0, 0.0, 1.0); + + // rot around z + s = sin(input.instanceRot.z); + c = cos(input.instanceRot.z); + + mz[0] = float4(1.0, 0.0, 0.0, 0.0); + mz[1] = float4(0.0, c, s, 0.0); + mz[2] = float4(0.0, -s, c, 0.0); + mz[3] = float4(0.0, 0.0, 0.0, 1.0); + + float4x4 rotMat = mul(mz, mul(my, mx)); + + output.Normal = mul((float4x3)rotMat, input.Normal).xyz; + + float4 pos = mul(rotMat, float4((input.Pos.xyz * input.instanceScale) + input.instancePos, 1.0)); + + output.Pos = mul(ubo.projection, mul(ubo.modelview, pos)); + + float4 wPos = mul(ubo.modelview, float4(pos.xyz, 1.0)); + float4 lPos = float4(0.0, -5.0, 0.0, 1.0); + output.LightVec = lPos.xyz - pos.xyz; + output.ViewVec = -pos.xyz; + return output; +} + +[shader("fragment")] +float4 fragmentMain(VSOutput input) +{ + float4 color = samplerArray.Sample(input.UV); + + if (color.a < 0.5) + { + clip(-1); + } + + float3 N = normalize(input.Normal); + float3 L = normalize(input.LightVec); + float3 ambient = float3(0.65, 0.65, 0.65); + float3 diffuse = max(dot(N, L), 0.0) * input.Color; + return float4((ambient + diffuse) * color.rgb, 1.0); +} diff --git a/shaders/slang/indirectdraw/skysphere.slang b/shaders/slang/indirectdraw/skysphere.slang new file mode 100644 index 00000000..6bf4679e --- /dev/null +++ b/shaders/slang/indirectdraw/skysphere.slang @@ -0,0 +1,42 @@ +/* Copyright (c) 2025, Sascha Willems + * + * SPDX-License-Identifier: MIT + * + */ + +struct VSInput +{ + float4 Pos; + float2 UV; +}; + +struct VSOutput +{ + float4 Pos : SV_POSITION; + float2 UV; +}; + +struct UBO +{ + float4x4 projection; + float4x4 modelview; +}; +ConstantBuffer ubo; + +[shader("vertex")] +VSOutput vertexMain(VSInput input) +{ + VSOutput output; + output.UV = input.UV; + // Skysphere always at center, only use rotation part of modelview matrix + output.Pos = mul(ubo.projection, float4(mul((float3x3)ubo.modelview, input.Pos.xyz), 1)); + return output; +} + +[shader("fragment")] +float4 fragmentMain(VSOutput input) +{ + const float4 gradientStart = float4(0.93, 0.9, 0.81, 1.0); + const float4 gradientEnd = float4(0.35, 0.5, 1.0, 1.0); + return lerp(gradientStart, gradientEnd, min(0.5 - (input.UV.y + 0.05), 0.5)/0.15 - 0.5); +} \ No newline at end of file diff --git a/shaders/slang/inlineuniformblocks/pbr.slang b/shaders/slang/inlineuniformblocks/pbr.slang new file mode 100644 index 00000000..825d4902 --- /dev/null +++ b/shaders/slang/inlineuniformblocks/pbr.slang @@ -0,0 +1,137 @@ +/* Copyright (c) 2025, Sascha Willems + * + * SPDX-License-Identifier: MIT + * + */ + +struct VSInput +{ + float3 Pos; + float3 Normal; +}; + +struct VSOutput +{ + float4 Pos : SV_POSITION; + float3 WorldPos; + float3 Normal; +}; + +struct UBO +{ + float4x4 projection; + float4x4 model; + float4x4 view; + float3 camPos; +}; +ConstantBuffer ubo; + +// Inline uniform block +struct UniformInline { + float roughness; + float metallic; + float r; + float g; + float b; + float ambient; +}; +[[vk::binding(0,1)]] ConstantBuffer material; + +#define PI 3.14159265359 +#define MATERIALCOLOR float3(material.r, material.g, material.b) + +// Normal Distribution function -------------------------------------- +float D_GGX(float dotNH, float roughness) +{ + float alpha = roughness * roughness; + float alpha2 = alpha * alpha; + float denom = dotNH * dotNH * (alpha2 - 1.0) + 1.0; + return (alpha2)/(PI * denom*denom); +} + +// Geometric Shadowing function -------------------------------------- +float G_SchlicksmithGGX(float dotNL, float dotNV, float roughness) +{ + float r = (roughness + 1.0); + float k = (r*r) / 8.0; + float GL = dotNL / (dotNL * (1.0 - k) + k); + float GV = dotNV / (dotNV * (1.0 - k) + k); + return GL * GV; +} + +// Fresnel function ---------------------------------------------------- +float3 F_Schlick(float cosTheta, float metallic) +{ + float3 F0 = lerp(float3(0.04, 0.04, 0.04), MATERIALCOLOR, metallic); // * material.specular + float3 F = F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); + return F; +} + +// Specular BRDF composition -------------------------------------------- + +float3 BRDF(float3 L, float3 V, float3 N, float metallic, float roughness) +{ + // Precalculate vectors and dot products + float3 H = normalize (V + L); + float dotNV = clamp(dot(N, V), 0.0, 1.0); + float dotNL = clamp(dot(N, L), 0.0, 1.0); + float dotLH = clamp(dot(L, H), 0.0, 1.0); + float dotNH = clamp(dot(N, H), 0.0, 1.0); + + // Light color fixed + float3 lightColor = float3(1.0, 1.0, 1.0); + + float3 color = float3(0.0, 0.0, 0.0); + + if (dotNL > 0.0) + { + float rroughness = max(0.05, roughness); + // D = Normal distribution (Distribution of the microfacets) + float D = D_GGX(dotNH, rroughness); + // G = Geometric shadowing term (Microfacets shadowing) + float G = G_SchlicksmithGGX(dotNL, dotNV, rroughness); + // F = Fresnel factor (Reflectance depending on angle of incidence) + float3 F = F_Schlick(dotNV, metallic); + + float3 spec = D * F * G / (4.0 * dotNL * dotNV); + + color += spec * dotNL * lightColor; + } + + return color; +} + +[shader("vertex")] +VSOutput vertexMain(VSInput input, uniform float3 objPos) +{ + VSOutput output; + float3 locPos = mul(ubo.model, float4(input.Pos, 1.0)).xyz; + output.WorldPos = locPos + objPos; + output.Normal = mul((float4x3)ubo.model, input.Normal).xyz; + output.Pos = mul(ubo.projection, mul(ubo.view, float4(output.WorldPos, 1.0))); + return output; +} + +[shader("fragment")] +float4 fragmentMain(VSOutput input) +{ + float3 N = normalize(input.Normal); + float3 V = normalize(ubo.camPos - input.WorldPos); + + float roughness = material.roughness; + + // Specular contribution + float3 lightPos = float3(0.0f, 0.0f, 10.0f); + float3 Lo = float3(0.0, 0.0, 0.0); + float3 L = normalize(lightPos.xyz - input.WorldPos); + Lo += BRDF(L, V, N, material.metallic, roughness); + + // Combine with ambient + float3 color = MATERIALCOLOR * material.ambient; + color += Lo; + + // Gamma correct + color = pow(color, float3(0.4545, 0.4545, 0.4545)); + + return float4(color, 1.0); +} \ No newline at end of file diff --git a/shaders/slang/inputattachments/attachmentread.slang b/shaders/slang/inputattachments/attachmentread.slang new file mode 100644 index 00000000..3612f1ca --- /dev/null +++ b/shaders/slang/inputattachments/attachmentread.slang @@ -0,0 +1,52 @@ +/* Copyright (c) 2025, Sascha Willems + * + * SPDX-License-Identifier: MIT + * + */ + +struct VSOutput +{ + float4 Pos : SV_POSITION; +}; + +[[vk::input_attachment_index(0)]] [[vk::binding(0)]] SubpassInput inputColor; +[[vk::input_attachment_index(1)]] [[vk::binding(1)]] SubpassInput inputDepth; + +struct UBO { + float2 brightnessContrast; + float2 range; + int attachmentIndex; +}; +ConstantBuffer ubo; + +float3 brightnessContrast(float3 color, float brightness, float contrast) { + return (color - 0.5) * contrast + 0.5 + brightness; +} + +[shader("vertex")] +VSOutput vertexMain(uint VertexIndex: SV_VertexID) +{ + VSOutput output; + output.Pos = float4(float2((VertexIndex << 1) & 2, VertexIndex & 2) * 2.0f - 1.0f, 0.0f, 1.0f); + return output; +} + +[shader("fragment")] +float4 fragmentMain() +{ + // Apply brightness and contrast filer to color input + if (ubo.attachmentIndex == 0) { + // Read color from previous color input attachment + float3 color = inputColor.SubpassLoad().rgb; + return float4(brightnessContrast(color, ubo.brightnessContrast[0], ubo.brightnessContrast[1]), 1.0); + } + + // Visualize depth input range + if (ubo.attachmentIndex == 1) { + // Read depth from previous depth input attachment + float depth = inputDepth.SubpassLoad().r; + return float4((depth - ubo.range[0]) * 1.0 / (ubo.range[1] - ubo.range[0]).xxx, 1.0); + } + + return float4(1.0); +} \ No newline at end of file diff --git a/shaders/slang/inputattachments/attachmentwrite.slang b/shaders/slang/inputattachments/attachmentwrite.slang new file mode 100644 index 00000000..e27e4e0e --- /dev/null +++ b/shaders/slang/inputattachments/attachmentwrite.slang @@ -0,0 +1,56 @@ +/* Copyright (c) 2025, Sascha Willems + * + * SPDX-License-Identifier: MIT + * + */ + +struct VSInput +{ + float3 Pos; + float3 Color; + float3 Normal; +}; + +struct VSOutput +{ + float4 Pos : SV_POSITION; + float3 Color; + float3 Normal; + float3 ViewVec; + float3 LightVec; +}; + +struct UBO { + float4x4 projection; + float4x4 model; + float4x4 view; +}; +ConstantBuffer ubo; + +[shader("vertex")] +VSOutput vertexMain(VSInput input) +{ + VSOutput output; + output.Pos = mul(ubo.projection, mul(ubo.view, mul(ubo.model, float4(input.Pos, 1.0)))); + output.Color = input.Color; + output.Normal = input.Normal; + output.LightVec = float3(0.0f, 5.0f, 15.0f) - input.Pos; + output.ViewVec = -input.Pos.xyz; + return output; +} + +[shader("fragment")] +float4 fragmentMain(VSOutput input) +{ + // Toon shading color attachment output + float intensity = dot(normalize(input.Normal), normalize(input.LightVec)); + float shade = 1.0; + shade = intensity < 0.5 ? 0.75 : shade; + shade = intensity < 0.35 ? 0.6 : shade; + shade = intensity < 0.25 ? 0.5 : shade; + shade = intensity < 0.1 ? 0.25 : shade; + + return float4(input.Color * 3.0 * shade, 1.0); + + // Depth attachment does not need to be explicitly written +} \ No newline at end of file