Added slang shaders for additional compute samples

This commit is contained in:
Sascha Willems 2025-05-19 19:51:43 +02:00
parent 80ff4a41d2
commit 829118736f
8 changed files with 460 additions and 2 deletions

View file

@ -391,8 +391,8 @@ public:
vks::initializers::vertexInputAttributeDescription(0, 2, VK_FORMAT_R32G32B32_SFLOAT, offsetof(vkglTF::Vertex, color)), // Location 2: Texture coordinates vks::initializers::vertexInputAttributeDescription(0, 2, VK_FORMAT_R32G32B32_SFLOAT, offsetof(vkglTF::Vertex, color)), // Location 2: Texture coordinates
// Per-Instance attributes // Per-Instance attributes
// These are fetched for each instance rendered // These are fetched for each instance rendered
vks::initializers::vertexInputAttributeDescription(1, 4, VK_FORMAT_R32G32B32_SFLOAT, offsetof(InstanceData, pos)), // Location 4: Position vks::initializers::vertexInputAttributeDescription(1, 3, VK_FORMAT_R32G32B32_SFLOAT, offsetof(InstanceData, pos)), // Location 4: Position
vks::initializers::vertexInputAttributeDescription(1, 5, VK_FORMAT_R32_SFLOAT, offsetof(InstanceData, scale)), // Location 5: Scale vks::initializers::vertexInputAttributeDescription(1, 4, VK_FORMAT_R32_SFLOAT, offsetof(InstanceData, scale)), // Location 5: Scale
}; };
inputState.pVertexBindingDescriptions = bindingDescriptions.data(); inputState.pVertexBindingDescriptions = bindingDescriptions.data();
inputState.pVertexAttributeDescriptions = attributeDescriptions.data(); inputState.pVertexAttributeDescriptions = attributeDescriptions.data();

View file

