1+ // Copyright 2020 Google LLC
2+
3+ #define LIGHT_COUNT 3
4+ #define SHADOW_FACTOR 0 . 25
5+ #define AMBIENT_LIGHT 0 . 1
6+ #define USE_PCF
7+
8+ struct VSOutput
9+ {
10+ float4 Pos : SV_POSITION;
11+ float2 UV;
12+ };
13+
14+ [[vk::binding(1 , 0 )]] Sampler2D samplerPosition;
15+ [[vk::binding(2 , 0 )]] Sampler2D samplerNormal;
16+ [[vk::binding(3 , 0 )]] Sampler2D samplerAlbedo;
17+
18+ struct Light
19+ {
20+ float4 position;
21+ float4 target;
22+ float4 color;
23+ float4x4 viewMatrix;
24+ };
25+
26+ struct UBO
27+ {
28+ float4 viewPos;
29+ Light lights [LIGHT_COUNT];
30+ int useShadows;
31+ int displayDebugTarget;
32+ };
33+ [[vk::binding(4 , 0 )]] ConstantBuffer < UBO> ubo;
34+
35+ // Depth from the light's point of view
36+ // layout (binding = 5) uniform sampler2DShadow samplerShadowMap;
37+ [[vk::binding(5 , 0 )]] Sampler2DArray samplerShadowMap;
38+
39+ float textureProj(float4 P, float layer, float2 offset)
40+ {
41+ float shadow = 1 . 0 ;
42+ float4 shadowCoord = P / P .w ;
43+ shadowCoord .xy = shadowCoord .xy * 0 . 5 + 0 . 5 ;
44+
45+ if (shadowCoord .z > - 1 . 0 && shadowCoord .z < 1 . 0 )
46+ {
47+ float dist = samplerShadowMap .Sample (float3(shadowCoord .xy + offset, layer)).r ;
48+ if (shadowCoord .w > 0 . 0 && dist < shadowCoord .z )
49+ {
50+ shadow = SHADOW_FACTOR;
51+ }
52+ }
53+ return shadow;
54+ }
55+
56+ float filterPCF(float4 sc, float layer)
57+ {
58+ int2 texDim; int elements; int levels;
59+ samplerShadowMap .GetDimensions (0 , texDim .x , texDim .y , elements, levels);
60+ float scale = 1 . 5 ;
61+ float dx = scale * 1 . 0 / float (texDim .x );
62+ float dy = scale * 1 . 0 / float (texDim .y );
63+
64+ float shadowFactor = 0 . 0 ;
65+ int count = 0 ;
66+ int range = 1 ;
67+
68+ for (int x = - range; x <= range; x++ )
69+ {
70+ for (int y = - range; y <= range; y++ )
71+ {
72+ shadowFactor += textureProj(sc, layer, float2(dx* x, dy* y));
73+ count++ ;
74+ }
75+
76+ }
77+ return shadowFactor / count;
78+ }
79+
80+ float3 shadow(float3 fragcolor, float3 fragPos)
81+ {
82+ for (int i = 0 ; i < LIGHT_COUNT; ++ i)
83+ {
84+ float4 shadowClip = mul(ubo .lights [i].viewMatrix , float4(fragPos .xyz , 1 . 0 ));
85+
86+ float shadowFactor;
87+ #ifdef USE_PCF
88+ shadowFactor= filterPCF(shadowClip, i);
89+ #else
90+ shadowFactor = textureProj(shadowClip, i, float2(0 . 0 , 0 . 0 ));
91+ #endif
92+
93+ fragcolor *= shadowFactor;
94+ }
95+ return fragcolor;
96+ }
97+
98+ [shader(" vertex" )]
99+ VSOutput vertexMain(uint VertexIndex: SV_VertexID)
100+ {
101+ VSOutput output;
102+ output .UV = float2((VertexIndex << 1 ) & 2 , VertexIndex & 2 );
103+ output .Pos = float4(output .UV * 2 . 0 f - 1 . 0 f , 0 . 0 f , 1 . 0 f );
104+ return output;
105+ }
106+
107+ [shader(" fragment" )]
108+ float4 fragmentMain(VSOutput input)
109+ {
110+ // Get G-Buffer values
111+ float3 fragPos = samplerPosition .Sample (input .UV ).rgb ;
112+ float3 normal = samplerNormal .Sample (input .UV ).rgb ;
113+ float4 albedo = samplerAlbedo .Sample (input .UV );
114+
115+ float3 fragcolor;
116+
117+ // Debug display
118+ if (ubo .displayDebugTarget > 0 ) {
119+ switch (ubo .displayDebugTarget ) {
120+ case 1 :
121+ fragcolor .rgb = shadow(float3(1 . 0 , 1 . 0 , 1 . 0 ), fragPos);
122+ break ;
123+ case 2 :
124+ fragcolor .rgb = fragPos;
125+ break ;
126+ case 3 :
127+ fragcolor .rgb = normal;
128+ break ;
129+ case 4 :
130+ fragcolor .rgb = albedo .rgb ;
131+ break ;
132+ case 5 :
133+ fragcolor .rgb = albedo .aaa ;
134+ break ;
135+ }
136+ return float4(fragcolor, 1 . 0 );
137+ }
138+
139+ // Ambient part
140+ fragcolor = albedo .rgb * AMBIENT_LIGHT;
141+
142+ float3 N = normalize(normal);
143+
144+ for (int i = 0 ; i < LIGHT_COUNT; ++ i)
145+ {
146+ // Vector to light
147+ float3 L = ubo .lights [i].position .xyz - fragPos;
148+ // Distance from light to fragment position
149+ float dist = length(L);
150+ L = normalize(L);
151+
152+ // Viewer to fragment
153+ float3 V = ubo .viewPos .xyz - fragPos;
154+ V = normalize(V);
155+
156+ float lightCosInnerAngle = cos(radians(15 . 0 ));
157+ float lightCosOuterAngle = cos(radians(25 . 0 ));
158+ float lightRange = 100 . 0 ;
159+
160+ // Direction vector from source to target
161+ float3 dir = normalize(ubo .lights [i].position .xyz - ubo .lights [i].target .xyz );
162+
163+ // Dual cone spot light with smooth transition between inner and outer angle
164+ float cosDir = dot(L, dir);
165+ float spotEffect = smoothstep(lightCosOuterAngle, lightCosInnerAngle, cosDir);
166+ float heightAttenuation = smoothstep(lightRange, 0 . 0 f , dist);
167+
168+ // Diffuse lighting
169+ float NdotL = max(0 . 0 , dot(N, L));
170+ float3 diff = NdotL .xxx ;
171+
172+ // Specular lighting
173+ float3 R = reflect(- L, N);
174+ float NdotR = max(0 . 0 , dot(R, V));
175+ float3 spec = (pow(NdotR, 16 . 0 ) * albedo .a * 2 . 5 ).xxx ;
176+
177+ fragcolor += float3((diff + spec) * spotEffect * heightAttenuation) * ubo .lights [i].color .rgb * albedo .rgb ;
178+ }
179+
180+ // Shadow calculations in a separate pass
181+ if (ubo .useShadows > 0 )
182+ {
183+ fragcolor = shadow(fragcolor, fragPos);
184+ }
185+
186+ return float4(fragcolor, 1 );
187+ }
0 commit comments