Skip to content

Commit 8291187

Browse files
committed
Added slang shaders for additional compute samples
1 parent 80ff4a4 commit 8291187

8 files changed

Lines changed: 460 additions & 2 deletions

File tree

examples/computecullandlod/computecullandlod.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,8 +391,8 @@ class VulkanExample : public VulkanExampleBase
391391
vks::initializers::vertexInputAttributeDescription(0, 2, VK_FORMAT_R32G32B32_SFLOAT, offsetof(vkglTF::Vertex, color)), // Location 2: Texture coordinates
392392
// Per-Instance attributes
393393
// These are fetched for each instance rendered
394-
vks::initializers::vertexInputAttributeDescription(1, 4, VK_FORMAT_R32G32B32_SFLOAT, offsetof(InstanceData, pos)), // Location 4: Position
395-
vks::initializers::vertexInputAttributeDescription(1, 5, VK_FORMAT_R32_SFLOAT, offsetof(InstanceData, scale)), // Location 5: Scale
394+
vks::initializers::vertexInputAttributeDescription(1, 3, VK_FORMAT_R32G32B32_SFLOAT, offsetof(InstanceData, pos)), // Location 4: Position
395+
vks::initializers::vertexInputAttributeDescription(1, 4, VK_FORMAT_R32_SFLOAT, offsetof(InstanceData, scale)), // Location 5: Scale
396396
};
397397
inputState.pVertexBindingDescriptions = bindingDescriptions.data();
398398
inputState.pVertexAttributeDescriptions = attributeDescriptions.data();
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
/* Copyright (c) 2025, Sascha Willems
2+
*
3+
* SPDX-License-Identifier: MIT
4+
*
5+
*/
6+
7+
// Shader is looseley based on the ray tracing coding session by Inigo Quilez (www.iquilezles.org)
8+
9+
#define EPSILON 0.0001
10+
#define MAXLEN 1000.0
11+
#define SHADOW 0.5
12+
#define RAYBOUNCES 2
13+
#define REFLECTIONS true
14+
#define REFLECTIONSTRENGTH 0.4
15+
#define REFLECTIONFALLOFF 0.5
16+
17+
#define SceneObjectTypeSphere 0
18+
#define SceneObjectTypePlane 1
19+
20+
RWTexture2D<float4> resultImage;
21+
22+
struct Camera
23+
{
24+
float3 pos;
25+
float3 lookat;
26+
float fov;
27+
};
28+
29+
struct UBO
30+
{
31+
float3 lightPos;
32+
float aspectRatio;
33+
float4 fogColor;
34+
Camera camera;
35+
float4x4 rotMat;
36+
};
37+
ConstantBuffer<UBO> ubo;
38+
39+
struct SceneObject
40+
{
41+
float4 objectProperties;
42+
float3 diffuse;
43+
float specular;
44+
int id;
45+
int objectType;
46+
};
47+
StructuredBuffer<SceneObject> sceneObjects;
48+
49+
void reflectRay(inout float3 rayD, in float3 mormal)
50+
{
51+
rayD = rayD + 2.0 * -dot(mormal, rayD) * mormal;
52+
}
53+
54+
// Lighting =========================================================
55+
56+
float lightDiffuse(float3 normal, float3 lightDir)
57+
{
58+
return clamp(dot(normal, lightDir), 0.1, 1.0);
59+
}
60+
61+
float lightSpecular(float3 normal, float3 lightDir, float specularFactor)
62+
{
63+
float3 viewVec = normalize(ubo.camera.pos);
64+
float3 halfVec = normalize(lightDir + viewVec);
65+
return pow(clamp(dot(normal, halfVec), 0.0, 1.0), specularFactor);
66+
}
67+
68+
// Sphere ===========================================================
69+
70+
float sphereIntersect(in float3 rayO, in float3 rayD, in SceneObject sphere)
71+
{
72+
float3 oc = rayO - sphere.objectProperties.xyz;
73+
float b = 2.0 * dot(oc, rayD);
74+
float c = dot(oc, oc) - sphere.objectProperties.w * sphere.objectProperties.w;
75+
float h = b*b - 4.0*c;
76+
if (h < 0.0)
77+
{
78+
return -1.0;
79+
}
80+
float t = (-b - sqrt(h)) / 2.0;
81+
82+
return t;
83+
}
84+
85+
float3 sphereNormal(in float3 pos, in SceneObject sphere)
86+
{
87+
return (pos - sphere.objectProperties.xyz) / sphere.objectProperties.w;
88+
}
89+
90+
// Plane ===========================================================
91+
92+
float planeIntersect(float3 rayO, float3 rayD, SceneObject plane)
93+
{
94+
float d = dot(rayD, plane.objectProperties.xyz);
95+
96+
if (d == 0.0)
97+
return 0.0;
98+
99+
float t = -(plane.objectProperties.w + dot(rayO, plane.objectProperties.xyz)) / d;
100+
101+
if (t < 0.0)
102+
return 0.0;
103+
104+
return t;
105+
}
106+
107+
108+
int intersect(in float3 rayO, in float3 rayD, inout float resT)
109+
{
110+
int id = -1;
111+
float t = MAXLEN;
112+
113+
uint sceneObjectsLength;
114+
uint sceneObjectsStride;
115+
sceneObjects.GetDimensions(sceneObjectsLength, sceneObjectsStride);
116+
117+
for (int i = 0; i < sceneObjectsLength; i++) {
118+
// Sphere
119+
if (sceneObjects[i].objectType == SceneObjectTypeSphere) {
120+
t = sphereIntersect(rayO, rayD, sceneObjects[i]);
121+
}
122+
// Plane
123+
if (sceneObjects[i].objectType == SceneObjectTypePlane) {
124+
t = planeIntersect(rayO, rayD, sceneObjects[i]);
125+
}
126+
if ((t > EPSILON) && (t < resT))
127+
{
128+
id = sceneObjects[i].id;
129+
resT = t;
130+
}
131+
}
132+
133+
return id;
134+
}
135+
136+
float calcShadow(in float3 rayO, in float3 rayD, in int objectId, inout float t)
137+
{
138+
uint sceneObjectsLength;
139+
uint sceneObjectsStride;
140+
sceneObjects.GetDimensions(sceneObjectsLength, sceneObjectsStride);
141+
142+
for (int i = 0; i < sceneObjectsLength; i++) {
143+
if (sceneObjects[i].id == objectId)
144+
continue;
145+
146+
float tLoc = MAXLEN;
147+
148+
// Sphere
149+
if (sceneObjects[i].objectType == SceneObjectTypeSphere)
150+
{
151+
tLoc = sphereIntersect(rayO, rayD, sceneObjects[i]);
152+
}
153+
// Plane
154+
if (sceneObjects[i].objectType == SceneObjectTypePlane)
155+
{
156+
tLoc = planeIntersect(rayO, rayD, sceneObjects[i]);
157+
}
158+
if ((tLoc > EPSILON) && (tLoc < t))
159+
{
160+
t = tLoc;
161+
return SHADOW;
162+
}
163+
}
164+
return 1.0;
165+
}
166+
167+
float3 fog(in float t, in float3 color)
168+
{
169+
return lerp(color, ubo.fogColor.rgb, clamp(sqrt(t*t)/20.0, 0.0, 1.0));
170+
}
171+
172+
float3 renderScene(inout float3 rayO, inout float3 rayD, inout int id)
173+
{
174+
float3 color = float3(0, 0, 0);
175+
float t = MAXLEN;
176+
177+
// Get intersected object ID
178+
int objectID = intersect(rayO, rayD, t);
179+
180+
if (objectID == -1)
181+
{
182+
return color;
183+
}
184+
185+
float3 pos = rayO + t * rayD;
186+
float3 lightVec = normalize(ubo.lightPos - pos);
187+
float3 normal;
188+
189+
uint sceneObjectsLength;
190+
uint sceneObjectsStride;
191+
sceneObjects.GetDimensions(sceneObjectsLength, sceneObjectsStride);
192+
193+
for (int i = 0; i < sceneObjectsLength; i++) {
194+
if (objectID == sceneObjects[i].id)
195+
{
196+
// Sphere
197+
if (sceneObjects[i].objectType == SceneObjectTypeSphere) {
198+
normal = sphereNormal(pos, sceneObjects[i]);
199+
}
200+
// Plane
201+
if (sceneObjects[i].objectType == SceneObjectTypePlane) {
202+
normal = sceneObjects[i].objectProperties.xyz;
203+
}
204+
// Lighting
205+
float diffuse = lightDiffuse(normal, lightVec);
206+
float specular = lightSpecular(normal, lightVec, sceneObjects[i].specular);
207+
color = diffuse * sceneObjects[i].diffuse + specular;
208+
}
209+
}
210+
211+
if (id == -1)
212+
return color;
213+
214+
id = objectID;
215+
216+
// Shadows
217+
t = length(ubo.lightPos - pos);
218+
color *= calcShadow(pos, lightVec, id, t);
219+
220+
// Fog
221+
color = fog(t, color);
222+
223+
// Reflect ray for next render pass
224+
reflectRay(rayD, normal);
225+
rayO = pos;
226+
227+
return color;
228+
}
229+
230+
[shader("compute")]
231+
[numthreads(16, 16, 1)]
232+
void computeMain(uint3 GlobalInvocationID : SV_DispatchThreadID)
233+
{
234+
int2 dim;
235+
resultImage.GetDimensions(dim.x, dim.y);
236+
float2 uv = float2(GlobalInvocationID.xy) / dim;
237+
238+
float3 rayO = ubo.camera.pos;
239+
float3 rayD = normalize(float3((-1.0 + 2.0 * uv) * float2(ubo.aspectRatio, 1.0), -1.0));
240+
241+
// Basic color path
242+
int id = 0;
243+
float3 finalColor = renderScene(rayO, rayD, id);
244+
245+
// Reflection
246+
if (REFLECTIONS)
247+
{
248+
float reflectionStrength = REFLECTIONSTRENGTH;
249+
for (int i = 0; i < RAYBOUNCES; i++)
250+
{
251+
float3 reflectionColor = renderScene(rayO, rayD, id);
252+
finalColor = (1.0 - reflectionStrength) * finalColor + reflectionStrength * lerp(reflectionColor, finalColor, 1.0 - reflectionStrength);
253+
reflectionStrength *= REFLECTIONFALLOFF;
254+
}
255+
}
256+
257+
resultImage[int2(GlobalInvocationID.xy)] = float4(finalColor, 0.0);
258+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* Copyright (c) 2025, Sascha Willems
2+
*
3+
* SPDX-License-Identifier: MIT
4+
*
5+
*/
6+
7+
struct VSOutput
8+
{
9+
float4 Pos : SV_POSITION;
10+
float2 UV;
11+
};
12+
13+
Sampler2D samplerColor;
14+
15+
[shader("vertex")]
16+
VSOutput vertexMain(uint VertexIndex: SV_VertexID)
17+
{
18+
VSOutput output;
19+
output.UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
20+
output.Pos = float4(output.UV * 2.0f + -1.0f, 0.0f, 1.0f);
21+
return output;
22+
}
23+
24+
[shader("fragment")]
25+
float4 fragmentMain(VSOutput input)
26+
{
27+
return samplerColor.Sample(float2(input.UV.x, 1.0 - input.UV.y));
28+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/* Copyright (c) 2025, Sascha Willems
2+
*
3+
* SPDX-License-Identifier: MIT
4+
*
5+
*/
6+
7+
import shared;
8+
9+
[shader("compute")]
10+
[numthreads(16, 16, 1)]
11+
void computeMain(uint3 GlobalInvocationID : SV_DispatchThreadID)
12+
{
13+
float imageData[9];
14+
// Fetch neighbouring texels
15+
int n = -1;
16+
for (int i=-1; i<2; ++i)
17+
{
18+
for(int j=-1; j<2; ++j)
19+
{
20+
n++;
21+
float3 rgb = inputImage[uint2(GlobalInvocationID.x + i, GlobalInvocationID.y + j)].rgb;
22+
imageData[n] = (rgb.r + rgb.g + rgb.b) / 3.0;
23+
}
24+
}
25+
26+
float kernel[9];
27+
kernel[0] = -1.0/8.0; kernel[1] = -1.0/8.0; kernel[2] = -1.0/8.0;
28+
kernel[3] = -1.0/8.0; kernel[4] = 1.0; kernel[5] = -1.0/8.0;
29+
kernel[6] = -1.0/8.0; kernel[7] = -1.0/8.0; kernel[8] = -1.0/8.0;
30+
31+
float4 res = float4(conv(kernel, imageData, 0.1, 0.0).xxx, 1.0);
32+
33+
resultImage[int2(GlobalInvocationID.xy)] = res;
34+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/* Copyright (c) 2025, Sascha Willems
2+
*
3+
* SPDX-License-Identifier: MIT
4+
*
5+
*/
6+
7+
import shared;
8+
9+
[shader("compute")]
10+
[numthreads(16, 16, 1)]
11+
void computeMain(uint3 GlobalInvocationID : SV_DispatchThreadID)
12+
{
13+
float imageData[9];
14+
// Fetch neighbouring texels
15+
int n = -1;
16+
for (int i=-1; i<2; ++i)
17+
{
18+
for(int j=-1; j<2; ++j)
19+
{
20+
n++;
21+
float3 rgb = inputImage[uint2(GlobalInvocationID.x + i, GlobalInvocationID.y + j)].rgb;
22+
imageData[n] = (rgb.r + rgb.g + rgb.b) / 3.0;
23+
}
24+
}
25+
26+
float kernel[9];
27+
kernel[0] = -1.0; kernel[1] = 0.0; kernel[2] = 0.0;
28+
kernel[3] = 0.0; kernel[4] = -1.0; kernel[5] = 0.0;
29+
kernel[6] = 0.0; kernel[7] = 0.0; kernel[8] = 2.0;
30+
31+
float4 res = float4(conv(kernel, imageData, 1.0, 0.50).xxx, 1.0);
32+
33+
resultImage[int2(GlobalInvocationID.xy)] = res;
34+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* Copyright (c) 2025, Sascha Willems
2+
*
3+
* SPDX-License-Identifier: MIT
4+
*
5+
*/
6+
7+
module shared;
8+
9+
public Texture2D inputImage;
10+
public RWTexture2D<float4> resultImage;
11+
12+
public float conv(in float kernel[9], in float data[9], in float denom, in float offset)
13+
{
14+
float res = 0.0;
15+
for (int i=0; i<9; ++i)
16+
{
17+
res += kernel[i] * data[i];
18+
}
19+
return saturate(res/denom + offset);
20+
}

0 commit comments

Comments
 (0)