1617a3babSopenharmony_ci/*
2617a3babSopenharmony_ciThe MIT License (MIT)
3617a3babSopenharmony_ci
4617a3babSopenharmony_ciCopyright (c) 2022 Google LLC
5617a3babSopenharmony_ciCopyright (c) 2022 Sascha Willems
6617a3babSopenharmony_ci
7617a3babSopenharmony_ciPermission is hereby granted, free of charge, to any person obtaining a copy
8617a3babSopenharmony_ciof this software and associated documentation files (the "Software"), to deal
9617a3babSopenharmony_ciin the Software without restriction, including without limitation the rights
10617a3babSopenharmony_cito use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11617a3babSopenharmony_cicopies of the Software, and to permit persons to whom the Software is
12617a3babSopenharmony_cifurnished to do so, subject to the following conditions:
13617a3babSopenharmony_ci
14617a3babSopenharmony_ciThe above copyright notice and this permission notice shall be included in all
15617a3babSopenharmony_cicopies or substantial portions of the Software.
16617a3babSopenharmony_ci
17617a3babSopenharmony_ciTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18617a3babSopenharmony_ciIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19617a3babSopenharmony_ciFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20617a3babSopenharmony_ciAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21617a3babSopenharmony_ciLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22617a3babSopenharmony_ciOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23617a3babSopenharmony_ciSOFTWARE.
24617a3babSopenharmony_ci*/
25617a3babSopenharmony_ci
26617a3babSopenharmony_ciTexture2D textureposition : register(t1);
27617a3babSopenharmony_ciSamplerState samplerposition : register(s1);
28617a3babSopenharmony_ciTexture2D textureNormal : register(t2);
29617a3babSopenharmony_ciSamplerState samplerNormal : register(s2);
30617a3babSopenharmony_ciTexture2D textureAlbedo : register(t3);
31617a3babSopenharmony_ciSamplerState samplerAlbedo : register(s3);
32617a3babSopenharmony_ci// Depth from the light's point of view
33617a3babSopenharmony_ci//layout (binding = 5) uniform sampler2DShadow samplerShadowMap;
34617a3babSopenharmony_ciTexture2DArray textureShadowMap : register(t5);
35617a3babSopenharmony_ciSamplerState samplerShadowMap : register(s5);
36617a3babSopenharmony_ci
37617a3babSopenharmony_ci#define LIGHT_COUNT 3
38617a3babSopenharmony_ci#define SHADOW_FACTOR 0.25
39617a3babSopenharmony_ci#define AMBIENT_LIGHT 0.1
40617a3babSopenharmony_ci#define USE_PCF
41617a3babSopenharmony_ci
42617a3babSopenharmony_cistruct Light
43617a3babSopenharmony_ci{
44617a3babSopenharmony_ci	float4 position;
45617a3babSopenharmony_ci	float4 target;
46617a3babSopenharmony_ci	float4 color;
47617a3babSopenharmony_ci	float4x4 viewMatrix;
48617a3babSopenharmony_ci};
49617a3babSopenharmony_ci
50617a3babSopenharmony_cistruct UBO
51617a3babSopenharmony_ci{
52617a3babSopenharmony_ci	float4 viewPos;
53617a3babSopenharmony_ci	Light lights[LIGHT_COUNT];
54617a3babSopenharmony_ci	int useShadows;
55617a3babSopenharmony_ci	int displayDebugTarget;
56617a3babSopenharmony_ci};
57617a3babSopenharmony_ci
58617a3babSopenharmony_cicbuffer ubo : register(b4) { UBO ubo; }
59617a3babSopenharmony_ci
60617a3babSopenharmony_cifloat textureProj(float4 P, float layer, float2 offset)
61617a3babSopenharmony_ci{
62617a3babSopenharmony_ci	float shadow = 1.0;
63617a3babSopenharmony_ci	float4 shadowCoord = P / P.w;
64617a3babSopenharmony_ci	shadowCoord.xy = shadowCoord.xy * 0.5 + 0.5;
65617a3babSopenharmony_ci
66617a3babSopenharmony_ci	if (shadowCoord.z > -1.0 && shadowCoord.z < 1.0)
67617a3babSopenharmony_ci	{
68617a3babSopenharmony_ci		float dist = textureShadowMap.Sample(samplerShadowMap, float3(shadowCoord.xy + offset, layer)).r;
69617a3babSopenharmony_ci		if (shadowCoord.w > 0.0 && dist < shadowCoord.z)
70617a3babSopenharmony_ci		{
71617a3babSopenharmony_ci			shadow = SHADOW_FACTOR;
72617a3babSopenharmony_ci		}
73617a3babSopenharmony_ci	}
74617a3babSopenharmony_ci	return shadow;
75617a3babSopenharmony_ci}
76617a3babSopenharmony_ci
77617a3babSopenharmony_cifloat filterPCF(float4 sc, float layer)
78617a3babSopenharmony_ci{
79617a3babSopenharmony_ci	int2 texDim; int elements; int levels;
80617a3babSopenharmony_ci	textureShadowMap.GetDimensions(0, texDim.x, texDim.y, elements, levels);
81617a3babSopenharmony_ci	float scale = 1.5;
82617a3babSopenharmony_ci	float dx = scale * 1.0 / float(texDim.x);
83617a3babSopenharmony_ci	float dy = scale * 1.0 / float(texDim.y);
84617a3babSopenharmony_ci
85617a3babSopenharmony_ci	float shadowFactor = 0.0;
86617a3babSopenharmony_ci	int count = 0;
87617a3babSopenharmony_ci	int range = 1;
88617a3babSopenharmony_ci
89617a3babSopenharmony_ci	for (int x = -range; x <= range; x++)
90617a3babSopenharmony_ci	{
91617a3babSopenharmony_ci		for (int y = -range; y <= range; y++)
92617a3babSopenharmony_ci		{
93617a3babSopenharmony_ci			shadowFactor += textureProj(sc, layer, float2(dx*x, dy*y));
94617a3babSopenharmony_ci			count++;
95617a3babSopenharmony_ci		}
96617a3babSopenharmony_ci
97617a3babSopenharmony_ci	}
98617a3babSopenharmony_ci	return shadowFactor / count;
99617a3babSopenharmony_ci}
100617a3babSopenharmony_ci
101617a3babSopenharmony_cifloat3 shadow(float3 fragcolor, float3 fragPos) {
102617a3babSopenharmony_ci	for (int i = 0; i < LIGHT_COUNT; ++i)
103617a3babSopenharmony_ci	{
104617a3babSopenharmony_ci		float4 shadowClip = mul(ubo.lights[i].viewMatrix, float4(fragPos.xyz, 1.0));
105617a3babSopenharmony_ci
106617a3babSopenharmony_ci		float shadowFactor;
107617a3babSopenharmony_ci		#ifdef USE_PCF
108617a3babSopenharmony_ci			shadowFactor= filterPCF(shadowClip, i);
109617a3babSopenharmony_ci		#else
110617a3babSopenharmony_ci			shadowFactor = textureProj(shadowClip, i, float2(0.0, 0.0));
111617a3babSopenharmony_ci		#endif
112617a3babSopenharmony_ci
113617a3babSopenharmony_ci		fragcolor *= shadowFactor;
114617a3babSopenharmony_ci	}
115617a3babSopenharmony_ci	return fragcolor;
116617a3babSopenharmony_ci}
117617a3babSopenharmony_ci
118617a3babSopenharmony_cifloat4 main([[vk::location(0)]] float2 inUV : TEXCOORD0) : SV_TARGET
119617a3babSopenharmony_ci{
120617a3babSopenharmony_ci	// Get G-Buffer values
121617a3babSopenharmony_ci	float3 fragPos = textureposition.Sample(samplerposition, inUV).rgb;
122617a3babSopenharmony_ci	float3 normal = textureNormal.Sample(samplerNormal, inUV).rgb;
123617a3babSopenharmony_ci	float4 albedo = textureAlbedo.Sample(samplerAlbedo, inUV);
124617a3babSopenharmony_ci
125617a3babSopenharmony_ci	float3 fragcolor;
126617a3babSopenharmony_ci
127617a3babSopenharmony_ci	// Debug display
128617a3babSopenharmony_ci	if (ubo.displayDebugTarget > 0) {
129617a3babSopenharmony_ci		switch (ubo.displayDebugTarget) {
130617a3babSopenharmony_ci			case 1: 
131617a3babSopenharmony_ci				fragcolor.rgb = shadow(float3(1.0, 1.0, 1.0), fragPos);
132617a3babSopenharmony_ci				break;
133617a3babSopenharmony_ci			case 2: 
134617a3babSopenharmony_ci				fragcolor.rgb = fragPos;
135617a3babSopenharmony_ci				break;
136617a3babSopenharmony_ci			case 3: 
137617a3babSopenharmony_ci				fragcolor.rgb = normal;
138617a3babSopenharmony_ci				break;
139617a3babSopenharmony_ci			case 4: 
140617a3babSopenharmony_ci				fragcolor.rgb = albedo.rgb;
141617a3babSopenharmony_ci				break;
142617a3babSopenharmony_ci			case 5: 
143617a3babSopenharmony_ci				fragcolor.rgb = albedo.aaa;
144617a3babSopenharmony_ci				break;
145617a3babSopenharmony_ci		}		
146617a3babSopenharmony_ci		return float4(fragcolor, 1.0);
147617a3babSopenharmony_ci	}
148617a3babSopenharmony_ci
149617a3babSopenharmony_ci	// Ambient part
150617a3babSopenharmony_ci	fragcolor  = albedo.rgb * AMBIENT_LIGHT;
151617a3babSopenharmony_ci
152617a3babSopenharmony_ci	float3 N = normalize(normal);
153617a3babSopenharmony_ci
154617a3babSopenharmony_ci	for(int i = 0; i < LIGHT_COUNT; ++i)
155617a3babSopenharmony_ci	{
156617a3babSopenharmony_ci		// Vector to light
157617a3babSopenharmony_ci		float3 L = ubo.lights[i].position.xyz - fragPos;
158617a3babSopenharmony_ci		// Distance from light to fragment position
159617a3babSopenharmony_ci		float dist = length(L);
160617a3babSopenharmony_ci		L = normalize(L);
161617a3babSopenharmony_ci
162617a3babSopenharmony_ci		// Viewer to fragment
163617a3babSopenharmony_ci		float3 V = ubo.viewPos.xyz - fragPos;
164617a3babSopenharmony_ci		V = normalize(V);
165617a3babSopenharmony_ci
166617a3babSopenharmony_ci		float lightCosInnerAngle = cos(radians(15.0));
167617a3babSopenharmony_ci		float lightCosOuterAngle = cos(radians(25.0));
168617a3babSopenharmony_ci		float lightRange = 100.0;
169617a3babSopenharmony_ci
170617a3babSopenharmony_ci		// Direction vector from source to target
171617a3babSopenharmony_ci		float3 dir = normalize(ubo.lights[i].position.xyz - ubo.lights[i].target.xyz);
172617a3babSopenharmony_ci
173617a3babSopenharmony_ci		// Dual cone spot light with smooth transition between inner and outer angle
174617a3babSopenharmony_ci		float cosDir = dot(L, dir);
175617a3babSopenharmony_ci		float spotEffect = smoothstep(lightCosOuterAngle, lightCosInnerAngle, cosDir);
176617a3babSopenharmony_ci		float heightAttenuation = smoothstep(lightRange, 0.0f, dist);
177617a3babSopenharmony_ci
178617a3babSopenharmony_ci		// Diffuse lighting
179617a3babSopenharmony_ci		float NdotL = max(0.0, dot(N, L));
180617a3babSopenharmony_ci		float3 diff = NdotL.xxx;
181617a3babSopenharmony_ci
182617a3babSopenharmony_ci		// Specular lighting
183617a3babSopenharmony_ci		float3 R = reflect(-L, N);
184617a3babSopenharmony_ci		float NdotR = max(0.0, dot(R, V));
185617a3babSopenharmony_ci		float3 spec = (pow(NdotR, 16.0) * albedo.a * 2.5).xxx;
186617a3babSopenharmony_ci
187617a3babSopenharmony_ci		fragcolor += float3((diff + spec) * spotEffect * heightAttenuation) * ubo.lights[i].color.rgb * albedo.rgb;
188617a3babSopenharmony_ci	}
189617a3babSopenharmony_ci
190617a3babSopenharmony_ci	// Shadow calculations in a separate pass
191617a3babSopenharmony_ci	if (ubo.useShadows > 0)
192617a3babSopenharmony_ci	{
193617a3babSopenharmony_ci		fragcolor = shadow(fragcolor, fragPos);
194617a3babSopenharmony_ci	}
195617a3babSopenharmony_ci
196617a3babSopenharmony_ci	return float4(fragcolor, 1);
197617a3babSopenharmony_ci}
198