Some initial support for doing GPU ray tracing without RTX

This commit is contained in:
Magnus Norddahl 2022-08-31 09:54:08 +02:00
parent e225118e8e
commit c80f611924
7 changed files with 151 additions and 53 deletions

View file

@ -1,9 +1,23 @@
static const char* glsl_frag = R"glsl(
#version 460
#extension GL_EXT_ray_query : require
#if defined(USE_RAYQUERY)
layout(set = 0, binding = 0) uniform accelerationStructureEXT acc;
#else
struct CollisionNode
{
vec3 center;
float padding1;
vec3 extents;
float padding2;
int left;
int right;
int element_index;
int padding3;
};
layout(set = 1, binding = 0) buffer NodeBuffer { CollisionNode nodes[]; };
layout(set = 1, binding = 1) buffer VertexBuffer { vec3 vertices[]; };
layout(set = 1, binding = 2) buffer ElementBuffer { vec3 elements[]; };
#endif
layout(set = 0, binding = 1) uniform Uniforms
{
@ -62,6 +76,10 @@ float TraceAmbientOcclusion(vec3 origin, vec3 normal);
vec2 Hammersley(uint i, uint N);
float RadicalInverse_VdC(uint bits);
bool TraceAnyHit(vec3 origin, float tmin, vec3 dir, float tmax);
int TraceFirstHitTriangle(vec3 origin, float tmin, vec3 dir, float tmax);
int TraceFirstHitTriangleT(vec3 origin, float tmin, vec3 dir, float tmax, out float t);
void main()
{
vec3 normal = surfaces[SurfaceIndex].Normal;
@ -105,12 +123,7 @@ vec3 TraceLight(vec3 origin, vec3 normal, LightInfo light)
float attenuation = distAttenuation * angleAttenuation * spotAttenuation;
if (attenuation > 0.0)
{
rayQueryEXT rayQuery;
rayQueryInitializeEXT(rayQuery, acc, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF, origin, minDistance, dir, dist);
while(rayQueryProceedEXT(rayQuery)) { }
if (rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT)
if (TraceAnyHit(origin, minDistance, dir, dist))
{
incoming.rgb += light.Color * (attenuation * light.Intensity);
}
@ -125,20 +138,9 @@ vec3 TraceSunLight(vec3 origin)
vec3 incoming = vec3(0.0);
const float dist = 32768.0;
rayQueryEXT rayQuery;
rayQueryInitializeEXT(rayQuery, acc, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF, origin, minDistance, SunDir, dist);
while(rayQueryProceedEXT(rayQuery))
int primitiveID = TraceFirstHitTriangle(origin, minDistance, SunDir, dist);
if (primitiveID != -1)
{
if (rayQueryGetIntersectionTypeEXT(rayQuery, false) == gl_RayQueryCommittedIntersectionTriangleEXT)
{
rayQueryConfirmIntersectionEXT(rayQuery);
}
}
if (rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionTriangleEXT)
{
int primitiveID = rayQueryGetIntersectionPrimitiveIndexEXT(rayQuery, true);
SurfaceInfo surface = surfaces[surfaceIndices[primitiveID]];
incoming.rgb += SunColor * SunIntensity * surface.Sky;
}
@ -163,24 +165,13 @@ float TraceAmbientOcclusion(vec3 origin, vec3 normal)
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;
rayQueryEXT rayQuery;
rayQueryInitializeEXT(rayQuery, acc, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF, origin, minDistance, L, aoDistance);
while(rayQueryProceedEXT(rayQuery))
float hitDistance;
int primitiveID = TraceFirstHitTriangleT(origin, minDistance, L, aoDistance, hitDistance);
if (primitiveID != -1)
{
if (rayQueryGetIntersectionTypeEXT(rayQuery, false) == gl_RayQueryCommittedIntersectionTriangleEXT)
{
rayQueryConfirmIntersectionEXT(rayQuery);
}
}
if (rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionTriangleEXT)
{
int primitiveID = rayQueryGetIntersectionPrimitiveIndexEXT(rayQuery, true);
SurfaceInfo surface = surfaces[surfaceIndices[primitiveID]];
if (surface.Sky == 0.0)
{
float hitDistance = rayQueryGetIntersectionTEXT(rayQuery, true);
ambience += clamp(hitDistance / aoDistance, 0.0, 1.0);
}
}
@ -207,4 +198,84 @@ float RadicalInverse_VdC(uint bits)
return float(bits) * 2.3283064365386963e-10f; // / 0x100000000
}
#if defined(USE_RAYQUERY)
bool TraceAnyHit(vec3 origin, float tmin, vec3 dir, float tmax)
{
rayQueryEXT rayQuery;
rayQueryInitializeEXT(rayQuery, acc, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF, origin, tmin, dir, tmax);
while(rayQueryProceedEXT(rayQuery)) { }
return rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT;
}
int TraceFirstHitTriangle(vec3 origin, float tmin, vec3 dir, float tmax)
{
rayQueryEXT rayQuery;
rayQueryInitializeEXT(rayQuery, acc, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF, origin, tmin, dir, tmax);
while(rayQueryProceedEXT(rayQuery))
{
if (rayQueryGetIntersectionTypeEXT(rayQuery, false) == gl_RayQueryCommittedIntersectionTriangleEXT)
{
rayQueryConfirmIntersectionEXT(rayQuery);
}
}
if (rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionTriangleEXT)
{
return rayQueryGetIntersectionPrimitiveIndexEXT(rayQuery, true);
}
else
{
return -1;
}
}
int TraceFirstHitTriangleT(vec3 origin, float tmin, vec3 dir, float tmax, out float t)
{
rayQueryEXT rayQuery;
rayQueryInitializeEXT(rayQuery, acc, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF, origin, tmin, dir, tmax);
while(rayQueryProceedEXT(rayQuery))
{
if (rayQueryGetIntersectionTypeEXT(rayQuery, false) == gl_RayQueryCommittedIntersectionTriangleEXT)
{
rayQueryConfirmIntersectionEXT(rayQuery);
}
}
if (rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionTriangleEXT)
{
t = rayQueryGetIntersectionTEXT(rayQuery, true);
return rayQueryGetIntersectionPrimitiveIndexEXT(rayQuery, true);
}
else
{
return -1;
}
}
#else
bool TraceAnyHit(vec3 origin, float tmin, vec3 dir, float tmax)
{
// To do: port TriangleMeshShape::find_any_hit(TriangleMeshShape *shape, const vec3 &ray_start, const vec3 &ray_end) to glsl
return false;
}
int TraceFirstHitTriangle(vec3 origin, float tmin, vec3 dir, float tmax)
{
float t;
return TraceFirstHitTriangleT(origin, tmin, dir, tmax, t);
}
int TraceFirstHitTriangleT(vec3 origin, float tmin, vec3 dir, float tmax, out float t)
{
// To do: port TriangleMeshShape::find_first_hit(TriangleMeshShape *shape, const vec3 &ray_start, const vec3 &ray_end) to glsl
return -1;
}
#endif
)glsl";

View file

@ -1,8 +1,5 @@
static const char* glsl_frag_resolve = R"glsl(
#version 460
#extension GL_EXT_ray_query : require
layout(set = 0, binding = 0) uniform sampler2DMS tex;
layout(location = 0) in vec3 worldpos;

View file

@ -1,7 +1,5 @@
static const char* glsl_vert = R"glsl(
#version 460
layout(push_constant) uniform PushConstants
{
uint LightStart;

View file

@ -337,8 +337,15 @@ void GPURaytracer::CreateVulkanObjects()
CreateSceneLightBuffer();
CreateVertexAndIndexBuffers();
CreateUniformBuffer();
if (useRayQuery)
{
CreateBottomLevelAccelerationStructure();
CreateTopLevelAccelerationStructure();
}
else
{
// To do: upload mesh->Collision->nodes (vertices and elements are already uploaded in CreateVertexAndIndexBuffers)
}
CreateShaders();
CreateRaytracePipeline();
CreateResolvePipeline();
@ -429,8 +436,9 @@ void GPURaytracer::CreateVertexAndIndexBuffers()
.Usage(
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFER_DST_BIT |
(useRayQuery ?
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR : 0) |
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
.Size(vertexbuffersize)
.DebugName("vertexBuffer")
@ -440,8 +448,9 @@ void GPURaytracer::CreateVertexAndIndexBuffers()
.Usage(
VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFER_DST_BIT |
(useRayQuery ?
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR : 0) |
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
.Size(indexbuffersize)
.DebugName("indexBuffer")
@ -479,7 +488,7 @@ void GPURaytracer::CreateVertexAndIndexBuffers()
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);
.Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, useRayQuery ? VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
}
void GPURaytracer::CreateBottomLevelAccelerationStructure()
@ -623,24 +632,35 @@ void GPURaytracer::CreateTopLevelAccelerationStructure()
void GPURaytracer::CreateShaders()
{
FString prefix = "#version 460\r\n#line 1\r\n";
FString traceprefix = "#version 460\r\n";
if (useRayQuery) // To do: check if ray query is available
{
traceprefix += "#extension GL_EXT_ray_query : require\r\n";
traceprefix += "#define USE_RAYQUERY\r\n";
}
traceprefix += "#line 1\r\n";
vertShader = ShaderBuilder()
.VertexShader(glsl_vert)
.VertexShader(prefix + glsl_vert)
.DebugName("vertShader")
.Create("vertShader", device.get());
fragShader = ShaderBuilder()
.FragmentShader(glsl_frag)
.FragmentShader(traceprefix + glsl_frag)
.DebugName("fragShader")
.Create("fragShader", device.get());
fragResolveShader = ShaderBuilder()
.FragmentShader(glsl_frag_resolve)
.FragmentShader(prefix + glsl_frag_resolve)
.DebugName("fragResolveShader")
.Create("fragResolveShader", device.get());
}
void GPURaytracer::CreateRaytracePipeline()
{
// To do: use rayQuery boolean to specify the alternative descriptor set
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)

View file

@ -50,6 +50,18 @@ struct LightInfo
float Padding2;
};
struct CollisionNode
{
vec3 center;
float padding1;
vec3 extents;
float padding2;
int left;
int right;
int element_index;
int padding3;
};
struct LightmapImage
{
struct
@ -120,6 +132,8 @@ private:
std::unique_ptr<VulkanDevice> device;
bool useRayQuery = true;
static const int SceneVertexBufferSize = 1 * 1024 * 1024;
std::unique_ptr<VulkanBuffer> sceneVertexBuffer;
SceneVertex* sceneVertices = nullptr;

View file

@ -10,5 +10,4 @@ LightmapTexture::LightmapTexture(int width, int height) : textureWidth(width), t
#else
mPixels.resize(width * height * 3, 0);
#endif
allocBlocks.resize(width);
}

View file

@ -17,5 +17,4 @@ private:
int textureWidth;
int textureHeight;
std::vector<uint16_t> mPixels;
std::vector<int> allocBlocks;
};