Only process lights within range of a surface

This commit is contained in:
Magnus Norddahl 2022-08-17 16:10:10 +02:00
parent f6f11af04a
commit c53ebe8121
6 changed files with 135 additions and 46 deletions

View file

@ -68,6 +68,13 @@ bool TriangleMeshShape::find_any_hit(TriangleMeshShape *shape1, SphereShape *sha
return find_any_hit(shape1, shape2, shape1->root); return find_any_hit(shape1, shape2, shape1->root);
} }
std::vector<int> TriangleMeshShape::find_all_hits(TriangleMeshShape* shape1, SphereShape* shape2)
{
std::vector<int> hits;
find_all_hits(shape1, shape2, shape1->root, hits);
return hits;
}
bool TriangleMeshShape::find_any_hit(TriangleMeshShape *shape, const vec3 &ray_start, const vec3 &ray_end) bool TriangleMeshShape::find_any_hit(TriangleMeshShape *shape, const vec3 &ray_start, const vec3 &ray_end)
{ {
return find_any_hit(shape, RayBBox(ray_start, ray_end), shape->root); return find_any_hit(shape, RayBBox(ray_start, ray_end), shape->root);
@ -133,6 +140,25 @@ bool TriangleMeshShape::find_any_hit(TriangleMeshShape *shape1, SphereShape *sha
return false; return false;
} }
void TriangleMeshShape::find_all_hits(TriangleMeshShape* shape1, SphereShape* shape2, int a, std::vector<int>& hits)
{
if (overlap_bv_sphere(shape1, shape2, a))
{
if (shape1->is_leaf(a))
{
if (overlap_triangle_sphere(shape1, shape2, a))
{
hits.push_back(shape1->nodes[a].element_index / 3);
}
}
else
{
find_all_hits(shape1, shape2, shape1->nodes[a].left, hits);
find_all_hits(shape1, shape2, shape1->nodes[a].right, hits);
}
}
}
bool TriangleMeshShape::find_any_hit(TriangleMeshShape *shape1, TriangleMeshShape *shape2, int a, int b) bool TriangleMeshShape::find_any_hit(TriangleMeshShape *shape1, TriangleMeshShape *shape2, int a, int b)
{ {
bool leaf_a = shape1->is_leaf(a); bool leaf_a = shape1->is_leaf(a);

View file

@ -97,6 +97,8 @@ public:
static bool find_any_hit(TriangleMeshShape *shape1, SphereShape *shape2); static bool find_any_hit(TriangleMeshShape *shape1, SphereShape *shape2);
static bool find_any_hit(TriangleMeshShape *shape, const vec3 &ray_start, const vec3 &ray_end); static bool find_any_hit(TriangleMeshShape *shape, const vec3 &ray_start, const vec3 &ray_end);
static std::vector<int> find_all_hits(TriangleMeshShape* shape1, SphereShape* shape2);
static TraceHit find_first_hit(TriangleMeshShape *shape, const vec3 &ray_start, const vec3 &ray_end); static TraceHit find_first_hit(TriangleMeshShape *shape, const vec3 &ray_start, const vec3 &ray_end);
private: private:
@ -126,6 +128,8 @@ private:
static bool find_any_hit(TriangleMeshShape *shape1, SphereShape *shape2, int a); static bool find_any_hit(TriangleMeshShape *shape1, SphereShape *shape2, int a);
static bool find_any_hit(TriangleMeshShape *shape1, const RayBBox &ray, int a); static bool find_any_hit(TriangleMeshShape *shape1, const RayBBox &ray, int a);
static void find_all_hits(TriangleMeshShape* shape1, SphereShape* shape2, int a, std::vector<int>& hits);
static void find_first_hit(TriangleMeshShape *shape1, const RayBBox &ray, int a, TraceHit *hit); static void find_first_hit(TriangleMeshShape *shape1, const RayBBox &ray, int a, TraceHit *hit);
inline static bool overlap_bv_ray(TriangleMeshShape *shape, const RayBBox &ray, int a); inline static bool overlap_bv_ray(TriangleMeshShape *shape, const RayBBox &ray, int a);

View file

@ -101,16 +101,6 @@ void GPURaytracer2::Raytrace(LevelMesh* level)
int sampleWidth = surface->texWidth; int sampleWidth = surface->texWidth;
int sampleHeight = surface->texHeight; int sampleHeight = surface->texHeight;
PushConstants2 pc;
pc.LightStart = 0;
pc.LightEnd = mesh->map->ThingLights.Size();
pc.SurfaceIndex = (int32_t)i;
pc.TileTL = vec2(0.0f);
pc.TileBR = vec2(1.0f);
pc.LightmapOrigin = surface->worldOrigin;
pc.LightmapStepX = surface->worldStepX * (float)sampleWidth;
pc.LightmapStepY = surface->worldStepY * (float)sampleHeight;
#if 1 #if 1
int firstVertex = sceneVertexPos; int firstVertex = sceneVertexPos;
int vertexCount = 4; int vertexCount = 4;
@ -133,15 +123,42 @@ void GPURaytracer2::Raytrace(LevelMesh* level)
} }
#endif #endif
int firstLight = sceneLightPos;
int lightCount = (int)surface->LightList.size();
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++;
}
VkViewport viewport = {}; VkViewport viewport = {};
viewport.maxDepth = 1; viewport.maxDepth = 1;
viewport.x = (float)surface->atlasX; viewport.x = (float)surface->atlasX;
viewport.y = (float)surface->atlasY; viewport.y = (float)surface->atlasY;
viewport.width = (float)sampleWidth; viewport.width = (float)sampleWidth;
viewport.height = (float)sampleHeight; viewport.height = (float)sampleHeight;
cmdbuffer->setViewport(0, 1, &viewport); cmdbuffer->setViewport(0, 1, &viewport);
PushConstants2 pc;
pc.LightStart = firstLight;
pc.LightEnd = firstLight + lightCount;
pc.SurfaceIndex = (int32_t)i;
pc.TileTL = vec2(0.0f);
pc.TileBR = vec2(1.0f);
pc.LightmapOrigin = surface->worldOrigin;
pc.LightmapStepX = surface->worldStepX * (float)sampleWidth;
pc.LightmapStepY = surface->worldStepY * (float)sampleHeight;
cmdbuffer->pushConstants(pipelineLayout.get(), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstants2), &pc); cmdbuffer->pushConstants(pipelineLayout.get(), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstants2), &pc);
cmdbuffer->draw(vertexCount, 1, firstVertex, 0); cmdbuffer->draw(vertexCount, 1, firstVertex, 0);
} }
cmdbuffer->endRenderPass(); cmdbuffer->endRenderPass();
@ -164,8 +181,20 @@ void GPURaytracer2::Raytrace(LevelMesh* level)
cmdbuffer->copyImageToBuffer(img.Image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, img.Transfer->buffer, 1, &region); cmdbuffer->copyImageToBuffer(img.Image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, img.Transfer->buffer, 1, &region);
} }
#ifdef WIN32
LARGE_INTEGER s;
QueryPerformanceCounter(&s);
#endif
FinishCommands(); 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++) for (size_t pageIndex = 0; pageIndex < atlasImages.size(); pageIndex++)
{ {
vec4* pixels = (vec4*)atlasImages[pageIndex].Transfer->Map(0, atlasImageSize * atlasImageSize * sizeof(vec4)); vec4* pixels = (vec4*)atlasImages[pageIndex].Transfer->Map(0, atlasImageSize * atlasImageSize * sizeof(vec4));
@ -207,6 +236,7 @@ void GPURaytracer2::CreateVulkanObjects()
BeginCommands(); BeginCommands();
CreateSceneVertexBuffer(); CreateSceneVertexBuffer();
CreateSceneLightBuffer();
CreateVertexAndIndexBuffers(); CreateVertexAndIndexBuffers();
CreateBottomLevelAccelerationStructure(); CreateBottomLevelAccelerationStructure();
CreateTopLevelAccelerationStructure(); CreateTopLevelAccelerationStructure();
@ -236,6 +266,25 @@ void GPURaytracer2::CreateSceneVertexBuffer()
sceneVertexPos = 0; 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() void GPURaytracer2::BeginCommands()
{ {
cmdbuffer = cmdpool->createBuffer(); cmdbuffer = cmdpool->createBuffer();
@ -262,19 +311,15 @@ void GPURaytracer2::FinishCommands()
void GPURaytracer2::CreateVertexAndIndexBuffers() void GPURaytracer2::CreateVertexAndIndexBuffers()
{ {
std::vector<SurfaceInfo2> surfaces = CreateSurfaceInfo(); std::vector<SurfaceInfo2> surfaces = CreateSurfaceInfo();
std::vector<LightInfo2> lights = CreateLightInfo();
if (lights.empty()) // vulkan doesn't support zero byte buffers if (surfaces.empty()) // vulkan doesn't support zero byte buffers
lights.push_back(LightInfo2());
if (surfaces.empty())
surfaces.push_back(SurfaceInfo2()); surfaces.push_back(SurfaceInfo2());
size_t vertexbuffersize = (size_t)mesh->MeshVertices.Size() * sizeof(vec3); size_t vertexbuffersize = (size_t)mesh->MeshVertices.Size() * sizeof(vec3);
size_t indexbuffersize = (size_t)mesh->MeshElements.Size() * sizeof(uint32_t); size_t indexbuffersize = (size_t)mesh->MeshElements.Size() * sizeof(uint32_t);
size_t surfaceindexbuffersize = (size_t)mesh->MeshSurfaces.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 surfacebuffersize = (size_t)surfaces.size() * sizeof(SurfaceInfo2);
size_t lightbuffersize = (size_t)lights.size() * sizeof(LightInfo2); size_t transferbuffersize = vertexbuffersize + indexbuffersize + surfaceindexbuffersize + surfacebuffersize;
size_t transferbuffersize = vertexbuffersize + indexbuffersize + surfaceindexbuffersize + surfacebuffersize + lightbuffersize;
size_t vertexoffset = 0; size_t vertexoffset = 0;
size_t indexoffset = vertexoffset + vertexbuffersize; size_t indexoffset = vertexoffset + vertexbuffersize;
size_t surfaceindexoffset = indexoffset + indexbuffersize; size_t surfaceindexoffset = indexoffset + indexbuffersize;
@ -315,12 +360,6 @@ void GPURaytracer2::CreateVertexAndIndexBuffers()
.DebugName("surfaceBuffer") .DebugName("surfaceBuffer")
.Create(device.get()); .Create(device.get());
lightBuffer = BufferBuilder()
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
.Size(lightbuffersize)
.DebugName("lightBuffer")
.Create(device.get());
transferBuffer = BufferBuilder() transferBuffer = BufferBuilder()
.Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY)
.Size(transferbuffersize) .Size(transferbuffersize)
@ -332,14 +371,12 @@ void GPURaytracer2::CreateVertexAndIndexBuffers()
memcpy(data + indexoffset, mesh->MeshElements.Data(), indexbuffersize); memcpy(data + indexoffset, mesh->MeshElements.Data(), indexbuffersize);
memcpy(data + surfaceindexoffset, mesh->MeshSurfaces.Data(), surfaceindexbuffersize); memcpy(data + surfaceindexoffset, mesh->MeshSurfaces.Data(), surfaceindexbuffersize);
memcpy(data + surfaceoffset, surfaces.data(), surfacebuffersize); memcpy(data + surfaceoffset, surfaces.data(), surfacebuffersize);
memcpy(data + lightoffset, lights.data(), lightbuffersize);
transferBuffer->Unmap(); transferBuffer->Unmap();
cmdbuffer->copyBuffer(transferBuffer.get(), vertexBuffer.get(), vertexoffset); cmdbuffer->copyBuffer(transferBuffer.get(), vertexBuffer.get(), vertexoffset);
cmdbuffer->copyBuffer(transferBuffer.get(), indexBuffer.get(), indexoffset); cmdbuffer->copyBuffer(transferBuffer.get(), indexBuffer.get(), indexoffset);
cmdbuffer->copyBuffer(transferBuffer.get(), surfaceIndexBuffer.get(), surfaceindexoffset); cmdbuffer->copyBuffer(transferBuffer.get(), surfaceIndexBuffer.get(), surfaceindexoffset);
cmdbuffer->copyBuffer(transferBuffer.get(), surfaceBuffer.get(), surfaceoffset); cmdbuffer->copyBuffer(transferBuffer.get(), surfaceBuffer.get(), surfaceoffset);
cmdbuffer->copyBuffer(transferBuffer.get(), lightBuffer.get(), lightoffset);
PipelineBarrier() PipelineBarrier()
.AddMemory(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT) .AddMemory(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT)
@ -613,7 +650,7 @@ void GPURaytracer2::CreateDescriptorSet()
.AddBuffer(descriptorSet.get(), 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uniformBuffer.get(), 0, sizeof(Uniforms2)) .AddBuffer(descriptorSet.get(), 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uniformBuffer.get(), 0, sizeof(Uniforms2))
.AddBuffer(descriptorSet.get(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, surfaceIndexBuffer.get()) .AddBuffer(descriptorSet.get(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, surfaceIndexBuffer.get())
.AddBuffer(descriptorSet.get(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, surfaceBuffer.get()) .AddBuffer(descriptorSet.get(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, surfaceBuffer.get())
.AddBuffer(descriptorSet.get(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, lightBuffer.get()) .AddBuffer(descriptorSet.get(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, sceneLightBuffer.get())
.Execute(device.get()); .Execute(device.get());
} }
@ -672,24 +709,6 @@ std::vector<SurfaceInfo2> GPURaytracer2::CreateSurfaceInfo()
return surfaces; return surfaces;
} }
std::vector<LightInfo2> GPURaytracer2::CreateLightInfo()
{
std::vector<LightInfo2> lights;
for (ThingLight& light : mesh->map->ThingLights)
{
LightInfo2 info;
info.Origin = light.LightOrigin();
info.Radius = light.LightRadius();
info.Intensity = light.intensity;
info.InnerAngleCos = light.innerAngleCos;
info.OuterAngleCos = light.outerAngleCos;
info.SpotDir = light.SpotDir();
info.Color = light.rgb;
lights.push_back(info);
}
return lights;
}
void GPURaytracer2::PrintVulkanInfo() void GPURaytracer2::PrintVulkanInfo()
{ {
const auto& props = device->physicalDevice.properties; const auto& props = device->physicalDevice.properties;

View file

@ -85,6 +85,7 @@ private:
void CreatePipeline(); void CreatePipeline();
void CreateDescriptorSet(); void CreateDescriptorSet();
void CreateSceneVertexBuffer(); void CreateSceneVertexBuffer();
void CreateSceneLightBuffer();
LightmapImage CreateImage(int width, int height); LightmapImage CreateImage(int width, int height);
@ -94,7 +95,6 @@ private:
void PrintVulkanInfo(); void PrintVulkanInfo();
std::vector<SurfaceInfo2> CreateSurfaceInfo(); std::vector<SurfaceInfo2> CreateSurfaceInfo();
std::vector<LightInfo2> CreateLightInfo();
LevelMesh* mesh = nullptr; LevelMesh* mesh = nullptr;
@ -110,12 +110,16 @@ private:
SceneVertex* sceneVertices = nullptr; SceneVertex* sceneVertices = nullptr;
int sceneVertexPos = 0; int sceneVertexPos = 0;
static const int SceneLightBufferSize = 1 * 1024 * 1024;
std::unique_ptr<VulkanBuffer> sceneLightBuffer;
LightInfo2* 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;

View file

@ -112,6 +112,35 @@ LevelMesh::LevelMesh(FLevel &doomMap, int sampleDistance, int textureSize)
{ {
BuildSurfaceParams(surfaces[i].get()); BuildSurfaceParams(surfaces[i].get());
} }
printf("Building collision data...\n\n");
Collision = std::make_unique<TriangleMeshShape>(MeshVertices.Data(), MeshVertices.Size(), MeshElements.Data(), MeshElements.Size());
printf("Building light list...\n\n");
for (ThingLight& light : map->ThingLights)
{
SphereShape sphere;
sphere.center = light.LightOrigin();
sphere.radius = light.LightRadius();
for (int triangleIndex : TriangleMeshShape::find_all_hits(Collision.get(), &sphere))
{
Surface* surface = surfaces[MeshSurfaces[triangleIndex]].get();
bool found = false;
for (ThingLight* light2 : surface->LightList)
{
if (light2 == &light)
{
found = true;
break;
}
}
if (!found)
surface->LightList.push_back(&light);
}
}
} }
// Determines a lightmap block in which to map to the lightmap texture. // Determines a lightmap block in which to map to the lightmap texture.

View file

@ -36,6 +36,7 @@
#include "framework/halffloat.h" #include "framework/halffloat.h"
#include "lightmaptexture.h" #include "lightmaptexture.h"
#include "math/mathlib.h" #include "math/mathlib.h"
#include "collision.h"
#include "dp_rect_pack/dp_rect_pack.h" #include "dp_rect_pack/dp_rect_pack.h"
@ -45,6 +46,7 @@ struct MapSubsectorEx;
struct IntSector; struct IntSector;
struct IntSideDef; struct IntSideDef;
struct FLevel; struct FLevel;
struct ThingLight;
class FWadWriter; class FWadWriter;
enum SurfaceType enum SurfaceType
@ -74,6 +76,9 @@ struct Surface
int sampleDimension = 0; int sampleDimension = 0;
bool bSky = false; bool bSky = false;
// Touching light sources
std::vector<ThingLight*> LightList;
// Lightmap world coordinates for the texture // Lightmap world coordinates for the texture
vec3 worldOrigin = { 0.0f }; vec3 worldOrigin = { 0.0f };
vec3 worldStepX = { 0.0f }; vec3 worldStepX = { 0.0f };
@ -125,6 +130,8 @@ public:
TArray<unsigned int> MeshElements; TArray<unsigned int> MeshElements;
TArray<int> MeshSurfaces; TArray<int> MeshSurfaces;
std::unique_ptr<TriangleMeshShape> Collision;
private: private:
void CreateSubsectorSurfaces(FLevel &doomMap); void CreateSubsectorSurfaces(FLevel &doomMap);
void CreateCeilingSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector *sector, int typeIndex, bool is3DFloor); void CreateCeilingSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector *sector, int typeIndex, bool is3DFloor);