mirror of
https://github.com/ZDoom/ZDRay.git
synced 2024-11-24 21:01:15 +00:00
Remove the old GPU raytracer
This commit is contained in:
parent
59c58b75f1
commit
8ed96484c2
16 changed files with 817 additions and 2683 deletions
|
@ -186,19 +186,6 @@ set( SOURCES
|
||||||
src/lightmap/surfaceclip.h
|
src/lightmap/surfaceclip.h
|
||||||
src/lightmap/gpuraytracer.cpp
|
src/lightmap/gpuraytracer.cpp
|
||||||
src/lightmap/gpuraytracer.h
|
src/lightmap/gpuraytracer.h
|
||||||
src/lightmap/gpuraytracer2.cpp
|
|
||||||
src/lightmap/gpuraytracer2.h
|
|
||||||
src/lightmap/glsl_rchit_bounce.h
|
|
||||||
src/lightmap/glsl_rchit_light.h
|
|
||||||
src/lightmap/glsl_rchit_sun.h
|
|
||||||
src/lightmap/glsl_rchit_ambient.h
|
|
||||||
src/lightmap/glsl_rgen_bounce.h
|
|
||||||
src/lightmap/glsl_rgen_light.h
|
|
||||||
src/lightmap/glsl_rgen_ambient.h
|
|
||||||
src/lightmap/glsl_rmiss_bounce.h
|
|
||||||
src/lightmap/glsl_rmiss_light.h
|
|
||||||
src/lightmap/glsl_rmiss_sun.h
|
|
||||||
src/lightmap/glsl_rmiss_ambient.h
|
|
||||||
src/lightmap/glsl_frag.h
|
src/lightmap/glsl_frag.h
|
||||||
src/lightmap/glsl_vert.h
|
src/lightmap/glsl_vert.h
|
||||||
src/lightmap/glsl_frag_resolve.h
|
src/lightmap/glsl_frag_resolve.h
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
static const char* glsl_rchit_ambient = R"glsl(
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
|
|
||||||
struct hitPayload
|
|
||||||
{
|
|
||||||
vec3 hitPosition;
|
|
||||||
float hitAttenuation;
|
|
||||||
int hitSurfaceIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SurfaceInfo
|
|
||||||
{
|
|
||||||
vec3 Normal;
|
|
||||||
float EmissiveDistance;
|
|
||||||
vec3 EmissiveColor;
|
|
||||||
float EmissiveIntensity;
|
|
||||||
float Sky;
|
|
||||||
float SamplingDistance;
|
|
||||||
float Padding1, Padding2;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(location = 0) rayPayloadInEXT hitPayload payload;
|
|
||||||
|
|
||||||
layout(set = 0, binding = 5) buffer SurfaceIndexBuffer { int surfaceIndices[]; };
|
|
||||||
layout(set = 0, binding = 6) buffer SurfaceBuffer { SurfaceInfo surfaces[]; };
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
SurfaceInfo surface = surfaces[surfaceIndices[gl_PrimitiveID]];
|
|
||||||
|
|
||||||
if(surface.Sky > 0.0)
|
|
||||||
{
|
|
||||||
payload.hitAttenuation = 100000.0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
payload.hitAttenuation = gl_HitTEXT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
)glsl";
|
|
|
@ -1,37 +0,0 @@
|
||||||
static const char* glsl_rchit_bounce = R"glsl(
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
|
|
||||||
struct hitPayload
|
|
||||||
{
|
|
||||||
vec3 hitPosition;
|
|
||||||
float hitAttenuation;
|
|
||||||
int hitSurfaceIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SurfaceInfo
|
|
||||||
{
|
|
||||||
vec3 Normal;
|
|
||||||
float EmissiveDistance;
|
|
||||||
vec3 EmissiveColor;
|
|
||||||
float EmissiveIntensity;
|
|
||||||
float Sky;
|
|
||||||
float SamplingDistance;
|
|
||||||
float Padding1, Padding2;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(location = 0) rayPayloadInEXT hitPayload payload;
|
|
||||||
|
|
||||||
layout(set = 0, binding = 5) buffer SurfaceIndexBuffer { int surfaceIndices[]; };
|
|
||||||
layout(set = 0, binding = 6) buffer SurfaceBuffer { SurfaceInfo surfaces[]; };
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
int surfaceIndex = surfaceIndices[gl_PrimitiveID];
|
|
||||||
payload.hitPosition = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT;
|
|
||||||
payload.hitSurfaceIndex = surfaceIndex;
|
|
||||||
payload.hitAttenuation = 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
)glsl";
|
|
|
@ -1,36 +0,0 @@
|
||||||
static const char* glsl_rchit_light = R"glsl(
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
|
|
||||||
struct hitPayload
|
|
||||||
{
|
|
||||||
vec3 hitPosition;
|
|
||||||
float hitAttenuation;
|
|
||||||
int hitSurfaceIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SurfaceInfo
|
|
||||||
{
|
|
||||||
vec3 Normal;
|
|
||||||
float EmissiveDistance;
|
|
||||||
vec3 EmissiveColor;
|
|
||||||
float EmissiveIntensity;
|
|
||||||
float Sky;
|
|
||||||
float SamplingDistance;
|
|
||||||
float Padding1, Padding2;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(location = 0) rayPayloadInEXT hitPayload payload;
|
|
||||||
|
|
||||||
layout(set = 0, binding = 5) buffer SurfaceIndexBuffer { uint surfaceIndices[]; };
|
|
||||||
layout(set = 0, binding = 6) buffer SurfaceBuffer { SurfaceInfo surfaces[]; };
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
//SurfaceInfo surface = surfaces[surfaceIndices[gl_PrimitiveID]];
|
|
||||||
|
|
||||||
payload.hitAttenuation = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
)glsl";
|
|
|
@ -1,35 +0,0 @@
|
||||||
static const char* glsl_rchit_sun = R"glsl(
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
|
|
||||||
struct hitPayload
|
|
||||||
{
|
|
||||||
vec3 hitPosition;
|
|
||||||
float hitAttenuation;
|
|
||||||
int hitSurfaceIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SurfaceInfo
|
|
||||||
{
|
|
||||||
vec3 Normal;
|
|
||||||
float EmissiveDistance;
|
|
||||||
vec3 EmissiveColor;
|
|
||||||
float EmissiveIntensity;
|
|
||||||
float Sky;
|
|
||||||
float SamplingDistance;
|
|
||||||
float Padding1, Padding2;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(location = 0) rayPayloadInEXT hitPayload payload;
|
|
||||||
|
|
||||||
layout(set = 0, binding = 5) buffer SurfaceIndexBuffer { int surfaceIndices[]; };
|
|
||||||
layout(set = 0, binding = 6) buffer SurfaceBuffer { SurfaceInfo surfaces[]; };
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
SurfaceInfo surface = surfaces[surfaceIndices[gl_PrimitiveID]];
|
|
||||||
payload.hitAttenuation = surface.Sky;
|
|
||||||
}
|
|
||||||
|
|
||||||
)glsl";
|
|
|
@ -1,112 +0,0 @@
|
||||||
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";
|
|
|
@ -1,155 +0,0 @@
|
||||||
static const char* glsl_rgen_bounce = 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;
|
|
||||||
};
|
|
||||||
|
|
||||||
vec3 ImportanceSample(vec3 N);
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
ivec2 texelPos = ivec2(gl_LaunchIDEXT.xy);
|
|
||||||
|
|
||||||
vec4 data0;
|
|
||||||
if (PassType == 2)
|
|
||||||
data0 = imageLoad(positions, texelPos);
|
|
||||||
else
|
|
||||||
data0 = imageLoad(startpositions, texelPos);
|
|
||||||
|
|
||||||
vec4 incoming = vec4(0.0, 0.0, 0.0, 1.0);
|
|
||||||
if (PassType != 0)
|
|
||||||
incoming = imageLoad(outputs, texelPos);
|
|
||||||
|
|
||||||
vec3 origin = data0.xyz;
|
|
||||||
int surfaceIndex = int(data0.w);
|
|
||||||
if (surfaceIndex != -1)
|
|
||||||
{
|
|
||||||
if (PassType == 0)
|
|
||||||
{
|
|
||||||
if (surfaceIndex >= 0)
|
|
||||||
{
|
|
||||||
SurfaceInfo surface = surfaces[surfaceIndex];
|
|
||||||
incoming.rgb = surface.EmissiveColor * surface.EmissiveIntensity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (PassType == 1)
|
|
||||||
incoming.w = 1.0f / float(SampleCount);
|
|
||||||
|
|
||||||
vec3 normal;
|
|
||||||
if (surfaceIndex >= 0)
|
|
||||||
{
|
|
||||||
normal = surfaces[surfaceIndex].Normal;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (SampleIndex % 6)
|
|
||||||
{
|
|
||||||
case 0: normal = vec3( 1.0f, 0.0f, 0.0f); break;
|
|
||||||
case 1: normal = vec3(-1.0f, 0.0f, 0.0f); break;
|
|
||||||
case 2: normal = vec3( 0.0f, 1.0f, 0.0f); break;
|
|
||||||
case 3: normal = vec3( 0.0f, -1.0f, 0.0f); break;
|
|
||||||
case 4: normal = vec3( 0.0f, 0.0f, 1.0f); break;
|
|
||||||
case 5: normal = vec3( 0.0f, 0.0f, -1.0f); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 H = ImportanceSample(normal);
|
|
||||||
vec3 L = normalize(H * (2.0f * dot(normal, H)) - normal);
|
|
||||||
|
|
||||||
float NdotL = max(dot(normal, L), 0.0);
|
|
||||||
|
|
||||||
const float p = 1 / (2 * 3.14159265359);
|
|
||||||
incoming.w *= NdotL / p;
|
|
||||||
|
|
||||||
surfaceIndex = -1;
|
|
||||||
if (NdotL > 0.0f)
|
|
||||||
{
|
|
||||||
const float minDistance = 0.1;
|
|
||||||
|
|
||||||
traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, origin + normal * 0.1, minDistance, L, 32768, 0);
|
|
||||||
if (payload.hitAttenuation == 1.0)
|
|
||||||
{
|
|
||||||
surfaceIndex = payload.hitSurfaceIndex;
|
|
||||||
SurfaceInfo surface = surfaces[surfaceIndex];
|
|
||||||
if (surface.EmissiveDistance > 0.0)
|
|
||||||
{
|
|
||||||
float hitDistance = distance(origin, payload.hitPosition);
|
|
||||||
float attenuation = max(1.0 - (hitDistance / surface.EmissiveDistance), 0.0f);
|
|
||||||
incoming.rgb += surface.EmissiveColor * (surface.EmissiveIntensity * attenuation * incoming.w);
|
|
||||||
}
|
|
||||||
origin = payload.hitPosition;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
incoming.w *= 0.25; // the amount of incoming light the surfaces emit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data0.xyz = origin;
|
|
||||||
data0.w = float(surfaceIndex);
|
|
||||||
|
|
||||||
imageStore(positions, texelPos, data0);
|
|
||||||
imageStore(outputs, texelPos, incoming);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 ImportanceSample(vec3 N)
|
|
||||||
{
|
|
||||||
// from tangent-space vector to world-space sample vector
|
|
||||||
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);
|
|
||||||
|
|
||||||
vec3 sampleVec = tangent * HemisphereVec.x + bitangent * HemisphereVec.y + N * HemisphereVec.z;
|
|
||||||
return normalize(sampleVec);
|
|
||||||
}
|
|
||||||
|
|
||||||
)glsl";
|
|
|
@ -1,203 +0,0 @@
|
||||||
static const char* glsl_rgen_light = 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;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LightInfo
|
|
||||||
{
|
|
||||||
vec3 Origin;
|
|
||||||
float Padding0;
|
|
||||||
float Radius;
|
|
||||||
float Intensity;
|
|
||||||
float InnerAngleCos;
|
|
||||||
float OuterAngleCos;
|
|
||||||
vec3 SpotDir;
|
|
||||||
float Padding1;
|
|
||||||
vec3 Color;
|
|
||||||
float Padding2;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(set = 0, binding = 6) buffer SurfaceBuffer { SurfaceInfo surfaces[]; };
|
|
||||||
layout(set = 0, binding = 7) buffer LightBuffer { LightInfo lights[]; };
|
|
||||||
|
|
||||||
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 incoming = imageLoad(outputs, texelPos);
|
|
||||||
vec4 data0 = imageLoad(positions, texelPos);
|
|
||||||
int surfaceIndex = int(data0.w);
|
|
||||||
if (surfaceIndex == -1 || incoming.w <= 0.0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
vec3 origin = data0.xyz;
|
|
||||||
vec3 normal;
|
|
||||||
if (surfaceIndex >= 0)
|
|
||||||
{
|
|
||||||
normal = surfaces[surfaceIndex].Normal;
|
|
||||||
origin += normal * 0.1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float minDistance = 0.01;
|
|
||||||
|
|
||||||
if (LightStart == 0) // Sun light
|
|
||||||
{
|
|
||||||
const float dist = 32768.0;
|
|
||||||
|
|
||||||
float attenuation = 0.0;
|
|
||||||
if (PassType == 0 && surfaceIndex >= 0)
|
|
||||||
{
|
|
||||||
if(dot(normal, SunDir) > 0.0)
|
|
||||||
{
|
|
||||||
vec3 e0 = normalize(cross(normal, abs(normal.x) < abs(normal.y) ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0)));
|
|
||||||
vec3 e1 = cross(normal, e0);
|
|
||||||
e0 = cross(normal, e1);
|
|
||||||
|
|
||||||
for (uint i = 0; i < SampleCount; i++)
|
|
||||||
{
|
|
||||||
vec2 offset = (Hammersley(i, SampleCount) - 0.5) * surfaces[surfaceIndex].SamplingDistance;
|
|
||||||
vec3 origin2 = origin + offset.x * e0 + offset.y * e1;
|
|
||||||
|
|
||||||
traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 2, 0, 2, origin2, minDistance, SunDir, dist, 0);
|
|
||||||
attenuation += payload.hitAttenuation;
|
|
||||||
}
|
|
||||||
attenuation *= 1.0 / float(SampleCount);
|
|
||||||
incoming.rgb += SunColor * (attenuation * SunIntensity * incoming.w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 2, 0, 2, origin, minDistance, SunDir, dist, 0);
|
|
||||||
attenuation = payload.hitAttenuation;
|
|
||||||
incoming.rgb += SunColor * (attenuation * SunIntensity * incoming.w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint j = LightStart; j < LightEnd; j++)
|
|
||||||
{
|
|
||||||
LightInfo light = lights[j];
|
|
||||||
|
|
||||||
float dist = distance(light.Origin, origin);
|
|
||||||
if (dist > minDistance && dist < light.Radius)
|
|
||||||
{
|
|
||||||
vec3 dir = normalize(light.Origin - origin);
|
|
||||||
if(surfaceIndex < 0 || dot(normal, dir) > 0.0)
|
|
||||||
{
|
|
||||||
float distAttenuation = max(1.0 - (dist / light.Radius), 0.0);
|
|
||||||
float angleAttenuation = 1.0f;
|
|
||||||
if (surfaceIndex >= 0)
|
|
||||||
{
|
|
||||||
angleAttenuation = max(dot(normal, dir), 0.0);
|
|
||||||
}
|
|
||||||
float spotAttenuation = 1.0;
|
|
||||||
if (light.OuterAngleCos > -1.0)
|
|
||||||
{
|
|
||||||
float cosDir = dot(dir, light.SpotDir);
|
|
||||||
spotAttenuation = smoothstep(light.OuterAngleCos, light.InnerAngleCos, cosDir);
|
|
||||||
spotAttenuation = max(spotAttenuation, 0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float attenuation = distAttenuation * angleAttenuation * spotAttenuation;
|
|
||||||
if (attenuation > 0.0)
|
|
||||||
{
|
|
||||||
float shadowAttenuation = 0.0;
|
|
||||||
|
|
||||||
if (PassType == 0 && surfaceIndex >= 0)
|
|
||||||
{
|
|
||||||
vec3 e0 = normalize(cross(normal, abs(normal.x) < abs(normal.y) ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0)));
|
|
||||||
vec3 e1 = cross(normal, e0);
|
|
||||||
e0 = cross(normal, e1);
|
|
||||||
for (uint i = 0; i < SampleCount; i++)
|
|
||||||
{
|
|
||||||
vec2 offset = (Hammersley(i, SampleCount) - 0.5) * surfaces[surfaceIndex].SamplingDistance;
|
|
||||||
vec3 origin2 = origin + offset.x * e0 + offset.y * e1;
|
|
||||||
|
|
||||||
float dist2 = distance(light.Origin, origin2);
|
|
||||||
vec3 dir2 = normalize(light.Origin - origin2);
|
|
||||||
|
|
||||||
traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 1, 0, 1, origin2, minDistance, dir2, dist2, 0);
|
|
||||||
shadowAttenuation += payload.hitAttenuation;
|
|
||||||
}
|
|
||||||
shadowAttenuation *= 1.0 / float(SampleCount);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 1, 0, 1, origin, minDistance, dir, dist, 0);
|
|
||||||
shadowAttenuation = payload.hitAttenuation;
|
|
||||||
}
|
|
||||||
|
|
||||||
attenuation *= shadowAttenuation;
|
|
||||||
|
|
||||||
incoming.rgb += light.Color * (attenuation * light.Intensity) * incoming.w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
imageStore(outputs, texelPos, incoming);
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 Hammersley(uint i, uint N)
|
|
||||||
{
|
|
||||||
return vec2(float(i) / float(N), RadicalInverse_VdC(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
)glsl";
|
|
|
@ -1,20 +0,0 @@
|
||||||
static const char* glsl_rmiss_ambient = R"glsl(
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
|
|
||||||
struct hitPayload
|
|
||||||
{
|
|
||||||
vec3 hitPosition;
|
|
||||||
float hitAttenuation;
|
|
||||||
int hitSurfaceIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(location = 0) rayPayloadInEXT hitPayload payload;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
payload.hitAttenuation = 100000.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
)glsl";
|
|
|
@ -1,20 +0,0 @@
|
||||||
static const char* glsl_rmiss_bounce = R"glsl(
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
|
|
||||||
struct hitPayload
|
|
||||||
{
|
|
||||||
vec3 hitPosition;
|
|
||||||
float hitAttenuation;
|
|
||||||
int hitSurfaceIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(location = 0) rayPayloadInEXT hitPayload payload;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
payload.hitAttenuation = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
)glsl";
|
|
|
@ -1,20 +0,0 @@
|
||||||
static const char* glsl_rmiss_light = R"glsl(
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
|
|
||||||
struct hitPayload
|
|
||||||
{
|
|
||||||
vec3 hitPosition;
|
|
||||||
float hitAttenuation;
|
|
||||||
int hitSurfaceIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(location = 0) rayPayloadInEXT hitPayload payload;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
payload.hitAttenuation = 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
)glsl";
|
|
|
@ -1,20 +0,0 @@
|
||||||
static const char* glsl_rmiss_sun = R"glsl(
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
|
|
||||||
struct hitPayload
|
|
||||||
{
|
|
||||||
vec3 hitPosition;
|
|
||||||
float hitAttenuation;
|
|
||||||
int hitSurfaceIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(location = 0) rayPayloadInEXT hitPayload payload;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
payload.hitAttenuation = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
)glsl";
|
|
File diff suppressed because it is too large
Load diff
|
@ -8,23 +8,24 @@ class LevelMesh;
|
||||||
|
|
||||||
struct Uniforms
|
struct Uniforms
|
||||||
{
|
{
|
||||||
uint32_t SampleIndex;
|
|
||||||
uint32_t SampleCount;
|
|
||||||
uint32_t PassType;
|
|
||||||
uint32_t Padding0;
|
|
||||||
vec3 SunDir;
|
vec3 SunDir;
|
||||||
float Padding1;
|
float Padding1;
|
||||||
vec3 SunColor;
|
vec3 SunColor;
|
||||||
float SunIntensity;
|
float SunIntensity;
|
||||||
vec3 HemisphereVec;
|
|
||||||
float Padding2;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PushConstants
|
struct PushConstants
|
||||||
{
|
{
|
||||||
uint32_t LightStart;
|
uint32_t LightStart;
|
||||||
uint32_t LightEnd;
|
uint32_t LightEnd;
|
||||||
ivec2 pushPadding;
|
int32_t SurfaceIndex;
|
||||||
|
int32_t PushPadding1;
|
||||||
|
vec3 LightmapOrigin;
|
||||||
|
float PushPadding2;
|
||||||
|
vec3 LightmapStepX;
|
||||||
|
float PushPadding3;
|
||||||
|
vec3 LightmapStepY;
|
||||||
|
float PushPadding4;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SurfaceInfo
|
struct SurfaceInfo
|
||||||
|
@ -52,9 +53,28 @@ struct LightInfo
|
||||||
float Padding2;
|
float Padding2;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TraceTask
|
struct LightmapImage
|
||||||
{
|
{
|
||||||
int id, x, y;
|
struct
|
||||||
|
{
|
||||||
|
std::unique_ptr<VulkanImage> Image;
|
||||||
|
std::unique_ptr<VulkanImageView> View;
|
||||||
|
std::unique_ptr<VulkanFramebuffer> Framebuffer;
|
||||||
|
} raytrace;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
std::unique_ptr<VulkanImage> Image;
|
||||||
|
std::unique_ptr<VulkanImageView> View;
|
||||||
|
std::unique_ptr<VulkanFramebuffer> Framebuffer;
|
||||||
|
} resolve;
|
||||||
|
|
||||||
|
std::unique_ptr<VulkanBuffer> Transfer;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SceneVertex
|
||||||
|
{
|
||||||
|
vec2 Position;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GPURaytracer
|
class GPURaytracer
|
||||||
|
@ -66,31 +86,34 @@ public:
|
||||||
void Raytrace(LevelMesh* level);
|
void Raytrace(LevelMesh* level);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void CreateTasks(std::vector<TraceTask>& tasks);
|
|
||||||
void CreateVulkanObjects();
|
void CreateVulkanObjects();
|
||||||
void CreateVertexAndIndexBuffers();
|
void CreateVertexAndIndexBuffers();
|
||||||
void CreateBottomLevelAccelerationStructure();
|
void CreateBottomLevelAccelerationStructure();
|
||||||
void CreateTopLevelAccelerationStructure();
|
void CreateTopLevelAccelerationStructure();
|
||||||
void CreateShaders();
|
void CreateShaders();
|
||||||
std::unique_ptr<VulkanShader> CompileRayGenShader(const char* code, const char* name);
|
void CreateRaytracePipeline();
|
||||||
std::unique_ptr<VulkanShader> CompileClosestHitShader(const char* code, const char* name);
|
void CreateResolvePipeline();
|
||||||
std::unique_ptr<VulkanShader> CompileMissShader(const char* code, const char* name);
|
void CreateUniformBuffer();
|
||||||
void CreatePipeline();
|
void CreateSceneVertexBuffer();
|
||||||
void CreateDescriptorSet();
|
void CreateSceneLightBuffer();
|
||||||
|
|
||||||
void UploadTasks(const TraceTask* tasks, size_t size);
|
void UploadUniforms();
|
||||||
void BeginTracing();
|
void CreateAtlasImages();
|
||||||
void RunTrace(const Uniforms& uniforms, const VkStridedDeviceAddressRegionKHR& rgenShader, int lightStart = 0, int lightEnd = 0);
|
void RenderAtlasImage(size_t pageIndex);
|
||||||
void EndTracing();
|
void ResolveAtlasImage(size_t pageIndex);
|
||||||
void DownloadTasks(const TraceTask* tasks, size_t size);
|
void DownloadAtlasImage(size_t pageIndex);
|
||||||
void SubmitCommands();
|
|
||||||
|
LightmapImage CreateImage(int width, int height);
|
||||||
|
|
||||||
|
void BeginCommands();
|
||||||
|
void FinishCommands();
|
||||||
|
|
||||||
void PrintVulkanInfo();
|
void PrintVulkanInfo();
|
||||||
|
|
||||||
static float RadicalInverse_VdC(uint32_t bits);
|
std::vector<SurfaceInfo> CreateSurfaceInfo();
|
||||||
static vec2 Hammersley(uint32_t i, uint32_t N);
|
|
||||||
|
|
||||||
int rayTraceImageSize = 1024;
|
static vec2 ToUV(const vec3& vert, const Surface* targetSurface);
|
||||||
|
static bool IsNegativelyOriented(const vec2& v1, const vec2& v2, const vec2& v3);
|
||||||
|
|
||||||
LevelMesh* mesh = nullptr;
|
LevelMesh* mesh = nullptr;
|
||||||
|
|
||||||
|
@ -101,12 +124,21 @@ private:
|
||||||
|
|
||||||
std::unique_ptr<VulkanDevice> device;
|
std::unique_ptr<VulkanDevice> device;
|
||||||
|
|
||||||
|
static const int SceneVertexBufferSize = 1 * 1024 * 1024;
|
||||||
|
std::unique_ptr<VulkanBuffer> sceneVertexBuffer;
|
||||||
|
SceneVertex* sceneVertices = nullptr;
|
||||||
|
int sceneVertexPos = 0;
|
||||||
|
|
||||||
|
static const int SceneLightBufferSize = 2 * 1024 * 1024;
|
||||||
|
std::unique_ptr<VulkanBuffer> sceneLightBuffer;
|
||||||
|
LightInfo* sceneLights = nullptr;
|
||||||
|
int sceneLightPos = 0;
|
||||||
|
|
||||||
std::unique_ptr<VulkanBuffer> vertexBuffer;
|
std::unique_ptr<VulkanBuffer> vertexBuffer;
|
||||||
std::unique_ptr<VulkanBuffer> indexBuffer;
|
std::unique_ptr<VulkanBuffer> indexBuffer;
|
||||||
std::unique_ptr<VulkanBuffer> transferBuffer;
|
std::unique_ptr<VulkanBuffer> transferBuffer;
|
||||||
std::unique_ptr<VulkanBuffer> surfaceIndexBuffer;
|
std::unique_ptr<VulkanBuffer> surfaceIndexBuffer;
|
||||||
std::unique_ptr<VulkanBuffer> surfaceBuffer;
|
std::unique_ptr<VulkanBuffer> surfaceBuffer;
|
||||||
std::unique_ptr<VulkanBuffer> lightBuffer;
|
|
||||||
|
|
||||||
std::unique_ptr<VulkanBuffer> blScratchBuffer;
|
std::unique_ptr<VulkanBuffer> blScratchBuffer;
|
||||||
std::unique_ptr<VulkanBuffer> blAccelStructBuffer;
|
std::unique_ptr<VulkanBuffer> blAccelStructBuffer;
|
||||||
|
@ -118,32 +150,38 @@ private:
|
||||||
std::unique_ptr<VulkanBuffer> tlAccelStructBuffer;
|
std::unique_ptr<VulkanBuffer> tlAccelStructBuffer;
|
||||||
std::unique_ptr<VulkanAccelerationStructure> tlAccelStruct;
|
std::unique_ptr<VulkanAccelerationStructure> tlAccelStruct;
|
||||||
|
|
||||||
std::unique_ptr<VulkanShader> rgenBounce, rgenLight, rgenAmbient;
|
std::unique_ptr<VulkanShader> vertShader;
|
||||||
std::unique_ptr<VulkanShader> rmissBounce, rmissLight, rmissSun, rmissAmbient;
|
std::unique_ptr<VulkanShader> fragShader;
|
||||||
std::unique_ptr<VulkanShader> rchitBounce, rchitLight, rchitSun, rchitAmbient;
|
std::unique_ptr<VulkanShader> fragResolveShader;
|
||||||
|
|
||||||
std::unique_ptr<VulkanDescriptorSetLayout> descriptorSetLayout;
|
struct
|
||||||
|
{
|
||||||
|
std::unique_ptr<VulkanDescriptorSetLayout> descriptorSetLayout;
|
||||||
|
std::unique_ptr<VulkanPipelineLayout> pipelineLayout;
|
||||||
|
std::unique_ptr<VulkanPipeline> pipeline;
|
||||||
|
std::unique_ptr<VulkanRenderPass> renderPass;
|
||||||
|
std::unique_ptr<VulkanDescriptorPool> descriptorPool;
|
||||||
|
std::unique_ptr<VulkanDescriptorSet> descriptorSet;
|
||||||
|
} raytrace;
|
||||||
|
|
||||||
std::unique_ptr<VulkanPipelineLayout> pipelineLayout;
|
struct
|
||||||
std::unique_ptr<VulkanPipeline> pipeline;
|
{
|
||||||
std::unique_ptr<VulkanBuffer> shaderBindingTable;
|
std::unique_ptr<VulkanDescriptorSetLayout> descriptorSetLayout;
|
||||||
std::unique_ptr<VulkanBuffer> sbtTransferBuffer;
|
std::unique_ptr<VulkanPipelineLayout> pipelineLayout;
|
||||||
|
std::unique_ptr<VulkanPipeline> pipeline;
|
||||||
VkStridedDeviceAddressRegionKHR rgenBounceRegion = {}, rgenLightRegion = {}, rgenAmbientRegion = {};
|
std::unique_ptr<VulkanRenderPass> renderPass;
|
||||||
VkStridedDeviceAddressRegionKHR missRegion = {};
|
std::unique_ptr<VulkanDescriptorPool> descriptorPool;
|
||||||
VkStridedDeviceAddressRegionKHR hitRegion = {};
|
std::vector<std::unique_ptr<VulkanDescriptorSet>> descriptorSets;
|
||||||
VkStridedDeviceAddressRegionKHR callRegion = {};
|
std::unique_ptr<VulkanSampler> sampler;
|
||||||
|
} resolve;
|
||||||
std::unique_ptr<VulkanImage> startPositionsImage, positionsImage, outputImage;
|
|
||||||
std::unique_ptr<VulkanImageView> startPositionsImageView, positionsImageView, outputImageView;
|
|
||||||
std::unique_ptr<VulkanBuffer> imageTransferBuffer;
|
|
||||||
|
|
||||||
std::unique_ptr<VulkanBuffer> uniformBuffer;
|
std::unique_ptr<VulkanBuffer> uniformBuffer;
|
||||||
std::unique_ptr<VulkanBuffer> uniformTransferBuffer;
|
std::unique_ptr<VulkanBuffer> uniformTransferBuffer;
|
||||||
|
|
||||||
std::unique_ptr<VulkanDescriptorPool> descriptorPool;
|
std::unique_ptr<VulkanFence> submitFence;
|
||||||
std::unique_ptr<VulkanDescriptorSet> descriptorSet;
|
|
||||||
|
|
||||||
std::unique_ptr<VulkanCommandPool> cmdpool;
|
std::unique_ptr<VulkanCommandPool> cmdpool;
|
||||||
std::unique_ptr<VulkanCommandBuffer> cmdbuffer;
|
std::unique_ptr<VulkanCommandBuffer> cmdbuffer;
|
||||||
|
|
||||||
|
std::vector<LightmapImage> atlasImages;
|
||||||
|
static const int atlasImageSize = 2048;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,923 +0,0 @@
|
||||||
|
|
||||||
#include "math/mathlib.h"
|
|
||||||
#include "levelmesh.h"
|
|
||||||
#include "level/level.h"
|
|
||||||
#include "gpuraytracer2.h"
|
|
||||||
#include "framework/binfile.h"
|
|
||||||
#include "framework/templates.h"
|
|
||||||
#include "framework/halffloat.h"
|
|
||||||
#include "vulkanbuilders.h"
|
|
||||||
#include <map>
|
|
||||||
#include <vector>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <limits>
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <mutex>
|
|
||||||
#include <thread>
|
|
||||||
#include "glsl_frag.h"
|
|
||||||
#include "glsl_frag_resolve.h"
|
|
||||||
#include "glsl_vert.h"
|
|
||||||
|
|
||||||
extern bool VKDebug;
|
|
||||||
|
|
||||||
GPURaytracer2::GPURaytracer2()
|
|
||||||
{
|
|
||||||
device = std::make_unique<VulkanDevice>(0, VKDebug);
|
|
||||||
PrintVulkanInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
GPURaytracer2::~GPURaytracer2()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPURaytracer2::Raytrace(LevelMesh* level)
|
|
||||||
{
|
|
||||||
mesh = level;
|
|
||||||
|
|
||||||
printf("Building Vulkan acceleration structures\n");
|
|
||||||
|
|
||||||
if (device->renderdoc)
|
|
||||||
device->renderdoc->StartFrameCapture(0, 0);
|
|
||||||
|
|
||||||
CreateVulkanObjects();
|
|
||||||
|
|
||||||
printf("Ray tracing in progress...\n");
|
|
||||||
|
|
||||||
CreateAtlasImages();
|
|
||||||
|
|
||||||
BeginCommands();
|
|
||||||
UploadUniforms();
|
|
||||||
|
|
||||||
for (size_t pageIndex = 0; pageIndex < atlasImages.size(); pageIndex++)
|
|
||||||
{
|
|
||||||
RenderAtlasImage(pageIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t pageIndex = 0; pageIndex < atlasImages.size(); pageIndex++)
|
|
||||||
{
|
|
||||||
ResolveAtlasImage(pageIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
LARGE_INTEGER s;
|
|
||||||
QueryPerformanceCounter(&s);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
FinishCommands();
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
LARGE_INTEGER e, f;
|
|
||||||
QueryPerformanceCounter(&e);
|
|
||||||
QueryPerformanceFrequency(&f);
|
|
||||||
printf("GPU ray tracing time was %.3f seconds.\n", double(e.QuadPart - s.QuadPart) / double(f.QuadPart));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (size_t pageIndex = 0; pageIndex < atlasImages.size(); pageIndex++)
|
|
||||||
{
|
|
||||||
DownloadAtlasImage(pageIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (device->renderdoc)
|
|
||||||
device->renderdoc->EndFrameCapture(0, 0);
|
|
||||||
|
|
||||||
printf("Ray trace complete\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPURaytracer2::RenderAtlasImage(size_t pageIndex)
|
|
||||||
{
|
|
||||||
LightmapImage& img = atlasImages[pageIndex];
|
|
||||||
|
|
||||||
RenderPassBegin()
|
|
||||||
.RenderPass(raytrace.renderPass.get())
|
|
||||||
.RenderArea(0, 0, atlasImageSize, atlasImageSize)
|
|
||||||
.Framebuffer(img.raytrace.Framebuffer.get())
|
|
||||||
.Execute(cmdbuffer.get());
|
|
||||||
|
|
||||||
VkDeviceSize offset = 0;
|
|
||||||
cmdbuffer->bindVertexBuffers(0, 1, &sceneVertexBuffer->buffer, &offset);
|
|
||||||
cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipeline.get());
|
|
||||||
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipelineLayout.get(), 0, raytrace.descriptorSet.get());
|
|
||||||
|
|
||||||
for (size_t i = 0; i < mesh->surfaces.size(); i++)
|
|
||||||
{
|
|
||||||
Surface* targetSurface = mesh->surfaces[i].get();
|
|
||||||
if (targetSurface->atlasPageIndex != pageIndex)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
VkViewport viewport = {};
|
|
||||||
viewport.maxDepth = 1;
|
|
||||||
viewport.x = (float)targetSurface->atlasX - 1;
|
|
||||||
viewport.y = (float)targetSurface->atlasY - 1;
|
|
||||||
viewport.width = (float)(targetSurface->texWidth + 2);
|
|
||||||
viewport.height = (float)(targetSurface->texHeight + 2);
|
|
||||||
cmdbuffer->setViewport(0, 1, &viewport);
|
|
||||||
|
|
||||||
// Paint all surfaces part of the smoothing group into the surface
|
|
||||||
for (const auto& surface : mesh->surfaces)
|
|
||||||
{
|
|
||||||
if (surface->smoothingGroupIndex != targetSurface->smoothingGroupIndex)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
vec2 minUV = ToUV(surface->bounds.min, targetSurface);
|
|
||||||
vec2 maxUV = ToUV(surface->bounds.max, targetSurface);
|
|
||||||
if (surface.get() != targetSurface && (maxUV.x < 0.0f || maxUV.y < 0.0f || minUV.x > 1.0f || minUV.y > 1.0f))
|
|
||||||
continue; // Bounding box not visible
|
|
||||||
|
|
||||||
int firstLight = sceneLightPos;
|
|
||||||
int lightCount = (int)surface->LightList.size();
|
|
||||||
if (sceneLightPos + lightCount > SceneLightBufferSize)
|
|
||||||
throw std::runtime_error("SceneLightBuffer is too small!");
|
|
||||||
sceneLightPos += lightCount;
|
|
||||||
|
|
||||||
LightInfo2* lightinfo = &sceneLights[firstLight];
|
|
||||||
for (ThingLight* light : surface->LightList)
|
|
||||||
{
|
|
||||||
lightinfo->Origin = light->LightOrigin();
|
|
||||||
lightinfo->Radius = light->LightRadius();
|
|
||||||
lightinfo->Intensity = light->intensity;
|
|
||||||
lightinfo->InnerAngleCos = light->innerAngleCos;
|
|
||||||
lightinfo->OuterAngleCos = light->outerAngleCos;
|
|
||||||
lightinfo->SpotDir = light->SpotDir();
|
|
||||||
lightinfo->Color = light->rgb;
|
|
||||||
lightinfo++;
|
|
||||||
}
|
|
||||||
|
|
||||||
PushConstants2 pc;
|
|
||||||
pc.LightStart = firstLight;
|
|
||||||
pc.LightEnd = firstLight + lightCount;
|
|
||||||
pc.SurfaceIndex = (int32_t)i;
|
|
||||||
pc.LightmapOrigin = targetSurface->worldOrigin - targetSurface->worldStepX - targetSurface->worldStepY;
|
|
||||||
pc.LightmapStepX = targetSurface->worldStepX * viewport.width;
|
|
||||||
pc.LightmapStepY = targetSurface->worldStepY * viewport.height;
|
|
||||||
cmdbuffer->pushConstants(raytrace.pipelineLayout.get(), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstants2), &pc);
|
|
||||||
|
|
||||||
int firstVertex = sceneVertexPos;
|
|
||||||
int vertexCount = (int)surface->verts.size();
|
|
||||||
if (sceneVertexPos + vertexCount > SceneVertexBufferSize)
|
|
||||||
throw std::runtime_error("SceneVertexBuffer is too small!");
|
|
||||||
sceneVertexPos += vertexCount;
|
|
||||||
SceneVertex* vertex = &sceneVertices[firstVertex];
|
|
||||||
|
|
||||||
if (surface->type == ST_FLOOR || surface->type == ST_CEILING)
|
|
||||||
{
|
|
||||||
for (int idx = 0; idx < vertexCount; idx++)
|
|
||||||
{
|
|
||||||
(vertex++)->Position = ToUV(surface->verts[idx], targetSurface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
(vertex++)->Position = ToUV(surface->verts[0], targetSurface);
|
|
||||||
(vertex++)->Position = ToUV(surface->verts[2], targetSurface);
|
|
||||||
(vertex++)->Position = ToUV(surface->verts[3], targetSurface);
|
|
||||||
(vertex++)->Position = ToUV(surface->verts[1], targetSurface);
|
|
||||||
}
|
|
||||||
|
|
||||||
cmdbuffer->draw(vertexCount, 1, firstVertex, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cmdbuffer->endRenderPass();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPURaytracer2::CreateAtlasImages()
|
|
||||||
{
|
|
||||||
const int spacing = 3; // Note: the spacing is here to avoid that the resolve sampler finds data from other surface tiles
|
|
||||||
RectPacker packer(atlasImageSize, atlasImageSize, RectPacker::Spacing(spacing));
|
|
||||||
|
|
||||||
for (size_t i = 0; i < mesh->surfaces.size(); i++)
|
|
||||||
{
|
|
||||||
Surface* surface = mesh->surfaces[i].get();
|
|
||||||
|
|
||||||
auto result = packer.insert(surface->texWidth + 2, surface->texHeight + 2);
|
|
||||||
surface->atlasX = result.pos.x + 1;
|
|
||||||
surface->atlasY = result.pos.y + 1;
|
|
||||||
surface->atlasPageIndex = (int)result.pageIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t pageIndex = 0; pageIndex < packer.getNumPages(); pageIndex++)
|
|
||||||
{
|
|
||||||
atlasImages.push_back(CreateImage(atlasImageSize, atlasImageSize));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPURaytracer2::UploadUniforms()
|
|
||||||
{
|
|
||||||
Uniforms2 uniforms = {};
|
|
||||||
uniforms.SunDir = mesh->map->GetSunDirection();
|
|
||||||
uniforms.SunColor = mesh->map->GetSunColor();
|
|
||||||
uniforms.SunIntensity = 1.0f;
|
|
||||||
|
|
||||||
mappedUniforms = (uint8_t*)uniformTransferBuffer->Map(0, uniformStructs * uniformStructStride);
|
|
||||||
*reinterpret_cast<Uniforms2*>(mappedUniforms + uniformStructStride * uniformsIndex) = uniforms;
|
|
||||||
uniformTransferBuffer->Unmap();
|
|
||||||
|
|
||||||
cmdbuffer->copyBuffer(uniformTransferBuffer.get(), uniformBuffer.get());
|
|
||||||
PipelineBarrier()
|
|
||||||
.AddBuffer(uniformBuffer.get(), VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT)
|
|
||||||
.Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPURaytracer2::ResolveAtlasImage(size_t i)
|
|
||||||
{
|
|
||||||
LightmapImage& img = atlasImages[i];
|
|
||||||
|
|
||||||
PipelineBarrier()
|
|
||||||
.AddImage(img.raytrace.Image.get(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT)
|
|
||||||
.Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
|
||||||
|
|
||||||
RenderPassBegin()
|
|
||||||
.RenderPass(resolve.renderPass.get())
|
|
||||||
.RenderArea(0, 0, atlasImageSize, atlasImageSize)
|
|
||||||
.Framebuffer(img.resolve.Framebuffer.get())
|
|
||||||
.Execute(cmdbuffer.get());
|
|
||||||
|
|
||||||
VkDeviceSize offset = 0;
|
|
||||||
cmdbuffer->bindVertexBuffers(0, 1, &sceneVertexBuffer->buffer, &offset);
|
|
||||||
cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, resolve.pipeline.get());
|
|
||||||
|
|
||||||
auto descriptorSet = resolve.descriptorPool->allocate(resolve.descriptorSetLayout.get());
|
|
||||||
descriptorSet->SetDebugName("resolve.descriptorSet");
|
|
||||||
WriteDescriptors()
|
|
||||||
.AddCombinedImageSampler(descriptorSet.get(), 0, img.raytrace.View.get(), resolve.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
|
||||||
.Execute(device.get());
|
|
||||||
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, resolve.pipelineLayout.get(), 0, descriptorSet.get());
|
|
||||||
resolve.descriptorSets.push_back(std::move(descriptorSet));
|
|
||||||
|
|
||||||
VkViewport viewport = {};
|
|
||||||
viewport.maxDepth = 1;
|
|
||||||
viewport.width = (float)atlasImageSize;
|
|
||||||
viewport.height = (float)atlasImageSize;
|
|
||||||
cmdbuffer->setViewport(0, 1, &viewport);
|
|
||||||
|
|
||||||
PushConstants2 pc;
|
|
||||||
pc.LightStart = 0;
|
|
||||||
pc.LightEnd = 0;
|
|
||||||
pc.SurfaceIndex = 0;
|
|
||||||
pc.LightmapOrigin = vec3(0.0f);
|
|
||||||
pc.LightmapStepX = vec3(0.0f);
|
|
||||||
pc.LightmapStepY = vec3(0.0f);
|
|
||||||
cmdbuffer->pushConstants(resolve.pipelineLayout.get(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(PushConstants2), &pc);
|
|
||||||
|
|
||||||
int firstVertex = sceneVertexPos;
|
|
||||||
int vertexCount = 4;
|
|
||||||
sceneVertexPos += vertexCount;
|
|
||||||
SceneVertex* vertex = &sceneVertices[firstVertex];
|
|
||||||
vertex[0].Position = vec2(0.0f, 0.0f);
|
|
||||||
vertex[1].Position = vec2(1.0f, 0.0f);
|
|
||||||
vertex[2].Position = vec2(1.0f, 1.0f);
|
|
||||||
vertex[3].Position = vec2(0.0f, 1.0f);
|
|
||||||
cmdbuffer->draw(vertexCount, 1, firstVertex, 0);
|
|
||||||
|
|
||||||
cmdbuffer->endRenderPass();
|
|
||||||
|
|
||||||
PipelineBarrier()
|
|
||||||
.AddImage(img.resolve.Image.get(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT)
|
|
||||||
.Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
|
||||||
|
|
||||||
VkBufferImageCopy region = {};
|
|
||||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
region.imageSubresource.layerCount = 1;
|
|
||||||
region.imageExtent.width = atlasImageSize;
|
|
||||||
region.imageExtent.height = atlasImageSize;
|
|
||||||
region.imageExtent.depth = 1;
|
|
||||||
cmdbuffer->copyImageToBuffer(img.resolve.Image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, img.Transfer->buffer, 1, ®ion);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPURaytracer2::DownloadAtlasImage(size_t pageIndex)
|
|
||||||
{
|
|
||||||
struct hvec4
|
|
||||||
{
|
|
||||||
unsigned short x, y, z, w;
|
|
||||||
vec3 xyz() { return vec3(halfToFloat(x), halfToFloat(y), halfToFloat(z)); }
|
|
||||||
};
|
|
||||||
|
|
||||||
hvec4* pixels = (hvec4*)atlasImages[pageIndex].Transfer->Map(0, atlasImageSize * atlasImageSize * sizeof(hvec4));
|
|
||||||
|
|
||||||
for (size_t i = 0; i < mesh->surfaces.size(); i++)
|
|
||||||
{
|
|
||||||
Surface* surface = mesh->surfaces[i].get();
|
|
||||||
if (surface->atlasPageIndex != pageIndex)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int atlasX = surface->atlasX;
|
|
||||||
int atlasY = surface->atlasY;
|
|
||||||
int sampleWidth = surface->texWidth;
|
|
||||||
int sampleHeight = surface->texHeight;
|
|
||||||
|
|
||||||
for (int y = 0; y < sampleHeight; y++)
|
|
||||||
{
|
|
||||||
vec3* dest = &surface->texPixels[y * sampleWidth];
|
|
||||||
hvec4* src = &pixels[atlasX + (atlasY + y) * atlasImageSize];
|
|
||||||
for (int x = 0; x < sampleWidth; x++)
|
|
||||||
{
|
|
||||||
dest[x] = src[x].xyz();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
atlasImages[pageIndex].Transfer->Unmap();
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 GPURaytracer2::ToUV(const vec3& vert, const Surface* targetSurface)
|
|
||||||
{
|
|
||||||
vec3 localPos = vert - targetSurface->translateWorldToLocal;
|
|
||||||
float u = (1.0f + dot(localPos, targetSurface->projLocalToU)) / (targetSurface->texWidth + 2);
|
|
||||||
float v = (1.0f + dot(localPos, targetSurface->projLocalToV)) / (targetSurface->texHeight + 2);
|
|
||||||
return vec2(u, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPURaytracer2::CreateVulkanObjects()
|
|
||||||
{
|
|
||||||
submitFence = std::make_unique<VulkanFence>(device.get());
|
|
||||||
cmdpool = std::make_unique<VulkanCommandPool>(device.get(), device->graphicsFamily);
|
|
||||||
|
|
||||||
BeginCommands();
|
|
||||||
|
|
||||||
CreateSceneVertexBuffer();
|
|
||||||
CreateSceneLightBuffer();
|
|
||||||
CreateVertexAndIndexBuffers();
|
|
||||||
CreateUniformBuffer();
|
|
||||||
CreateBottomLevelAccelerationStructure();
|
|
||||||
CreateTopLevelAccelerationStructure();
|
|
||||||
CreateShaders();
|
|
||||||
CreateRaytracePipeline();
|
|
||||||
CreateResolvePipeline();
|
|
||||||
|
|
||||||
FinishCommands();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPURaytracer2::CreateSceneVertexBuffer()
|
|
||||||
{
|
|
||||||
size_t size = sizeof(SceneVertex) * SceneVertexBufferSize;
|
|
||||||
|
|
||||||
sceneVertexBuffer = BufferBuilder()
|
|
||||||
.Usage(
|
|
||||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
|
||||||
VMA_MEMORY_USAGE_UNKNOWN, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT)
|
|
||||||
.MemoryType(
|
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
|
|
||||||
.Size(size)
|
|
||||||
.DebugName("SceneVertexBuffer")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
sceneVertices = (SceneVertex*)sceneVertexBuffer->Map(0, size);
|
|
||||||
sceneVertexPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPURaytracer2::CreateSceneLightBuffer()
|
|
||||||
{
|
|
||||||
size_t size = sizeof(LightInfo2) * SceneLightBufferSize;
|
|
||||||
|
|
||||||
sceneLightBuffer = BufferBuilder()
|
|
||||||
.Usage(
|
|
||||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
|
|
||||||
VMA_MEMORY_USAGE_UNKNOWN, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT)
|
|
||||||
.MemoryType(
|
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
|
|
||||||
.Size(size)
|
|
||||||
.DebugName("SceneLightBuffer")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
sceneLights = (LightInfo2*)sceneLightBuffer->Map(0, size);
|
|
||||||
sceneLightPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPURaytracer2::BeginCommands()
|
|
||||||
{
|
|
||||||
cmdbuffer = cmdpool->createBuffer();
|
|
||||||
cmdbuffer->begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPURaytracer2::FinishCommands()
|
|
||||||
{
|
|
||||||
cmdbuffer->end();
|
|
||||||
|
|
||||||
QueueSubmit()
|
|
||||||
.AddCommandBuffer(cmdbuffer.get())
|
|
||||||
.Execute(device.get(), device->graphicsQueue, submitFence.get());
|
|
||||||
|
|
||||||
VkResult result = vkWaitForFences(device->device, 1, &submitFence->fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
|
|
||||||
if (result != VK_SUCCESS)
|
|
||||||
throw std::runtime_error("vkWaitForFences failed");
|
|
||||||
result = vkResetFences(device->device, 1, &submitFence->fence);
|
|
||||||
if (result != VK_SUCCESS)
|
|
||||||
throw std::runtime_error("vkResetFences failed");
|
|
||||||
cmdbuffer.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPURaytracer2::CreateVertexAndIndexBuffers()
|
|
||||||
{
|
|
||||||
std::vector<SurfaceInfo2> surfaces = CreateSurfaceInfo();
|
|
||||||
|
|
||||||
if (surfaces.empty()) // vulkan doesn't support zero byte buffers
|
|
||||||
surfaces.push_back(SurfaceInfo2());
|
|
||||||
|
|
||||||
size_t vertexbuffersize = (size_t)mesh->MeshVertices.Size() * sizeof(vec3);
|
|
||||||
size_t indexbuffersize = (size_t)mesh->MeshElements.Size() * sizeof(uint32_t);
|
|
||||||
size_t surfaceindexbuffersize = (size_t)mesh->MeshSurfaces.Size() * sizeof(uint32_t);
|
|
||||||
size_t surfacebuffersize = (size_t)surfaces.size() * sizeof(SurfaceInfo2);
|
|
||||||
size_t transferbuffersize = vertexbuffersize + indexbuffersize + surfaceindexbuffersize + surfacebuffersize;
|
|
||||||
size_t vertexoffset = 0;
|
|
||||||
size_t indexoffset = vertexoffset + vertexbuffersize;
|
|
||||||
size_t surfaceindexoffset = indexoffset + indexbuffersize;
|
|
||||||
size_t surfaceoffset = surfaceindexoffset + surfaceindexbuffersize;
|
|
||||||
size_t lightoffset = surfaceoffset + surfacebuffersize;
|
|
||||||
|
|
||||||
vertexBuffer = BufferBuilder()
|
|
||||||
.Usage(
|
|
||||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
|
|
||||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
|
||||||
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
|
|
||||||
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
|
|
||||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
|
|
||||||
.Size(vertexbuffersize)
|
|
||||||
.DebugName("vertexBuffer")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
indexBuffer = BufferBuilder()
|
|
||||||
.Usage(
|
|
||||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
|
|
||||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
|
||||||
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
|
|
||||||
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
|
|
||||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
|
|
||||||
.Size(indexbuffersize)
|
|
||||||
.DebugName("indexBuffer")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
surfaceIndexBuffer = BufferBuilder()
|
|
||||||
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
|
||||||
.Size(surfaceindexbuffersize)
|
|
||||||
.DebugName("surfaceIndexBuffer")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
surfaceBuffer = BufferBuilder()
|
|
||||||
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
|
||||||
.Size(surfacebuffersize)
|
|
||||||
.DebugName("surfaceBuffer")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
transferBuffer = BufferBuilder()
|
|
||||||
.Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY)
|
|
||||||
.Size(transferbuffersize)
|
|
||||||
.DebugName("transferBuffer")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
uint8_t* data = (uint8_t*)transferBuffer->Map(0, transferbuffersize);
|
|
||||||
memcpy(data + vertexoffset, mesh->MeshVertices.Data(), vertexbuffersize);
|
|
||||||
memcpy(data + indexoffset, mesh->MeshElements.Data(), indexbuffersize);
|
|
||||||
memcpy(data + surfaceindexoffset, mesh->MeshSurfaces.Data(), surfaceindexbuffersize);
|
|
||||||
memcpy(data + surfaceoffset, surfaces.data(), surfacebuffersize);
|
|
||||||
transferBuffer->Unmap();
|
|
||||||
|
|
||||||
cmdbuffer->copyBuffer(transferBuffer.get(), vertexBuffer.get(), vertexoffset);
|
|
||||||
cmdbuffer->copyBuffer(transferBuffer.get(), indexBuffer.get(), indexoffset);
|
|
||||||
cmdbuffer->copyBuffer(transferBuffer.get(), surfaceIndexBuffer.get(), surfaceindexoffset);
|
|
||||||
cmdbuffer->copyBuffer(transferBuffer.get(), surfaceBuffer.get(), surfaceoffset);
|
|
||||||
|
|
||||||
PipelineBarrier()
|
|
||||||
.AddMemory(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT)
|
|
||||||
.Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPURaytracer2::CreateBottomLevelAccelerationStructure()
|
|
||||||
{
|
|
||||||
VkAccelerationStructureBuildGeometryInfoKHR buildInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR };
|
|
||||||
VkAccelerationStructureGeometryKHR accelStructBLDesc = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR };
|
|
||||||
VkAccelerationStructureGeometryKHR* geometries[] = { &accelStructBLDesc };
|
|
||||||
VkAccelerationStructureBuildRangeInfoKHR rangeInfo = {};
|
|
||||||
VkAccelerationStructureBuildRangeInfoKHR* rangeInfos[] = { &rangeInfo };
|
|
||||||
|
|
||||||
accelStructBLDesc.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
|
|
||||||
accelStructBLDesc.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
|
|
||||||
accelStructBLDesc.geometry.triangles = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR };
|
|
||||||
accelStructBLDesc.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
|
|
||||||
accelStructBLDesc.geometry.triangles.vertexData.deviceAddress = vertexBuffer->GetDeviceAddress();
|
|
||||||
accelStructBLDesc.geometry.triangles.vertexStride = sizeof(vec3);
|
|
||||||
accelStructBLDesc.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32;
|
|
||||||
accelStructBLDesc.geometry.triangles.indexData.deviceAddress = indexBuffer->GetDeviceAddress();
|
|
||||||
accelStructBLDesc.geometry.triangles.maxVertex = mesh->MeshVertices.Size() - 1;
|
|
||||||
|
|
||||||
buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
|
|
||||||
buildInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR;
|
|
||||||
buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
|
||||||
buildInfo.geometryCount = 1;
|
|
||||||
buildInfo.pGeometries = &accelStructBLDesc;
|
|
||||||
|
|
||||||
uint32_t maxPrimitiveCount = mesh->MeshElements.Size() / 3;
|
|
||||||
|
|
||||||
VkAccelerationStructureBuildSizesInfoKHR sizeInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR };
|
|
||||||
vkGetAccelerationStructureBuildSizesKHR(device->device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, &maxPrimitiveCount, &sizeInfo);
|
|
||||||
|
|
||||||
blAccelStructBuffer = BufferBuilder()
|
|
||||||
.Usage(VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT)
|
|
||||||
.Size(sizeInfo.accelerationStructureSize)
|
|
||||||
.DebugName("blAccelStructBuffer")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
blAccelStruct = AccelerationStructureBuilder()
|
|
||||||
.Type(VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR)
|
|
||||||
.Buffer(blAccelStructBuffer.get(), sizeInfo.accelerationStructureSize)
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
blScratchBuffer = BufferBuilder()
|
|
||||||
.Usage(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
|
|
||||||
.Size(sizeInfo.buildScratchSize)
|
|
||||||
.DebugName("blScratchBuffer")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
buildInfo.dstAccelerationStructure = blAccelStruct->accelstruct;
|
|
||||||
buildInfo.scratchData.deviceAddress = blScratchBuffer->GetDeviceAddress();
|
|
||||||
rangeInfo.primitiveCount = maxPrimitiveCount;
|
|
||||||
|
|
||||||
cmdbuffer->buildAccelerationStructures(1, &buildInfo, rangeInfos);
|
|
||||||
|
|
||||||
// Finish building before using it as input to a toplevel accel structure
|
|
||||||
PipelineBarrier()
|
|
||||||
.AddMemory(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR)
|
|
||||||
.Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPURaytracer2::CreateTopLevelAccelerationStructure()
|
|
||||||
{
|
|
||||||
VkAccelerationStructureInstanceKHR instance = {};
|
|
||||||
instance.transform.matrix[0][0] = 1.0f;
|
|
||||||
instance.transform.matrix[1][1] = 1.0f;
|
|
||||||
instance.transform.matrix[2][2] = 1.0f;
|
|
||||||
instance.mask = 0xff;
|
|
||||||
instance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
|
||||||
instance.accelerationStructureReference = blAccelStruct->GetDeviceAddress();
|
|
||||||
|
|
||||||
tlTransferBuffer = BufferBuilder()
|
|
||||||
.Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY)
|
|
||||||
.Size(sizeof(VkAccelerationStructureInstanceKHR))
|
|
||||||
.DebugName("tlTransferBuffer")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
auto data = (uint8_t*)tlTransferBuffer->Map(0, sizeof(VkAccelerationStructureInstanceKHR));
|
|
||||||
memcpy(data, &instance, sizeof(VkAccelerationStructureInstanceKHR));
|
|
||||||
tlTransferBuffer->Unmap();
|
|
||||||
|
|
||||||
tlInstanceBuffer = BufferBuilder()
|
|
||||||
.Usage(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
|
||||||
.Size(sizeof(VkAccelerationStructureInstanceKHR))
|
|
||||||
.DebugName("tlInstanceBuffer")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
cmdbuffer->copyBuffer(tlTransferBuffer.get(), tlInstanceBuffer.get());
|
|
||||||
|
|
||||||
PipelineBarrier()
|
|
||||||
.AddMemory(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT)
|
|
||||||
.Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR);
|
|
||||||
|
|
||||||
VkAccelerationStructureGeometryKHR accelStructTLDesc = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR };
|
|
||||||
VkAccelerationStructureBuildGeometryInfoKHR buildInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR };
|
|
||||||
VkAccelerationStructureBuildRangeInfoKHR rangeInfo = {};
|
|
||||||
VkAccelerationStructureBuildRangeInfoKHR* rangeInfos[] = { &rangeInfo };
|
|
||||||
|
|
||||||
accelStructTLDesc.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR;
|
|
||||||
accelStructTLDesc.geometry.instances = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR };
|
|
||||||
accelStructTLDesc.geometry.instances.data.deviceAddress = tlInstanceBuffer->GetDeviceAddress();
|
|
||||||
|
|
||||||
buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
|
|
||||||
buildInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR;
|
|
||||||
buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
|
||||||
buildInfo.geometryCount = 1;
|
|
||||||
buildInfo.pGeometries = &accelStructTLDesc;
|
|
||||||
|
|
||||||
uint32_t maxInstanceCount = 1;
|
|
||||||
|
|
||||||
VkAccelerationStructureBuildSizesInfoKHR sizeInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR };
|
|
||||||
vkGetAccelerationStructureBuildSizesKHR(device->device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, &maxInstanceCount, &sizeInfo);
|
|
||||||
|
|
||||||
tlAccelStructBuffer = BufferBuilder()
|
|
||||||
.Usage(VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT)
|
|
||||||
.Size(sizeInfo.accelerationStructureSize)
|
|
||||||
.DebugName("tlAccelStructBuffer")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
tlAccelStruct = AccelerationStructureBuilder()
|
|
||||||
.Type(VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR)
|
|
||||||
.Buffer(tlAccelStructBuffer.get(), sizeInfo.accelerationStructureSize)
|
|
||||||
.DebugName("tlAccelStruct")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
tlScratchBuffer = BufferBuilder()
|
|
||||||
.Usage(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
|
|
||||||
.Size(sizeInfo.buildScratchSize)
|
|
||||||
.DebugName("tlScratchBuffer")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
buildInfo.dstAccelerationStructure = tlAccelStruct->accelstruct;
|
|
||||||
buildInfo.scratchData.deviceAddress = tlScratchBuffer->GetDeviceAddress();
|
|
||||||
rangeInfo.primitiveCount = maxInstanceCount;
|
|
||||||
|
|
||||||
cmdbuffer->buildAccelerationStructures(1, &buildInfo, rangeInfos);
|
|
||||||
|
|
||||||
PipelineBarrier()
|
|
||||||
.AddMemory(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR)
|
|
||||||
.Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPURaytracer2::CreateShaders()
|
|
||||||
{
|
|
||||||
vertShader = ShaderBuilder()
|
|
||||||
.VertexShader(glsl_vert)
|
|
||||||
.DebugName("vertShader")
|
|
||||||
.Create("vertShader", device.get());
|
|
||||||
|
|
||||||
fragShader = ShaderBuilder()
|
|
||||||
.FragmentShader(glsl_frag)
|
|
||||||
.DebugName("fragShader")
|
|
||||||
.Create("fragShader", device.get());
|
|
||||||
|
|
||||||
fragResolveShader = ShaderBuilder()
|
|
||||||
.FragmentShader(glsl_frag_resolve)
|
|
||||||
.DebugName("fragResolveShader")
|
|
||||||
.Create("fragResolveShader", device.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPURaytracer2::CreateRaytracePipeline()
|
|
||||||
{
|
|
||||||
raytrace.descriptorSetLayout = DescriptorSetLayoutBuilder()
|
|
||||||
.AddBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_FRAGMENT_BIT)
|
|
||||||
.AddBinding(1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT)
|
|
||||||
.AddBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT)
|
|
||||||
.AddBinding(3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT)
|
|
||||||
.AddBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT)
|
|
||||||
.DebugName("raytrace.descriptorSetLayout")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
raytrace.pipelineLayout = PipelineLayoutBuilder()
|
|
||||||
.AddSetLayout(raytrace.descriptorSetLayout.get())
|
|
||||||
.AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstants2))
|
|
||||||
.DebugName("raytrace.pipelineLayout")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
raytrace.renderPass = RenderPassBuilder()
|
|
||||||
.AddAttachment(
|
|
||||||
VK_FORMAT_R16G16B16A16_SFLOAT,
|
|
||||||
VK_SAMPLE_COUNT_4_BIT,
|
|
||||||
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
|
||||||
VK_ATTACHMENT_STORE_OP_STORE,
|
|
||||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
|
||||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
|
|
||||||
.AddSubpass()
|
|
||||||
.AddSubpassColorAttachmentRef(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
|
|
||||||
.AddExternalSubpassDependency(
|
|
||||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
||||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
||||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
||||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT)
|
|
||||||
.DebugName("raytrace.renderpass")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
raytrace.pipeline = GraphicsPipelineBuilder()
|
|
||||||
.Layout(raytrace.pipelineLayout.get())
|
|
||||||
.RenderPass(raytrace.renderPass.get())
|
|
||||||
.AddVertexShader(vertShader.get())
|
|
||||||
.AddFragmentShader(fragShader.get())
|
|
||||||
.AddVertexBufferBinding(0, sizeof(SceneVertex))
|
|
||||||
.AddVertexAttribute(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(SceneVertex, Position))
|
|
||||||
.Topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN)
|
|
||||||
.AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT)
|
|
||||||
.RasterizationSamples(VK_SAMPLE_COUNT_4_BIT)
|
|
||||||
.Viewport(0.0f, 0.0f, 0.0f, 0.0f)
|
|
||||||
.Scissor(0, 0, 4096, 4096)
|
|
||||||
.DebugName("raytrace.pipeline")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
raytrace.descriptorPool = DescriptorPoolBuilder()
|
|
||||||
.AddPoolSize(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1)
|
|
||||||
.AddPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1)
|
|
||||||
.AddPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3)
|
|
||||||
.MaxSets(1)
|
|
||||||
.DebugName("raytrace.descriptorPool")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
raytrace.descriptorSet = raytrace.descriptorPool->allocate(raytrace.descriptorSetLayout.get());
|
|
||||||
raytrace.descriptorSet->SetDebugName("raytrace.descriptorSet");
|
|
||||||
|
|
||||||
WriteDescriptors()
|
|
||||||
.AddAccelerationStructure(raytrace.descriptorSet.get(), 0, tlAccelStruct.get())
|
|
||||||
.AddBuffer(raytrace.descriptorSet.get(), 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uniformBuffer.get(), 0, sizeof(Uniforms2))
|
|
||||||
.AddBuffer(raytrace.descriptorSet.get(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, surfaceIndexBuffer.get())
|
|
||||||
.AddBuffer(raytrace.descriptorSet.get(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, surfaceBuffer.get())
|
|
||||||
.AddBuffer(raytrace.descriptorSet.get(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, sceneLightBuffer.get())
|
|
||||||
.Execute(device.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPURaytracer2::CreateResolvePipeline()
|
|
||||||
{
|
|
||||||
resolve.descriptorSetLayout = DescriptorSetLayoutBuilder()
|
|
||||||
.AddBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT)
|
|
||||||
.DebugName("resolve.descriptorSetLayout")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
resolve.pipelineLayout = PipelineLayoutBuilder()
|
|
||||||
.AddSetLayout(resolve.descriptorSetLayout.get())
|
|
||||||
.AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(PushConstants2))
|
|
||||||
.DebugName("resolve.pipelineLayout")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
resolve.renderPass = RenderPassBuilder()
|
|
||||||
.AddAttachment(
|
|
||||||
VK_FORMAT_R16G16B16A16_SFLOAT,
|
|
||||||
VK_SAMPLE_COUNT_1_BIT,
|
|
||||||
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
|
||||||
VK_ATTACHMENT_STORE_OP_STORE,
|
|
||||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
|
||||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
|
|
||||||
.AddSubpass()
|
|
||||||
.AddSubpassColorAttachmentRef(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
|
|
||||||
.AddExternalSubpassDependency(
|
|
||||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
||||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
||||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
||||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT)
|
|
||||||
.DebugName("resolve.renderpass")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
resolve.pipeline = GraphicsPipelineBuilder()
|
|
||||||
.Layout(resolve.pipelineLayout.get())
|
|
||||||
.RenderPass(resolve.renderPass.get())
|
|
||||||
.AddVertexShader(vertShader.get())
|
|
||||||
.AddFragmentShader(fragResolveShader.get())
|
|
||||||
.AddVertexBufferBinding(0, sizeof(SceneVertex))
|
|
||||||
.AddVertexAttribute(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(SceneVertex, Position))
|
|
||||||
.Topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN)
|
|
||||||
.AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT)
|
|
||||||
.Viewport(0.0f, 0.0f, 0.0f, 0.0f)
|
|
||||||
.Scissor(0, 0, 4096, 4096)
|
|
||||||
.DebugName("resolve.pipeline")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
resolve.descriptorPool = DescriptorPoolBuilder()
|
|
||||||
.AddPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 256)
|
|
||||||
.MaxSets(256)
|
|
||||||
.DebugName("resolve.descriptorPool")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
resolve.sampler = SamplerBuilder()
|
|
||||||
.DebugName("resolve.Sampler")
|
|
||||||
.Create(device.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
LightmapImage GPURaytracer2::CreateImage(int width, int height)
|
|
||||||
{
|
|
||||||
LightmapImage img;
|
|
||||||
|
|
||||||
img.raytrace.Image = ImageBuilder()
|
|
||||||
.Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)
|
|
||||||
.Format(VK_FORMAT_R16G16B16A16_SFLOAT)
|
|
||||||
.Size(width, height)
|
|
||||||
.Samples(VK_SAMPLE_COUNT_4_BIT)
|
|
||||||
.DebugName("LightmapImage.raytrace.Image")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
img.raytrace.View = ImageViewBuilder()
|
|
||||||
.Image(img.raytrace.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT)
|
|
||||||
.DebugName("LightmapImage.raytrace.View")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
img.raytrace.Framebuffer = FramebufferBuilder()
|
|
||||||
.RenderPass(raytrace.renderPass.get())
|
|
||||||
.Size(width, height)
|
|
||||||
.AddAttachment(img.raytrace.View.get())
|
|
||||||
.DebugName("LightmapImage.raytrace.Framebuffer")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
img.resolve.Image = ImageBuilder()
|
|
||||||
.Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)
|
|
||||||
.Format(VK_FORMAT_R16G16B16A16_SFLOAT)
|
|
||||||
.Size(width, height)
|
|
||||||
.DebugName("LightmapImage.resolve.Image")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
img.resolve.View = ImageViewBuilder()
|
|
||||||
.Image(img.resolve.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT)
|
|
||||||
.DebugName("LightmapImage.resolve.View")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
img.resolve.Framebuffer = FramebufferBuilder()
|
|
||||||
.RenderPass(resolve.renderPass.get())
|
|
||||||
.Size(width, height)
|
|
||||||
.AddAttachment(img.resolve.View.get())
|
|
||||||
.DebugName("LightmapImage.resolve.Framebuffer")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
img.Transfer = BufferBuilder()
|
|
||||||
.Size(width * height * sizeof(vec4))
|
|
||||||
.Usage(VK_IMAGE_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_CPU_ONLY)
|
|
||||||
.DebugName("LightmapImage.Transfer")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
return img;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPURaytracer2::CreateUniformBuffer()
|
|
||||||
{
|
|
||||||
VkDeviceSize align = device->physicalDevice.properties.limits.minUniformBufferOffsetAlignment;
|
|
||||||
uniformStructStride = (sizeof(Uniforms2) + align - 1) / align * align;
|
|
||||||
|
|
||||||
uniformBuffer = BufferBuilder()
|
|
||||||
.Usage(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
|
||||||
.Size(uniformStructs * uniformStructStride)
|
|
||||||
.DebugName("uniformBuffer")
|
|
||||||
.Create(device.get());
|
|
||||||
|
|
||||||
uniformTransferBuffer = BufferBuilder()
|
|
||||||
.Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU)
|
|
||||||
.Size(uniformStructs * uniformStructStride)
|
|
||||||
.DebugName("uniformTransferBuffer")
|
|
||||||
.Create(device.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<SurfaceInfo2> GPURaytracer2::CreateSurfaceInfo()
|
|
||||||
{
|
|
||||||
std::vector<SurfaceInfo2> surfaces;
|
|
||||||
surfaces.reserve(mesh->surfaces.size());
|
|
||||||
for (const auto& surface : mesh->surfaces)
|
|
||||||
{
|
|
||||||
SurfaceLightDef* def = nullptr;
|
|
||||||
if (surface->type >= ST_MIDDLESIDE && surface->type <= ST_LOWERSIDE)
|
|
||||||
{
|
|
||||||
int lightdefidx = mesh->map->Sides[surface->typeIndex].lightdef;
|
|
||||||
if (lightdefidx != -1)
|
|
||||||
{
|
|
||||||
def = &mesh->map->SurfaceLights[lightdefidx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (surface->type == ST_FLOOR || surface->type == ST_CEILING)
|
|
||||||
{
|
|
||||||
MapSubsectorEx* sub = &mesh->map->GLSubsectors[surface->typeIndex];
|
|
||||||
IntSector* sector = mesh->map->GetSectorFromSubSector(sub);
|
|
||||||
|
|
||||||
if (sector && surface->verts.size() > 0)
|
|
||||||
{
|
|
||||||
if (sector->floorlightdef != -1 && surface->type == ST_FLOOR)
|
|
||||||
{
|
|
||||||
def = &mesh->map->SurfaceLights[sector->floorlightdef];
|
|
||||||
}
|
|
||||||
else if (sector->ceilinglightdef != -1 && surface->type == ST_CEILING)
|
|
||||||
{
|
|
||||||
def = &mesh->map->SurfaceLights[sector->ceilinglightdef];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SurfaceInfo2 info;
|
|
||||||
info.Sky = surface->bSky ? 1.0f : 0.0f;
|
|
||||||
info.Normal = surface->plane.Normal();
|
|
||||||
if (def)
|
|
||||||
{
|
|
||||||
info.EmissiveDistance = def->distance + def->distance;
|
|
||||||
info.EmissiveIntensity = def->intensity;
|
|
||||||
info.EmissiveColor = def->rgb;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
info.EmissiveDistance = 0.0f;
|
|
||||||
info.EmissiveIntensity = 0.0f;
|
|
||||||
info.EmissiveColor = vec3(0.0f, 0.0f, 0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
info.SamplingDistance = float(surface->sampleDimension);
|
|
||||||
surfaces.push_back(info);
|
|
||||||
}
|
|
||||||
return surfaces;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPURaytracer2::PrintVulkanInfo()
|
|
||||||
{
|
|
||||||
const auto& props = device->physicalDevice.properties;
|
|
||||||
|
|
||||||
std::string deviceType;
|
|
||||||
switch (props.deviceType)
|
|
||||||
{
|
|
||||||
case VK_PHYSICAL_DEVICE_TYPE_OTHER: deviceType = "other"; break;
|
|
||||||
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: deviceType = "integrated gpu"; break;
|
|
||||||
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: deviceType = "discrete gpu"; break;
|
|
||||||
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: deviceType = "virtual gpu"; break;
|
|
||||||
case VK_PHYSICAL_DEVICE_TYPE_CPU: deviceType = "cpu"; break;
|
|
||||||
default: deviceType = std::to_string(props.deviceType); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string apiVersion = std::to_string(VK_VERSION_MAJOR(props.apiVersion)) + "." + std::to_string(VK_VERSION_MINOR(props.apiVersion)) + "." + std::to_string(VK_VERSION_PATCH(props.apiVersion));
|
|
||||||
std::string driverVersion = std::to_string(VK_VERSION_MAJOR(props.driverVersion)) + "." + std::to_string(VK_VERSION_MINOR(props.driverVersion)) + "." + std::to_string(VK_VERSION_PATCH(props.driverVersion));
|
|
||||||
|
|
||||||
printf("Vulkan device: %s\n", props.deviceName);
|
|
||||||
printf("Vulkan device type: %s\n", deviceType.c_str());
|
|
||||||
printf("Vulkan version: %s (api) %s (driver)\n", apiVersion.c_str(), driverVersion.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GPURaytracer2::IsNegativelyOriented(const vec2& v1, const vec2& v2, const vec2& v3)
|
|
||||||
{
|
|
||||||
float A =
|
|
||||||
v1.x * v2.y - v2.x * v1.y +
|
|
||||||
v2.x * v3.y - v3.x * v2.y +
|
|
||||||
v3.x * v1.y - v1.x * v3.y;
|
|
||||||
return A < 0.0f;
|
|
||||||
}
|
|
|
@ -1,187 +0,0 @@
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "vulkandevice.h"
|
|
||||||
#include "vulkanobjects.h"
|
|
||||||
|
|
||||||
class LevelMesh;
|
|
||||||
|
|
||||||
struct Uniforms2
|
|
||||||
{
|
|
||||||
vec3 SunDir;
|
|
||||||
float Padding1;
|
|
||||||
vec3 SunColor;
|
|
||||||
float SunIntensity;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PushConstants2
|
|
||||||
{
|
|
||||||
uint32_t LightStart;
|
|
||||||
uint32_t LightEnd;
|
|
||||||
int32_t SurfaceIndex;
|
|
||||||
int32_t PushPadding1;
|
|
||||||
vec3 LightmapOrigin;
|
|
||||||
float PushPadding2;
|
|
||||||
vec3 LightmapStepX;
|
|
||||||
float PushPadding3;
|
|
||||||
vec3 LightmapStepY;
|
|
||||||
float PushPadding4;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SurfaceInfo2
|
|
||||||
{
|
|
||||||
vec3 Normal;
|
|
||||||
float EmissiveDistance;
|
|
||||||
vec3 EmissiveColor;
|
|
||||||
float EmissiveIntensity;
|
|
||||||
float Sky;
|
|
||||||
float SamplingDistance;
|
|
||||||
float Padding1, Padding2;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LightInfo2
|
|
||||||
{
|
|
||||||
vec3 Origin;
|
|
||||||
float Padding0;
|
|
||||||
float Radius;
|
|
||||||
float Intensity;
|
|
||||||
float InnerAngleCos;
|
|
||||||
float OuterAngleCos;
|
|
||||||
vec3 SpotDir;
|
|
||||||
float Padding1;
|
|
||||||
vec3 Color;
|
|
||||||
float Padding2;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LightmapImage
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
std::unique_ptr<VulkanImage> Image;
|
|
||||||
std::unique_ptr<VulkanImageView> View;
|
|
||||||
std::unique_ptr<VulkanFramebuffer> Framebuffer;
|
|
||||||
} raytrace;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
std::unique_ptr<VulkanImage> Image;
|
|
||||||
std::unique_ptr<VulkanImageView> View;
|
|
||||||
std::unique_ptr<VulkanFramebuffer> Framebuffer;
|
|
||||||
} resolve;
|
|
||||||
|
|
||||||
std::unique_ptr<VulkanBuffer> Transfer;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SceneVertex
|
|
||||||
{
|
|
||||||
vec2 Position;
|
|
||||||
};
|
|
||||||
|
|
||||||
class GPURaytracer2
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GPURaytracer2();
|
|
||||||
~GPURaytracer2();
|
|
||||||
|
|
||||||
void Raytrace(LevelMesh* level);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void CreateVulkanObjects();
|
|
||||||
void CreateVertexAndIndexBuffers();
|
|
||||||
void CreateBottomLevelAccelerationStructure();
|
|
||||||
void CreateTopLevelAccelerationStructure();
|
|
||||||
void CreateShaders();
|
|
||||||
void CreateRaytracePipeline();
|
|
||||||
void CreateResolvePipeline();
|
|
||||||
void CreateUniformBuffer();
|
|
||||||
void CreateSceneVertexBuffer();
|
|
||||||
void CreateSceneLightBuffer();
|
|
||||||
|
|
||||||
void UploadUniforms();
|
|
||||||
void CreateAtlasImages();
|
|
||||||
void RenderAtlasImage(size_t pageIndex);
|
|
||||||
void ResolveAtlasImage(size_t pageIndex);
|
|
||||||
void DownloadAtlasImage(size_t pageIndex);
|
|
||||||
|
|
||||||
LightmapImage CreateImage(int width, int height);
|
|
||||||
|
|
||||||
void BeginCommands();
|
|
||||||
void FinishCommands();
|
|
||||||
|
|
||||||
void PrintVulkanInfo();
|
|
||||||
|
|
||||||
std::vector<SurfaceInfo2> CreateSurfaceInfo();
|
|
||||||
|
|
||||||
static vec2 ToUV(const vec3& vert, const Surface* targetSurface);
|
|
||||||
static bool IsNegativelyOriented(const vec2& v1, const vec2& v2, const vec2& v3);
|
|
||||||
|
|
||||||
LevelMesh* mesh = nullptr;
|
|
||||||
|
|
||||||
uint8_t* mappedUniforms = nullptr;
|
|
||||||
int uniformsIndex = 0;
|
|
||||||
int uniformStructs = 256;
|
|
||||||
VkDeviceSize uniformStructStride = sizeof(Uniforms2);
|
|
||||||
|
|
||||||
std::unique_ptr<VulkanDevice> device;
|
|
||||||
|
|
||||||
static const int SceneVertexBufferSize = 1 * 1024 * 1024;
|
|
||||||
std::unique_ptr<VulkanBuffer> sceneVertexBuffer;
|
|
||||||
SceneVertex* sceneVertices = nullptr;
|
|
||||||
int sceneVertexPos = 0;
|
|
||||||
|
|
||||||
static const int SceneLightBufferSize = 2 * 1024 * 1024;
|
|
||||||
std::unique_ptr<VulkanBuffer> sceneLightBuffer;
|
|
||||||
LightInfo2* sceneLights = nullptr;
|
|
||||||
int sceneLightPos = 0;
|
|
||||||
|
|
||||||
std::unique_ptr<VulkanBuffer> vertexBuffer;
|
|
||||||
std::unique_ptr<VulkanBuffer> indexBuffer;
|
|
||||||
std::unique_ptr<VulkanBuffer> transferBuffer;
|
|
||||||
std::unique_ptr<VulkanBuffer> surfaceIndexBuffer;
|
|
||||||
std::unique_ptr<VulkanBuffer> surfaceBuffer;
|
|
||||||
|
|
||||||
std::unique_ptr<VulkanBuffer> blScratchBuffer;
|
|
||||||
std::unique_ptr<VulkanBuffer> blAccelStructBuffer;
|
|
||||||
std::unique_ptr<VulkanAccelerationStructure> blAccelStruct;
|
|
||||||
|
|
||||||
std::unique_ptr<VulkanBuffer> tlTransferBuffer;
|
|
||||||
std::unique_ptr<VulkanBuffer> tlScratchBuffer;
|
|
||||||
std::unique_ptr<VulkanBuffer> tlInstanceBuffer;
|
|
||||||
std::unique_ptr<VulkanBuffer> tlAccelStructBuffer;
|
|
||||||
std::unique_ptr<VulkanAccelerationStructure> tlAccelStruct;
|
|
||||||
|
|
||||||
std::unique_ptr<VulkanShader> vertShader;
|
|
||||||
std::unique_ptr<VulkanShader> fragShader;
|
|
||||||
std::unique_ptr<VulkanShader> fragResolveShader;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
std::unique_ptr<VulkanDescriptorSetLayout> descriptorSetLayout;
|
|
||||||
std::unique_ptr<VulkanPipelineLayout> pipelineLayout;
|
|
||||||
std::unique_ptr<VulkanPipeline> pipeline;
|
|
||||||
std::unique_ptr<VulkanRenderPass> renderPass;
|
|
||||||
std::unique_ptr<VulkanDescriptorPool> descriptorPool;
|
|
||||||
std::unique_ptr<VulkanDescriptorSet> descriptorSet;
|
|
||||||
} raytrace;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
std::unique_ptr<VulkanDescriptorSetLayout> descriptorSetLayout;
|
|
||||||
std::unique_ptr<VulkanPipelineLayout> pipelineLayout;
|
|
||||||
std::unique_ptr<VulkanPipeline> pipeline;
|
|
||||||
std::unique_ptr<VulkanRenderPass> renderPass;
|
|
||||||
std::unique_ptr<VulkanDescriptorPool> descriptorPool;
|
|
||||||
std::vector<std::unique_ptr<VulkanDescriptorSet>> descriptorSets;
|
|
||||||
std::unique_ptr<VulkanSampler> sampler;
|
|
||||||
} resolve;
|
|
||||||
|
|
||||||
std::unique_ptr<VulkanBuffer> uniformBuffer;
|
|
||||||
std::unique_ptr<VulkanBuffer> uniformTransferBuffer;
|
|
||||||
|
|
||||||
std::unique_ptr<VulkanFence> submitFence;
|
|
||||||
std::unique_ptr<VulkanCommandPool> cmdpool;
|
|
||||||
std::unique_ptr<VulkanCommandBuffer> cmdbuffer;
|
|
||||||
|
|
||||||
std::vector<LightmapImage> atlasImages;
|
|
||||||
static const int atlasImageSize = 2048;
|
|
||||||
};
|
|
Loading…
Reference in a new issue