@ -0,0 +1,258 @@
/* Copyright (c) 2025, Sascha Willems
*
* SPDX-License-Identifier: MIT
*
*/
// Shader is looseley based on the ray tracing coding session by Inigo Quilez (www.iquilezles.org)
#define EPSILON 0.0001
#define MAXLEN 1000.0
#define SHADOW 0.5
#define RAYBOUNCES 2
#define REFLECTIONS true
#define REFLECTIONSTRENGTH 0.4
#define REFLECTIONFALLOFF 0.5
#define SceneObjectTypeSphere 0
#define SceneObjectTypePlane 1
RWTexture2D<float4> resultImage;
struct Camera
{
float3 pos;
float3 lookat;
float fov;
};
struct UBO
{
float3 lightPos;
float aspectRatio;
float4 fogColor;
Camera camera;
float4x4 rotMat;
};
ConstantBuffer<UBO> ubo;
struct SceneObject
{
float4 objectProperties;
float3 diffuse;
float specular;
int id;
int objectType;
};
StructuredBuffer<SceneObject> sceneObjects;
void reflectRay(inout float3 rayD, in float3 mormal)
{
rayD = rayD + 2.0 * -dot(mormal, rayD) * mormal;
}
// Lighting =========================================================
float lightDiffuse(float3 normal, float3 lightDir)
{
return clamp(dot(normal, lightDir), 0.1, 1.0);
}
float lightSpecular(float3 normal, float3 lightDir, float specularFactor)
{
float3 viewVec = normalize(ubo.camera.pos);
float3 halfVec = normalize(lightDir + viewVec);
return pow(clamp(dot(normal, halfVec), 0.0, 1.0), specularFactor);
}
// Sphere ===========================================================
float sphereIntersect(in float3 rayO, in float3 rayD, in SceneObject sphere)
{
float3 oc = rayO - sphere.objectProperties.xyz;
float b = 2.0 * dot(oc, rayD);
float c = dot(oc, oc) - sphere.objectProperties.w * sphere.objectProperties.w;
float h = b*b - 4.0*c;
if (h < 0.0)
{
return -1.0;
}
float t = (-b - sqrt(h)) / 2.0;
return t;
}
float3 sphereNormal(in float3 pos, in SceneObject sphere)
{
return (pos - sphere.objectProperties.xyz) / sphere.objectProperties.w;
}
// Plane ===========================================================
float planeIntersect(float3 rayO, float3 rayD, SceneObject plane)
{
float d = dot(rayD, plane.objectProperties.xyz);
if (d == 0.0)
return 0.0;
float t = -(plane.objectProperties.w + dot(rayO, plane.objectProperties.xyz)) / d;
if (t < 0.0)
return 0.0;
return t;
}
int intersect(in float3 rayO, in float3 rayD, inout float resT)
{
int id = -1;
float t = MAXLEN;
uint sceneObjectsLength;
uint sceneObjectsStride;
sceneObjects.GetDimensions(sceneObjectsLength, sceneObjectsStride);
for (int i = 0; i < sceneObjectsLength; i++) {
// Sphere
if (sceneObjects[i].objectType == SceneObjectTypeSphere) {
t = sphereIntersect(rayO, rayD, sceneObjects[i]);
}
// Plane
if (sceneObjects[i].objectType == SceneObjectTypePlane) {
t = planeIntersect(rayO, rayD, sceneObjects[i]);
}
if ((t > EPSILON) && (t < resT))
{
id = sceneObjects[i].id;
resT = t;
}
}
return id;
}
float calcShadow(in float3 rayO, in float3 rayD, in int objectId, inout float t)
{
uint sceneObjectsLength;
uint sceneObjectsStride;
sceneObjects.GetDimensions(sceneObjectsLength, sceneObjectsStride);
for (int i = 0; i < sceneObjectsLength; i++) {
if (sceneObjects[i].id == objectId)
continue;
float tLoc = MAXLEN;
// Sphere
if (sceneObjects[i].objectType == SceneObjectTypeSphere)
{
tLoc = sphereIntersect(rayO, rayD, sceneObjects[i]);
}
// Plane
if (sceneObjects[i].objectType == SceneObjectTypePlane)
{
tLoc = planeIntersect(rayO, rayD, sceneObjects[i]);
}
if ((tLoc > EPSILON) && (tLoc < t))
{
t = tLoc;
return SHADOW;
}
}
return 1.0;
}
float3 fog(in float t, in float3 color)
{
return lerp(color, ubo.fogColor.rgb, clamp(sqrt(t*t)/20.0, 0.0, 1.0));
}
float3 renderScene(inout float3 rayO, inout float3 rayD, inout int id)
{
float3 color = float3(0, 0, 0);
float t = MAXLEN;
// Get intersected object ID
int objectID = intersect(rayO, rayD, t);
if (objectID == -1)
{
return color;
}
float3 pos = rayO + t * rayD;
float3 lightVec = normalize(ubo.lightPos - pos);
float3 normal;
uint sceneObjectsLength;
uint sceneObjectsStride;
sceneObjects.GetDimensions(sceneObjectsLength, sceneObjectsStride);
for (int i = 0; i < sceneObjectsLength; i++) {
if (objectID == sceneObjects[i].id)
{
// Sphere
if (sceneObjects[i].objectType == SceneObjectTypeSphere) {
normal = sphereNormal(pos, sceneObjects[i]);
}
// Plane
if (sceneObjects[i].objectType == SceneObjectTypePlane) {
normal = sceneObjects[i].objectProperties.xyz;
}
// Lighting
float diffuse = lightDiffuse(normal, lightVec);
float specular = lightSpecular(normal, lightVec, sceneObjects[i].specular);
color = diffuse * sceneObjects[i].diffuse + specular;
}
}
if (id == -1)
return color;
id = objectID;
// Shadows
t = length(ubo.lightPos - pos);
color *= calcShadow(pos, lightVec, id, t);
// Fog
color = fog(t, color);
// Reflect ray for next render pass
reflectRay(rayD, normal);
rayO = pos;
return color;
}
[shader("compute")]
[numthreads(16, 16, 1)]
void computeMain(uint3 GlobalInvocationID : SV_DispatchThreadID)
{
int2 dim;
resultImage.GetDimensions(dim.x, dim.y);
float2 uv = float2(GlobalInvocationID.xy) / dim;
float3 rayO = ubo.camera.pos;
float3 rayD = normalize(float3((-1.0 + 2.0 * uv) * float2(ubo.aspectRatio, 1.0), -1.0));
// Basic color path
int id = 0;
float3 finalColor = renderScene(rayO, rayD, id);
// Reflection
if (REFLECTIONS)
{
float reflectionStrength = REFLECTIONSTRENGTH;
for (int i = 0; i < RAYBOUNCES; i++)
{
float3 reflectionColor = renderScene(rayO, rayD, id);
finalColor = (1.0 - reflectionStrength) * finalColor + reflectionStrength * lerp(reflectionColor, finalColor, 1.0 - reflectionStrength);
reflectionStrength *= REFLECTIONFALLOFF;
}
}
resultImage[int2(GlobalInvocationID.xy)] = float4(finalColor, 0.0);
}

View file

@ -0,0 +1,28 @@
/* Copyright (c) 2025, Sascha Willems
*
* SPDX-License-Identifier: MIT
*
*/
struct VSOutput
{
float4 Pos : SV_POSITION;
float2 UV;
};
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)
{
return samplerColor.Sample(float2(input.UV.x, 1.0 - input.UV.y));
}

View file

