Skip to content

Commit b102f0b

Browse files
committed
Added shaders for order independent transparency sample
1 parent 8ca1234 commit b102f0b

2 files changed

Lines changed: 150 additions & 0 deletions

File tree

shaders/slang/oit/color.slang

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/* Copyright (c) 2025, Sascha Willems
2+
*
3+
* SPDX-License-Identifier: MIT
4+
*
5+
*/
6+
7+
#define MAX_FRAGMENT_COUNT 128
8+
9+
struct VSOutput
10+
{
11+
float4 Pos : SV_POSITION;
12+
};
13+
14+
struct Node
15+
{
16+
float4 color;
17+
float depth;
18+
uint next;
19+
};
20+
RWTexture2D<uint> headIndexImage;
21+
22+
struct Particle
23+
{
24+
float2 pos;
25+
float2 vel;
26+
float4 gradientPos;
27+
};
28+
RWStructuredBuffer<Node> nodes;
29+
30+
[shader("vertex")]
31+
VSOutput vertexMain(uint VertexIndex: SV_VertexID)
32+
{
33+
VSOutput output;
34+
float2 UV = float2((VertexIndex << 1) & 2, VertexIndex & 2);
35+
output.Pos = float4(UV * 2.0f - 1.0f, 0.0f, 1.0f);
36+
return output;
37+
}
38+
39+
[shader("fragment")]
40+
float4 fragmentMain(VSOutput input)
41+
{
42+
Node fragments[MAX_FRAGMENT_COUNT];
43+
int count = 0;
44+
45+
uint nodeIdx = headIndexImage[uint2(input.Pos.xy)].r;
46+
47+
while (nodeIdx != 0xffffffff && count < MAX_FRAGMENT_COUNT)
48+
{
49+
fragments[count] = nodes[nodeIdx];
50+
nodeIdx = fragments[count].next;
51+
++count;
52+
}
53+
54+
// Do the insertion sort
55+
for (uint i = 1; i < count; ++i)
56+
{
57+
Node insert = fragments[i];
58+
uint j = i;
59+
while (j > 0 && insert.depth > fragments[j - 1].depth)
60+
{
61+
fragments[j] = fragments[j-1];
62+
--j;
63+
}
64+
fragments[j] = insert;
65+
}
66+
67+
// Do blending
68+
float4 color = float4(0.025, 0.025, 0.025, 1.0f);
69+
for (uint f = 0; f < count; ++f)
70+
{
71+
color = lerp(color, fragments[f].color, fragments[f].color.a);
72+
}
73+
74+
return color;
75+
}

shaders/slang/oit/geometry.slang

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/* Copyright (c) 2025, Sascha Willems
2+
*
3+
* SPDX-License-Identifier: MIT
4+
*
5+
*/
6+
7+
struct VSInput
8+
{
9+
float4 Pos : POSITION0;
10+
};
11+
12+
struct VSOutput
13+
{
14+
float4 Pos : SV_POSITION;
15+
};
16+
17+
struct RenderPassUBO
18+
{
19+
float4x4 projection;
20+
float4x4 view;
21+
};
22+
ConstantBuffer<RenderPassUBO> renderPassUBO;
23+
24+
struct GeometrySBO
25+
{
26+
uint count;
27+
uint maxNodeCount;
28+
};
29+
// Binding 0 : Position storage buffer
30+
RWStructuredBuffer<GeometrySBO> geometrySBO;
31+
32+
struct Node
33+
{
34+
float4 color;
35+
float depth;
36+
uint next;
37+
};
38+
RWTexture2D<uint> headIndexImage;
39+
40+
RWStructuredBuffer<Node> nodes;
41+
42+
struct PushConsts {
43+
float4x4 model;
44+
float4 color;
45+
};
46+
47+
[shader("vertex")]
48+
VSOutput vertexMain(VSInput input, uniform PushConsts pushConsts)
49+
{
50+
VSOutput output;
51+
output.Pos = mul(renderPassUBO.projection, mul(renderPassUBO.view, mul(pushConsts.model, input.Pos)));
52+
return output;
53+
}
54+
55+
[shader("fragment")]
56+
[earlydepthstencil]
57+
void fragmentMain(VSOutput input, uniform PushConsts pushConsts)
58+
{
59+
// Increase the node count
60+
uint nodeIdx;
61+
InterlockedAdd(geometrySBO[0].count, 1, nodeIdx);
62+
63+
// Check LinkedListSBO is full
64+
if (nodeIdx < geometrySBO[0].maxNodeCount)
65+
{
66+
// Exchange new head index and previous head index
67+
uint prevHeadIdx;
68+
InterlockedExchange(headIndexImage[uint2(input.Pos.xy)], nodeIdx, prevHeadIdx);
69+
70+
// Store node data
71+
nodes[nodeIdx].color = pushConsts.color;
72+
nodes[nodeIdx].depth = input.Pos.z;
73+
nodes[nodeIdx].next = prevHeadIdx;
74+
}
75+
}

0 commit comments

Comments
 (0)