static const char* glsl_rgen_ambient = R"glsl(

#version 460
#extension GL_EXT_ray_tracing : require

struct hitPayload
{
	vec3 hitPosition;
	float hitAttenuation;
	int hitSurfaceIndex;
};

layout(location = 0) rayPayloadEXT hitPayload payload;

layout(set = 0, binding = 0) uniform accelerationStructureEXT acc;
layout(set = 0, binding = 1, rgba32f) uniform image2D startpositions;
layout(set = 0, binding = 2, rgba32f) uniform image2D positions;
layout(set = 0, binding = 3, rgba32f) uniform image2D outputs;

layout(set = 0, binding = 4) uniform Uniforms
{
	uint SampleIndex;
	uint SampleCount;
	uint PassType;
	uint Padding0;
	vec3 SunDir;
	float Padding1;
	vec3 SunColor;
	float SunIntensity;
	vec3 HemisphereVec;
	float Padding2;
};

struct SurfaceInfo
{
	vec3 Normal;
	float EmissiveDistance;
	vec3 EmissiveColor;
	float EmissiveIntensity;
	float Sky;
	float SamplingDistance;
	float Padding1, Padding2;
};

layout(set = 0, binding = 6) buffer SurfaceBuffer { SurfaceInfo surfaces[]; };

layout(push_constant) uniform PushConstants
{
	uint LightStart;
	uint LightEnd;
	ivec2 pushPadding;
};

vec2 Hammersley(uint i, uint N);
float RadicalInverse_VdC(uint bits);

void main()
{
	ivec2 texelPos = ivec2(gl_LaunchIDEXT.xy);

	vec4 data0 = imageLoad(startpositions, texelPos);
	vec4 incoming = imageLoad(outputs, texelPos);

	if (PassType == 1)
		incoming.rgb = vec3(1.0); // For debugging

	vec3 origin = data0.xyz;
	int surfaceIndex = int(data0.w);

	if (surfaceIndex >= 0)
	{
		const float minDistance = 0.05;
		const float aoDistance = 100;

		vec3 N = surfaces[surfaceIndex].Normal;
		vec3 up = abs(N.x) < abs(N.y) ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0);
		vec3 tangent = normalize(cross(up, N));
		vec3 bitangent = cross(N, tangent);

		float ambience = 0.0f;
		for (uint i = 0; i < SampleCount; i++)
		{
			vec2 Xi = Hammersley(i, SampleCount);
			vec3 H = normalize(vec3(Xi.x * 2.0f - 1.0f, Xi.y * 2.0f - 1.0f, 1.5 - length(Xi)));
			vec3 L = H.x * tangent + H.y * bitangent + H.z * N;
			traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 3, 0, 3, origin, minDistance, L, 32768, 0);
			ambience += clamp(payload.hitAttenuation / aoDistance, 0.0, 1.0);
		}
		ambience /= float(SampleCount);

		incoming.rgb = incoming.rgb * ambience;
	}

	imageStore(outputs, texelPos, incoming);
}

vec2 Hammersley(uint i, uint N)
{
	return vec2(float(i) / float(N), RadicalInverse_VdC(i));
}

float RadicalInverse_VdC(uint bits)
{
	bits = (bits << 16u) | (bits >> 16u);
	bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
	bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
	bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
	bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
	return float(bits) * 2.3283064365386963e-10f; // / 0x100000000
}

)glsl";