@ -0,0 +1,34 @@
/* Copyright (c) 2025, Sascha Willems
*
* SPDX-License-Identifier: MIT
*
*/
import shared;
[shader("compute")]
[numthreads(16, 16, 1)]
void computeMain(uint3 GlobalInvocationID : SV_DispatchThreadID)
{
float imageData[9];
// Fetch neighbouring texels
int n = -1;
for (int i=-1; i<2; ++i)
{
for(int j=-1; j<2; ++j)
{
n++;
float3 rgb = inputImage[uint2(GlobalInvocationID.x + i, GlobalInvocationID.y + j)].rgb;
imageData[n] = (rgb.r + rgb.g + rgb.b) / 3.0;
}
}
float kernel[9];
kernel[0] = -1.0/8.0; kernel[1] = -1.0/8.0; kernel[2] = -1.0/8.0;
kernel[3] = -1.0/8.0; kernel[4] = 1.0; kernel[5] = -1.0/8.0;
kernel[6] = -1.0/8.0; kernel[7] = -1.0/8.0; kernel[8] = -1.0/8.0;
float4 res = float4(conv(kernel, imageData, 0.1, 0.0).xxx, 1.0);
resultImage[int2(GlobalInvocationID.xy)] = res;
}

View file

@ -0,0 +1,34 @@
/* Copyright (c) 2025, Sascha Willems
*
* SPDX-License-Identifier: MIT
*
*/
import shared;
[shader("compute")]
[numthreads(16, 16, 1)]
void computeMain(uint3 GlobalInvocationID : SV_DispatchThreadID)
{
float imageData[9];
// Fetch neighbouring texels
int n = -1;
for (int i=-1; i<2; ++i)
{
for(int j=-1; j<2; ++j)
{
n++;
float3 rgb = inputImage[uint2(GlobalInvocationID.x + i, GlobalInvocationID.y + j)].rgb;
imageData[n] = (rgb.r + rgb.g + rgb.b) / 3.0;
}
}
float kernel[9];
kernel[0] = -1.0; kernel[1] = 0.0; kernel[2] = 0.0;
kernel[3] = 0.0; kernel[4] = -1.0; kernel[5] = 0.0;
kernel[6] = 0.0; kernel[7] = 0.0; kernel[8] = 2.0;
float4 res = float4(conv(kernel, imageData, 1.0, 0.50).xxx, 1.0);
resultImage[int2(GlobalInvocationID.xy)] = res;
}

View file

@ -0,0 +1,20 @@
/* Copyright (c) 2025, Sascha Willems
*
* SPDX-License-Identifier: MIT
*
*/
module shared;
public Texture2D inputImage;
public RWTexture2D<float4> resultImage;
public float conv(in float kernel[9], in float data[9], in float denom, in float offset)
{
float res = 0.0;
for (int i=0; i<9; ++i)
{
res += kernel[i] * data[i];
}
return saturate(res/denom + offset);
}

View file

@ -0,0 +1,43 @@
/* Copyright (c) 2025, Sascha Willems
*
* SPDX-License-Identifier: MIT
*
*/
import shared;
[shader("compute")]
[numthreads(16, 16, 1)]
void computeMain(uint3 GlobalInvocationID : SV_DispatchThreadID)
{
float r[9];
float g[9];
float b[9];
// Fetch neighbouring texels
int n = -1;
for (int i=-1; i<2; ++i)
{
for(int j=-1; j<2; ++j)
{
n++;
float3 rgb = inputImage[uint2(GlobalInvocationID.x + i, GlobalInvocationID.y + j)].rgb;
r[n] = rgb.r;
g[n] = rgb.g;
b[n] = rgb.b;
}
}
float kernel[9];
kernel[0] = -1.0; kernel[1] = -1.0; kernel[2] = -1.0;
kernel[3] = -1.0; kernel[4] = 9.0; kernel[5] = -1.0;
kernel[6] = -1.0; kernel[7] = -1.0; kernel[8] = -1.0;
float4 res = float4(
conv(kernel, r, 1.0, 0.0),
conv(kernel, g, 1.0, 0.0),
conv(kernel, b, 1.0, 0.0),
1.0);
resultImage[int2(GlobalInvocationID.xy)] = res;
}

View file

@ -0,0 +1,41 @@
/* Copyright (c) 2025, Sascha Willems
*
* SPDX-License-Identifier: MIT
*
*/
struct VSInput
{
float3 Pos;
float2 UV;
};
struct VSOutput
{
float4 Pos : SV_POSITION;
float2 UV;
};
struct UBO
{
float4x4 projection;
float4x4 model;
};
ConstantBuffer<UBO> ubo;
Sampler2D samplerColor;
[shader("vertex")]
VSOutput vertexMain(VSInput input)
{
VSOutput output;
output.UV = input.UV;
output.Pos = mul(ubo.projection, mul(ubo.model, float4(input.Pos.xyz, 1.0)));
return output;
}
[shader("fragment")]
float4 fragmentMain(VSOutput input)
{
return samplerColor.Sample(input.UV);
}