diff --git a/shaders/slang/particlesystem/normalmap.slang b/shaders/slang/particlesystem/normalmap.slang new file mode 100644 index 00000000..6b471e4b --- /dev/null +++ b/shaders/slang/particlesystem/normalmap.slang @@ -0,0 +1,98 @@ +/* Copyright (c) 2025, Sascha Willems + * + * SPDX-License-Identifier: MIT + * + */ + +struct VSInput +{ + float3 Pos; + float2 UV; + float3 Normal; + float4 Tangent; +}; + +struct VSOutput +{ + float4 Pos : SV_POSITION; + float2 UV; + float3 LightVec; + float3 LightVecB; + float3 LightDir; + float3 ViewVec; +}; + +struct UBO +{ + float4x4 projection; + float4x4 model; + float4x4 normal; + float4 lightPos; +}; +ConstantBuffer ubo; + +Sampler2D samplerColorMap; +Sampler2D samplerNormalHeightMap; + +#define lightRadius 45.0 + +[shader("vertex")] +VSOutput vertexMain(VSInput input) +{ + VSOutput output; + float3 vertexPosition = mul(ubo.model, float4(input.Pos, 1.0)).xyz; + output.LightDir = normalize(ubo.lightPos.xyz - vertexPosition); + + float3 biTangent = cross(input.Normal, input.Tangent.xyz); + + // Setup (t)angent-(b)inormal-(n)ormal matrix for converting + // object coordinates into tangent space + float3x3 tbnMatrix; + tbnMatrix[0] = mul((float3x3)ubo.normal, input.Tangent.xyz); + tbnMatrix[1] = mul((float3x3)ubo.normal, biTangent); + tbnMatrix[2] = mul((float3x3)ubo.normal, input.Normal); + + output.LightVec.xyz = mul(float3(ubo.lightPos.xyz - vertexPosition), tbnMatrix); + + float3 lightDist = ubo.lightPos.xyz - input.Pos; + output.LightVecB.x = dot(input.Tangent.xyz, lightDist); + output.LightVecB.y = dot(biTangent, lightDist); + output.LightVecB.z = dot(input.Normal, lightDist); + + output.ViewVec.x = dot(input.Tangent.xyz, input.Pos); + output.ViewVec.y = dot(biTangent, input.Pos); + output.ViewVec.z = dot(input.Normal, input.Pos); + + output.UV = input.UV; + + output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos, 1.0))); + return output; +} + +[shader("fragment")] +float4 fragmentMain(VSOutput input) +{ + float3 specularColor = float3(0.85, 0.5, 0.0); + + float invRadius = 1.0/lightRadius; + float ambient = 0.25; + + float3 rgb, normal; + + rgb = samplerColorMap.Sample(input.UV).rgb; + normal = normalize((samplerNormalHeightMap.Sample(input.UV).rgb - 0.5) * 2.0); + + float distSqr = dot(input.LightVecB, input.LightVecB); + float3 lVec = input.LightVecB * rsqrt(distSqr); + + float atten = max(clamp(1.0 - invRadius * sqrt(distSqr), 0.0, 1.0), ambient); + float diffuse = clamp(dot(lVec, normal), 0.0, 1.0); + + float3 light = normalize(-input.LightVec); + float3 view = normalize(input.ViewVec); + float3 reflectDir = reflect(-light, normal); + + float specular = pow(max(dot(view, reflectDir), 0.0), 4.0); + + return float4((rgb * atten + (diffuse * rgb + 0.5 * specular * specularColor.rgb)) * atten, 1.0); +} \ No newline at end of file diff --git a/shaders/slang/particlesystem/particle.slang b/shaders/slang/particlesystem/particle.slang new file mode 100644 index 00000000..d479260c --- /dev/null +++ b/shaders/slang/particlesystem/particle.slang @@ -0,0 +1,97 @@ +/* Copyright (c) 2025, Sascha Willems + * + * SPDX-License-Identifier: MIT + * + */ + +struct VSInput +{ + float4 Pos; + float4 Color; + float Alpha; + float Size; + float Rotation; + int Type; +}; + +struct VSOutput +{ + float4 Pos : SV_POSITION; + float PSize : SV_PointSize; + float4 Color; + float Alpha; + int Type; + float Rotation; + float2 CenterPos; + float PointSize; +}; + +struct UBO +{ + float4x4 projection; + float4x4 modelview; + float2 viewportDim; + float pointSize; +}; +ConstantBuffer ubo; + +Sampler2D samplerSmoke; +Sampler2D samplerFire; + +[shader("vertex")] +VSOutput vertexMain(VSInput input) +{ + VSOutput output; + output.Color = input.Color; + output.Alpha = input.Alpha; + output.Type = input.Type; + output.Rotation = input.Rotation; + + output.Pos = mul(ubo.projection, mul(ubo.modelview, float4(input.Pos.xyz, 1.0))); + + // Base size of the point sprites + float spriteSize = 8.0 * input.Size; + + // Scale particle size depending on camera projection + float4 eyePos = mul(ubo.modelview, float4(input.Pos.xyz, 1.0)); + float4 projectedCorner = mul(ubo.projection, float4(0.5 * spriteSize, 0.5 * spriteSize, eyePos.z, eyePos.w)); + output.PointSize = output.PSize = ubo.viewportDim.x * projectedCorner.x / projectedCorner.w; + output.CenterPos = ((output.Pos.xy / output.Pos.w) + 1.0) * 0.5 * ubo.viewportDim; + return output; +} + +[shader("fragment")] +float4 fragmentMain(VSOutput input) +{ + float4 color; + float alpha = (input.Alpha <= 1.0) ? input.Alpha : 2.0 - input.Alpha; + + // Rotate texture coordinates + // Rotate UV + float rotCenter = 0.5; + float rotCos = cos(input.Rotation); + float rotSin = sin(input.Rotation); + + float2 PointCoord = (input.Pos.xy - input.CenterPos.xy) / input.PointSize + 0.5; + + float2 rotUV = float2( + rotCos * (PointCoord.x - rotCenter) + rotSin * (PointCoord.y - rotCenter) + rotCenter, + rotCos * (PointCoord.y - rotCenter) - rotSin * (PointCoord.x - rotCenter) + rotCenter); + + float4 outFragColor; + if (input.Type == 0) + { + // Flame + color = samplerFire.Sample(rotUV); + outFragColor.a = 0.0; + } + else + { + // Smoke + color = samplerSmoke.Sample(rotUV); + outFragColor.a = color.a * alpha; + } + + outFragColor.rgb = color.rgb * input.Color.rgb * alpha; + return outFragColor; +} \ No newline at end of file diff --git a/shaders/slang/radialblur/colorpass.slang b/shaders/slang/radialblur/colorpass.slang new file mode 100644 index 00000000..c36de69e --- /dev/null +++ b/shaders/slang/radialblur/colorpass.slang @@ -0,0 +1,51 @@ +/* Copyright (c) 2025, Sascha Willems + * + * SPDX-License-Identifier: MIT + * + */ + +struct VSInput +{ + float3 Pos; + float2 UV; + float3 Color; +}; + +struct VSOutput +{ + float4 Pos : SV_POSITION; + float3 Color; + float2 UV; +}; + +struct UBO +{ + float4x4 projection; + float4x4 model; + float gradientPos; +}; +ConstantBuffer ubo; + +Sampler2D samplerGradientRamp; + +[shader("vertex")] +VSOutput vertexMain(VSInput input) +{ + VSOutput output; + output.Color = input.Color; + output.UV = float2(ubo.gradientPos, 0.0f); + output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos, 1.0))); + return output; +} + +[shader("fragment")] +float4 fragmentMain(VSOutput input) +{ + // Use max. color channel value to detect bright glow emitters + if ((input.Color.r >= 0.9) || (input.Color.g >= 0.9) || (input.Color.b >= 0.9)) + { + return float4(samplerGradientRamp.Sample(input.UV).rgb, 1); + } else { + return float4(input.Color, 1); + } +} \ No newline at end of file diff --git a/shaders/slang/radialblur/phongpass.slang b/shaders/slang/radialblur/phongpass.slang new file mode 100644 index 00000000..7569146d --- /dev/null +++ b/shaders/slang/radialblur/phongpass.slang @@ -0,0 +1,67 @@ +/* Copyright (c) 2025, Sascha Willems + * + * SPDX-License-Identifier: MIT + * + */ + +struct VSInput +{ + float4 Pos; + float2 UV; + float3 Color; + float3 Normal; +}; + +struct VSOutput +{ + float4 Pos : SV_POSITION; + float3 Normal; + float3 Color; + float3 EyePos; + float3 LightVec; + float2 UV; +}; + +struct UBO +{ + float4x4 projection; + float4x4 model; + float gradientPos; +}; +ConstantBuffer ubo; + +Sampler2D samplerGradientRamp; + +[shader("vertex")] +VSOutput vertexMain(VSInput input) +{ + VSOutput output; + output.Normal = input.Normal; + output.Color = input.Color; + output.UV = float2(ubo.gradientPos, 0.0); + output.Pos = mul(ubo.projection, mul(ubo.model, input.Pos)); + output.EyePos = mul(ubo.model, input.Pos).xyz; + float4 lightPos = float4(0.0, 0.0, -5.0, 1.0); // * ubo.model; + output.LightVec = normalize(lightPos.xyz - input.Pos.xyz); + return output; +} + +[shader("fragment")] +float4 fragmentMain(VSOutput input) +{ + // No light calculations for glow color + // Use max. color channel value + // to detect bright glow emitters + if ((input.Color.r >= 0.9) || (input.Color.g >= 0.9) || (input.Color.b >= 0.9)) + { + return float4(samplerGradientRamp.Sample(input.UV).rgb, 1); + } else { + float3 Eye = normalize(-input.EyePos); + float3 Reflected = normalize(reflect(-input.LightVec, input.Normal)); + float4 IAmbient = float4(0.2, 0.2, 0.2, 1.0); + float4 IDiffuse = float4(0.5, 0.5, 0.5, 0.5) * max(dot(input.Normal, input.LightVec), 0.0); + float specular = 0.25; + float4 ISpecular = float4(0.5, 0.5, 0.5, 1.0) * pow(max(dot(Reflected, Eye), 0.0), 4.0) * specular; + return float4((IAmbient + IDiffuse) * float4(input.Color, 1.0) + ISpecular); + } +} \ No newline at end of file diff --git a/shaders/slang/radialblur/radialblur.slang b/shaders/slang/radialblur/radialblur.slang new file mode 100644 index 00000000..8fefdf16 --- /dev/null +++ b/shaders/slang/radialblur/radialblur.slang @@ -0,0 +1,48 @@ +/* Copyright (c) 2025, Sascha Willems + * + * SPDX-License-Identifier: MIT + * + */ + +struct VSOutput +{ + float4 Pos : SV_POSITION; + float2 UV; +}; + +struct UBO +{ + float radialBlurScale; + float radialBlurStrength; + float2 radialOrigin; +}; +ConstantBuffer ubo; + +Sampler2D samplerColor; + +[shader("vertex")] +VSOutput vertexMain(uint VertexIndex: SV_VertexID) +{ + VSOutput output; + output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2); + output.Pos = float4(output.UV * 2.0f - 1.0f, 0.0f, 1.0f); + return output; +} + +[shader("fragment")] +float4 fragmentMain(VSOutput input) +{ + int2 texDim; + samplerColor.GetDimensions(texDim.x, texDim.y); + float2 radialSize = float2(1.0 / texDim.x, 1.0 / texDim.y); + float2 UV = input.UV; + float4 color = float4(0.0, 0.0, 0.0, 0.0); + UV += radialSize * 0.5 - ubo.radialOrigin; + #define samples 32 + for (int i = 0; i < samples; i++) + { + float scale = 1.0 - ubo.radialBlurScale * (float(i) / float(samples - 1)); + color += samplerColor.Sample(UV * scale + ubo.radialOrigin); + } + return (color / samples) * ubo.radialBlurStrength; +} \ No newline at end of file