Change lightmapper to only use one image
This commit is contained in:
parent
d609396e3b
commit
651b2ef9e3
6 changed files with 201 additions and 275 deletions
|
|
@ -38,6 +38,7 @@ VkLightmap::VkLightmap(VulkanRenderDevice* fb) : fb(fb)
|
|||
CreateRaytracePipeline();
|
||||
CreateResolvePipeline();
|
||||
CreateBlurPipeline();
|
||||
CreateBakeImage();
|
||||
}
|
||||
|
||||
VkLightmap::~VkLightmap()
|
||||
|
|
@ -70,38 +71,14 @@ void VkLightmap::Raytrace(const TArray<LevelMeshSurface*>& surfaces)
|
|||
lightmapRaytrace.Clock();
|
||||
lightmapRaytraceLast.ResetAndClock();
|
||||
|
||||
CreateAtlasImages(surfaces);
|
||||
|
||||
uint32_t pixels = 0;
|
||||
|
||||
for (auto& surface : surfaces)
|
||||
SelectSurfaces(surfaces);
|
||||
if (selectedSurfaces.Size() > 0)
|
||||
{
|
||||
surface->needsUpdate = false; // it may have been set to false already, but lightmapper ultimately decides so
|
||||
pixels += surface->Area();
|
||||
}
|
||||
|
||||
UploadUniforms();
|
||||
|
||||
lastSurfaceCount = surfaces.Size();
|
||||
lastPixelCount = pixels;
|
||||
totalPixelCount += pixels;
|
||||
|
||||
for (size_t pageIndex = 0; pageIndex < atlasImages.size(); pageIndex++)
|
||||
{
|
||||
if (atlasImages[pageIndex].pageMaxX && atlasImages[pageIndex].pageMaxY)
|
||||
{
|
||||
RenderAtlasImage(pageIndex, surfaces);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t pageIndex = 0; pageIndex < atlasImages.size(); pageIndex++)
|
||||
{
|
||||
if (atlasImages[pageIndex].pageMaxX && atlasImages[pageIndex].pageMaxY)
|
||||
{
|
||||
ResolveAtlasImage(pageIndex);
|
||||
BlurAtlasImage(pageIndex);
|
||||
CopyAtlasImageResult(pageIndex, surfaces);
|
||||
}
|
||||
UploadUniforms();
|
||||
RenderBakeImage();
|
||||
ResolveBakeImage();
|
||||
BlurBakeImage();
|
||||
CopyBakeImageResult();
|
||||
}
|
||||
|
||||
lightmapRaytrace.Unclock();
|
||||
|
|
@ -109,45 +86,79 @@ void VkLightmap::Raytrace(const TArray<LevelMeshSurface*>& surfaces)
|
|||
}
|
||||
}
|
||||
|
||||
void VkLightmap::RenderAtlasImage(size_t pageIndex, const TArray<LevelMeshSurface*>& surfaces)
|
||||
void VkLightmap::SelectSurfaces(const TArray<LevelMeshSurface*>& surfaces)
|
||||
{
|
||||
LightmapImage& img = atlasImages[pageIndex];
|
||||
bakeImage.maxX = 0;
|
||||
bakeImage.maxY = 0;
|
||||
selectedSurfaces.Clear();
|
||||
|
||||
// Begin with clear
|
||||
{
|
||||
auto cmdbuffer = fb->GetCommands()->GetTransferCommands();
|
||||
|
||||
RenderPassBegin()
|
||||
.RenderPass(raytrace.renderPassBegin.get())
|
||||
.RenderArea(0, 0, atlasImageSize, atlasImageSize)
|
||||
.Framebuffer(img.raytrace.Framebuffer.get())
|
||||
.AddClearColor(0.0f, 0.0f, 0.0f, 0.0f)
|
||||
.Execute(cmdbuffer);
|
||||
|
||||
VkDeviceSize offset = 0;
|
||||
cmdbuffer->bindVertexBuffers(0, 1, &vertices.Buffer->buffer, &offset);
|
||||
cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipeline.get());
|
||||
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipelineLayout.get(), 0, raytrace.descriptorSet0.get());
|
||||
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipelineLayout.get(), 1, raytrace.descriptorSet1.get());
|
||||
}
|
||||
const int spacing = 3; // Note: the spacing is here to avoid that the resolve sampler finds data from other surface tiles
|
||||
RectPacker packer(bakeImageSize, bakeImageSize, RectPacker::Spacing(spacing));
|
||||
|
||||
for (int i = 0, count = surfaces.Size(); i < count; i++)
|
||||
{
|
||||
LevelMeshSurface* targetSurface = surfaces[i];
|
||||
if (targetSurface->lightmapperAtlasPage != pageIndex)
|
||||
continue;
|
||||
LevelMeshSurface* surface = surfaces[i];
|
||||
|
||||
if (targetSurface->LightList.empty() && (targetSurface->plane.XYZ() | mesh->SunDirection) < 0.0f) // No lights, no sun //TODO fill the area with black pixels skipping blur and resolve pass
|
||||
// All surfaces needs to be updated until we rendered them.
|
||||
surface->needsUpdate = true;
|
||||
|
||||
// Only grab surfaces until our bake texture is full
|
||||
auto result = packer.insert(surface->texWidth + 2, surface->texHeight + 2);
|
||||
if (result.pageIndex == 0)
|
||||
{
|
||||
SelectedSurface selected;
|
||||
selected.Surface = surface;
|
||||
selected.X = result.pos.x + 1;
|
||||
selected.Y = result.pos.y + 1;
|
||||
selectedSurfaces.Push(selected);
|
||||
|
||||
bakeImage.maxX = std::max<uint16_t>(bakeImage.maxX, uint16_t(selected.X + surface->texWidth + spacing));
|
||||
bakeImage.maxY = std::max<uint16_t>(bakeImage.maxY, uint16_t(selected.Y + surface->texHeight + spacing));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VkLightmap::RenderBakeImage()
|
||||
{
|
||||
auto cmdbuffer = fb->GetCommands()->GetTransferCommands();
|
||||
|
||||
RenderPassBegin()
|
||||
.RenderPass(raytrace.renderPass.get())
|
||||
.RenderArea(0, 0, bakeImageSize, bakeImageSize)
|
||||
.Framebuffer(bakeImage.raytrace.Framebuffer.get())
|
||||
.AddClearColor(0.0f, 0.0f, 0.0f, 0.0f)
|
||||
.Execute(cmdbuffer);
|
||||
|
||||
VkDeviceSize offset = 0;
|
||||
cmdbuffer->bindVertexBuffers(0, 1, &vertices.Buffer->buffer, &offset);
|
||||
cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipeline.get());
|
||||
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipelineLayout.get(), 0, raytrace.descriptorSet0.get());
|
||||
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipelineLayout.get(), 1, raytrace.descriptorSet1.get());
|
||||
|
||||
lights.Pos = 0;
|
||||
vertices.Pos = 0;
|
||||
|
||||
for (int i = 0, count = selectedSurfaces.Size(); i < count; i++)
|
||||
{
|
||||
auto& selectedSurface = selectedSurfaces[i];
|
||||
LevelMeshSurface* targetSurface = selectedSurface.Surface;
|
||||
|
||||
if (targetSurface->LightList.empty() && (targetSurface->plane.XYZ() | mesh->SunDirection) < 0.0f) // No lights, no sun
|
||||
{
|
||||
selectedSurface.Rendered = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
VkViewport viewport = {};
|
||||
viewport.maxDepth = 1;
|
||||
viewport.x = (float)targetSurface->lightmapperAtlasX - 1;
|
||||
viewport.y = (float)targetSurface->lightmapperAtlasY - 1;
|
||||
viewport.x = (float)selectedSurface.X - 1;
|
||||
viewport.y = (float)selectedSurface.Y - 1;
|
||||
viewport.width = (float)(targetSurface->texWidth + 2);
|
||||
viewport.height = (float)(targetSurface->texHeight + 2);
|
||||
fb->GetCommands()->GetTransferCommands()->setViewport(0, 1, &viewport);
|
||||
|
||||
bool buffersFull = false;
|
||||
|
||||
// Paint all surfaces part of the smoothing group into the surface
|
||||
for (LevelMeshSurface* surface : mesh->SmoothingGroups[targetSurface->smoothingGroupIndex].surfaces)
|
||||
{
|
||||
|
|
@ -156,46 +167,18 @@ void VkLightmap::RenderAtlasImage(size_t pageIndex, const TArray<LevelMeshSurfac
|
|||
if (surface != targetSurface && (maxUV.X < 0.0f || maxUV.Y < 0.0f || minUV.X > 1.0f || minUV.Y > 1.0f))
|
||||
continue; // Bounding box not visible
|
||||
|
||||
int firstLight = lights.Pos;
|
||||
int firstVertex = vertices.Pos;
|
||||
int lightCount = (int)surface->LightList.size();
|
||||
int vertexCount = (int)surface->verts.Size();
|
||||
int vertexCount = surface->numVerts;
|
||||
|
||||
if (lights.Pos + lightCount > lights.BufferSize || vertices.Pos + vertexCount > vertices.BufferSize)
|
||||
{
|
||||
// Flush scene buffers
|
||||
fb->GetCommands()->GetTransferCommands()->endRenderPass();
|
||||
fb->GetCommands()->WaitForCommands(false);
|
||||
lights.Pos = 0;
|
||||
vertices.Pos = 0;
|
||||
firstLight = 0;
|
||||
firstVertex = 0;
|
||||
|
||||
// Begin without clear
|
||||
auto cmdbuffer = fb->GetCommands()->GetTransferCommands();
|
||||
|
||||
RenderPassBegin()
|
||||
.RenderPass(raytrace.renderPassContinue.get())
|
||||
.RenderArea(0, 0, atlasImageSize, atlasImageSize)
|
||||
.Framebuffer(img.raytrace.Framebuffer.get())
|
||||
.Execute(cmdbuffer);
|
||||
|
||||
VkDeviceSize offset = 0;
|
||||
cmdbuffer->bindVertexBuffers(0, 1, &vertices.Buffer->buffer, &offset);
|
||||
cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipeline.get());
|
||||
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipelineLayout.get(), 0, raytrace.descriptorSet0.get());
|
||||
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipelineLayout.get(), 1, raytrace.descriptorSet1.get());
|
||||
|
||||
cmdbuffer->setViewport(0, 1, &viewport);
|
||||
|
||||
if (lights.Pos + lightCount > lights.BufferSize)
|
||||
{
|
||||
throw std::runtime_error("SceneLightBuffer is too small!");
|
||||
}
|
||||
else if (vertices.Pos + vertexCount > vertices.BufferSize)
|
||||
{
|
||||
throw std::runtime_error("SceneVertexBuffer is too small!");
|
||||
}
|
||||
// Our vertex or light buffer is full. Postpone the rest.
|
||||
buffersFull = true;
|
||||
break;
|
||||
}
|
||||
|
||||
int firstLight = lights.Pos;
|
||||
int firstVertex = vertices.Pos;
|
||||
lights.Pos += lightCount;
|
||||
vertices.Pos += vertexCount;
|
||||
|
||||
|
|
@ -228,57 +211,29 @@ void VkLightmap::RenderAtlasImage(size_t pageIndex, const TArray<LevelMeshSurfac
|
|||
{
|
||||
for (int idx = 0; idx < vertexCount; idx++)
|
||||
{
|
||||
(vertex++)->Position = ToUV(surface->verts[idx], targetSurface);
|
||||
(vertex++)->Position = ToUV(mesh->MeshVertices[surface->startVertIndex + 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);
|
||||
(vertex++)->Position = ToUV(mesh->MeshVertices[surface->startVertIndex + 0], targetSurface);
|
||||
(vertex++)->Position = ToUV(mesh->MeshVertices[surface->startVertIndex + 2], targetSurface);
|
||||
(vertex++)->Position = ToUV(mesh->MeshVertices[surface->startVertIndex + 3], targetSurface);
|
||||
(vertex++)->Position = ToUV(mesh->MeshVertices[surface->startVertIndex + 1], targetSurface);
|
||||
}
|
||||
|
||||
fb->GetCommands()->GetTransferCommands()->draw(vertexCount, 1, firstVertex, 0);
|
||||
}
|
||||
|
||||
if (buffersFull)
|
||||
break;
|
||||
|
||||
selectedSurface.Rendered = true;
|
||||
}
|
||||
|
||||
fb->GetCommands()->GetTransferCommands()->endRenderPass();
|
||||
}
|
||||
|
||||
void VkLightmap::CreateAtlasImages(const TArray<LevelMeshSurface*>& surfaces)
|
||||
{
|
||||
for (auto& page : atlasImages)
|
||||
{
|
||||
page.pageMaxX = 0;
|
||||
page.pageMaxY = 0;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
size_t pageIndex = atlasImages.size();
|
||||
|
||||
for (int i = 0, count = surfaces.Size(); i < count; i++)
|
||||
{
|
||||
LevelMeshSurface* surface = surfaces[i];
|
||||
|
||||
auto result = packer.insert(surface->texWidth + 2, surface->texHeight + 2);
|
||||
surface->lightmapperAtlasX = result.pos.x + 1;
|
||||
surface->lightmapperAtlasY = result.pos.y + 1;
|
||||
surface->lightmapperAtlasPage = (int)result.pageIndex;
|
||||
|
||||
for (;pageIndex <= result.pageIndex; pageIndex++)
|
||||
{
|
||||
atlasImages.push_back(CreateImage(atlasImageSize, atlasImageSize));
|
||||
}
|
||||
|
||||
auto& image = atlasImages[result.pageIndex];
|
||||
image.pageMaxX = std::max<uint16_t>(image.pageMaxX, uint16_t(surface->lightmapperAtlasX + surface->texWidth + spacing));
|
||||
image.pageMaxY = std::max<uint16_t>(image.pageMaxY, uint16_t(surface->lightmapperAtlasY + surface->texHeight + spacing));
|
||||
}
|
||||
}
|
||||
|
||||
void VkLightmap::UploadUniforms()
|
||||
{
|
||||
Uniforms values = {};
|
||||
|
|
@ -297,31 +252,29 @@ void VkLightmap::UploadUniforms()
|
|||
.Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||
}
|
||||
|
||||
void VkLightmap::ResolveAtlasImage(size_t pageIndex)
|
||||
void VkLightmap::ResolveBakeImage()
|
||||
{
|
||||
LightmapImage& img = atlasImages[pageIndex];
|
||||
|
||||
auto cmdbuffer = fb->GetCommands()->GetTransferCommands();
|
||||
|
||||
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)
|
||||
.AddImage(bakeImage.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, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||
|
||||
RenderPassBegin()
|
||||
.RenderPass(resolve.renderPass.get())
|
||||
.RenderArea(0, 0, img.pageMaxX, img.pageMaxY)
|
||||
.Framebuffer(img.resolve.Framebuffer.get())
|
||||
.RenderArea(0, 0, bakeImage.maxX, bakeImage.maxY)
|
||||
.Framebuffer(bakeImage.resolve.Framebuffer.get())
|
||||
.Execute(cmdbuffer);
|
||||
|
||||
VkDeviceSize offset = 0;
|
||||
cmdbuffer->bindVertexBuffers(0, 1, &vertices.Buffer->buffer, &offset);
|
||||
cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, resolve.pipeline.get());
|
||||
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, resolve.pipelineLayout.get(), 0, img.resolve.DescriptorSet.get());
|
||||
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, resolve.pipelineLayout.get(), 0, bakeImage.resolve.DescriptorSet.get());
|
||||
|
||||
VkViewport viewport = {};
|
||||
viewport.maxDepth = 1;
|
||||
viewport.width = (float)img.pageMaxX;
|
||||
viewport.height = (float)img.pageMaxY;
|
||||
viewport.width = (float)bakeImage.maxX;
|
||||
viewport.height = (float)bakeImage.maxY;
|
||||
cmdbuffer->setViewport(0, 1, &viewport);
|
||||
|
||||
LightmapPushConstants pc;
|
||||
|
|
@ -346,33 +299,31 @@ void VkLightmap::ResolveAtlasImage(size_t pageIndex)
|
|||
cmdbuffer->endRenderPass();
|
||||
}
|
||||
|
||||
void VkLightmap::BlurAtlasImage(size_t pageIndex)
|
||||
void VkLightmap::BlurBakeImage()
|
||||
{
|
||||
LightmapImage& img = atlasImages[pageIndex];
|
||||
|
||||
auto cmdbuffer = fb->GetCommands()->GetTransferCommands();
|
||||
|
||||
PipelineBarrier()
|
||||
.AddImage(img.resolve.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)
|
||||
.AddImage(bakeImage.resolve.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, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||
|
||||
// Pass 0
|
||||
{
|
||||
RenderPassBegin()
|
||||
.RenderPass(blur.renderPass.get())
|
||||
.RenderArea(0, 0, img.pageMaxX, img.pageMaxY)
|
||||
.Framebuffer(img.blur.Framebuffer.get())
|
||||
.RenderArea(0, 0, bakeImage.maxX, bakeImage.maxY)
|
||||
.Framebuffer(bakeImage.blur.Framebuffer.get())
|
||||
.Execute(cmdbuffer);
|
||||
|
||||
VkDeviceSize offset = 0;
|
||||
cmdbuffer->bindVertexBuffers(0, 1, &vertices.Buffer->buffer, &offset);
|
||||
cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, blur.pipeline[0].get());
|
||||
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, blur.pipelineLayout.get(), 0, img.blur.DescriptorSet[0].get());
|
||||
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, blur.pipelineLayout.get(), 0, bakeImage.blur.DescriptorSet[0].get());
|
||||
|
||||
VkViewport viewport = {};
|
||||
viewport.maxDepth = 1;
|
||||
viewport.width = (float)img.pageMaxX;
|
||||
viewport.height = (float)img.pageMaxY;
|
||||
viewport.width = (float)bakeImage.maxX;
|
||||
viewport.height = (float)bakeImage.maxY;
|
||||
cmdbuffer->setViewport(0, 1, &viewport);
|
||||
|
||||
LightmapPushConstants pc;
|
||||
|
|
@ -398,26 +349,26 @@ void VkLightmap::BlurAtlasImage(size_t pageIndex)
|
|||
}
|
||||
|
||||
PipelineBarrier()
|
||||
.AddImage(img.blur.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)
|
||||
.AddImage(bakeImage.blur.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, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||
|
||||
// Pass 1 (outputs back into resolve fb)
|
||||
{
|
||||
RenderPassBegin()
|
||||
.RenderPass(blur.renderPass.get())
|
||||
.RenderArea(0, 0, img.pageMaxX, img.pageMaxY)
|
||||
.Framebuffer(img.resolve.Framebuffer.get())
|
||||
.RenderArea(0, 0, bakeImage.maxX, bakeImage.maxY)
|
||||
.Framebuffer(bakeImage.resolve.Framebuffer.get())
|
||||
.Execute(cmdbuffer);
|
||||
|
||||
VkDeviceSize offset = 0;
|
||||
cmdbuffer->bindVertexBuffers(0, 1, &vertices.Buffer->buffer, &offset);
|
||||
cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, blur.pipeline[1].get());
|
||||
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, blur.pipelineLayout.get(), 0, img.blur.DescriptorSet[1].get());
|
||||
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, blur.pipelineLayout.get(), 0, bakeImage.blur.DescriptorSet[1].get());
|
||||
|
||||
VkViewport viewport = {};
|
||||
viewport.maxDepth = 1;
|
||||
viewport.width = (float)img.pageMaxX;
|
||||
viewport.height = (float)img.pageMaxY;
|
||||
viewport.width = (float)bakeImage.maxX;
|
||||
viewport.height = (float)bakeImage.maxY;
|
||||
cmdbuffer->setViewport(0, 1, &viewport);
|
||||
|
||||
LightmapPushConstants pc;
|
||||
|
|
@ -443,47 +394,61 @@ void VkLightmap::BlurAtlasImage(size_t pageIndex)
|
|||
}
|
||||
}
|
||||
|
||||
void VkLightmap::CopyAtlasImageResult(size_t pageIndex, const TArray<LevelMeshSurface*>& surfaces)
|
||||
void VkLightmap::CopyBakeImageResult()
|
||||
{
|
||||
LightmapImage& img = atlasImages[pageIndex];
|
||||
uint32_t pixels = 0;
|
||||
|
||||
std::set<int> seenPages;
|
||||
std::vector<VkImageCopy> regions;
|
||||
for (int i = 0, count = surfaces.Size(); i < count; i++)
|
||||
for (int i = 0, count = selectedSurfaces.Size(); i < count; i++)
|
||||
{
|
||||
LevelMeshSurface* surface = surfaces[i];
|
||||
if (surface->lightmapperAtlasPage != pageIndex)
|
||||
continue;
|
||||
auto& selected = selectedSurfaces[i];
|
||||
if (selected.Rendered)
|
||||
{
|
||||
LevelMeshSurface* surface = selected.Surface;
|
||||
VkImageCopy region = {};
|
||||
region.srcOffset.x = selected.X;
|
||||
region.srcOffset.y = selected.Y;
|
||||
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.srcSubresource.layerCount = 1;
|
||||
region.dstOffset.x = surface->atlasX;
|
||||
region.dstOffset.y = surface->atlasY;
|
||||
region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.dstSubresource.layerCount = 1;
|
||||
region.dstSubresource.baseArrayLayer = surface->atlasPageIndex;
|
||||
region.extent.width = surface->texWidth;
|
||||
region.extent.height = surface->texHeight;
|
||||
region.extent.depth = 1;
|
||||
regions.push_back(region);
|
||||
seenPages.insert(surface->atlasPageIndex);
|
||||
|
||||
VkImageCopy region = {};
|
||||
region.srcOffset.x = surface->lightmapperAtlasX;
|
||||
region.srcOffset.y = surface->lightmapperAtlasY;
|
||||
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.srcSubresource.layerCount = 1;
|
||||
region.dstOffset.x = surface->atlasX;
|
||||
region.dstOffset.y = surface->atlasY;
|
||||
region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.dstSubresource.layerCount = 1;
|
||||
region.dstSubresource.baseArrayLayer = surface->atlasPageIndex;
|
||||
region.extent.width = surface->texWidth;
|
||||
region.extent.height = surface->texHeight;
|
||||
region.extent.depth = 1;
|
||||
regions.push_back(region);
|
||||
// We rendered this surface. Does not need an update anymore.
|
||||
surface->needsUpdate = false;
|
||||
|
||||
pixels += surface->Area();
|
||||
lastSurfaceCount++;
|
||||
}
|
||||
}
|
||||
|
||||
lastPixelCount = pixels;
|
||||
totalPixelCount += pixels;
|
||||
|
||||
if (!regions.empty())
|
||||
{
|
||||
auto cmdbuffer = fb->GetCommands()->GetTransferCommands();
|
||||
|
||||
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)
|
||||
.AddImage(fb->GetTextureManager()->Lightmap.Image.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, (int)pageIndex, 1)
|
||||
.Execute(cmdbuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||
PipelineBarrier barrier0;
|
||||
barrier0.AddImage(bakeImage.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);
|
||||
for (int pageIndex : seenPages)
|
||||
barrier0.AddImage(fb->GetTextureManager()->Lightmap.Image.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, pageIndex, 1);
|
||||
barrier0.Execute(cmdbuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||
|
||||
cmdbuffer->copyImage(img.resolve.Image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, fb->GetTextureManager()->Lightmap.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (uint32_t)regions.size(), regions.data());
|
||||
cmdbuffer->copyImage(bakeImage.resolve.Image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, fb->GetTextureManager()->Lightmap.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (uint32_t)regions.size(), regions.data());
|
||||
|
||||
PipelineBarrier()
|
||||
.AddImage(fb->GetTextureManager()->Lightmap.Image.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, (int)pageIndex, 1)
|
||||
.Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||
PipelineBarrier barrier1;
|
||||
for (int pageIndex : seenPages)
|
||||
barrier1.AddImage(fb->GetTextureManager()->Lightmap.Image.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, pageIndex, 1);
|
||||
barrier1.Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -584,7 +549,7 @@ void VkLightmap::CreateRaytracePipeline()
|
|||
.DebugName("raytrace.pipelineLayout")
|
||||
.Create(fb->GetDevice());
|
||||
|
||||
raytrace.renderPassBegin = RenderPassBuilder()
|
||||
raytrace.renderPass = RenderPassBuilder()
|
||||
.AddAttachment(
|
||||
VK_FORMAT_R16G16B16A16_SFLOAT,
|
||||
VK_SAMPLE_COUNT_4_BIT,
|
||||
|
|
@ -599,30 +564,12 @@ void VkLightmap::CreateRaytracePipeline()
|
|||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT)
|
||||
.DebugName("raytrace.renderPassBegin")
|
||||
.Create(fb->GetDevice());
|
||||
|
||||
raytrace.renderPassContinue = RenderPassBuilder()
|
||||
.AddAttachment(
|
||||
VK_FORMAT_R16G16B16A16_SFLOAT,
|
||||
VK_SAMPLE_COUNT_4_BIT,
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
VK_ATTACHMENT_STORE_OP_STORE,
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
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.renderPassContinue")
|
||||
.DebugName("raytrace.renderPass")
|
||||
.Create(fb->GetDevice());
|
||||
|
||||
raytrace.pipeline = GraphicsPipelineBuilder()
|
||||
.Layout(raytrace.pipelineLayout.get())
|
||||
.RenderPass(raytrace.renderPassBegin.get())
|
||||
.RenderPass(raytrace.renderPass.get())
|
||||
.AddVertexShader(shaders.vert.get())
|
||||
.AddFragmentShader(shaders.fragRaytrace.get())
|
||||
.AddVertexBufferBinding(0, sizeof(SceneVertex))
|
||||
|
|
@ -808,11 +755,12 @@ void VkLightmap::CreateBlurPipeline()
|
|||
.Create(fb->GetDevice());
|
||||
}
|
||||
|
||||
LightmapImage VkLightmap::CreateImage(int width, int height)
|
||||
void VkLightmap::CreateBakeImage()
|
||||
{
|
||||
LightmapImage img;
|
||||
int width = bakeImageSize;
|
||||
int height = bakeImageSize;
|
||||
|
||||
img.raytrace.Image = ImageBuilder()
|
||||
bakeImage.raytrace.Image = ImageBuilder()
|
||||
.Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)
|
||||
.Format(VK_FORMAT_R16G16B16A16_SFLOAT)
|
||||
.Size(width, height)
|
||||
|
|
@ -820,73 +768,71 @@ LightmapImage VkLightmap::CreateImage(int width, int height)
|
|||
.DebugName("LightmapImage.raytrace.Image")
|
||||
.Create(fb->GetDevice());
|
||||
|
||||
img.raytrace.View = ImageViewBuilder()
|
||||
.Image(img.raytrace.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT)
|
||||
bakeImage.raytrace.View = ImageViewBuilder()
|
||||
.Image(bakeImage.raytrace.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT)
|
||||
.DebugName("LightmapImage.raytrace.View")
|
||||
.Create(fb->GetDevice());
|
||||
|
||||
img.raytrace.Framebuffer = FramebufferBuilder()
|
||||
.RenderPass(raytrace.renderPassBegin.get())
|
||||
bakeImage.raytrace.Framebuffer = FramebufferBuilder()
|
||||
.RenderPass(raytrace.renderPass.get())
|
||||
.Size(width, height)
|
||||
.AddAttachment(img.raytrace.View.get())
|
||||
.AddAttachment(bakeImage.raytrace.View.get())
|
||||
.DebugName("LightmapImage.raytrace.Framebuffer")
|
||||
.Create(fb->GetDevice());
|
||||
|
||||
img.resolve.Image = ImageBuilder()
|
||||
bakeImage.resolve.Image = ImageBuilder()
|
||||
.Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)
|
||||
.Format(VK_FORMAT_R16G16B16A16_SFLOAT)
|
||||
.Size(width, height)
|
||||
.DebugName("LightmapImage.resolve.Image")
|
||||
.Create(fb->GetDevice());
|
||||
|
||||
img.resolve.View = ImageViewBuilder()
|
||||
.Image(img.resolve.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT)
|
||||
bakeImage.resolve.View = ImageViewBuilder()
|
||||
.Image(bakeImage.resolve.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT)
|
||||
.DebugName("LightmapImage.resolve.View")
|
||||
.Create(fb->GetDevice());
|
||||
|
||||
img.resolve.Framebuffer = FramebufferBuilder()
|
||||
bakeImage.resolve.Framebuffer = FramebufferBuilder()
|
||||
.RenderPass(resolve.renderPass.get())
|
||||
.Size(width, height)
|
||||
.AddAttachment(img.resolve.View.get())
|
||||
.AddAttachment(bakeImage.resolve.View.get())
|
||||
.DebugName("LightmapImage.resolve.Framebuffer")
|
||||
.Create(fb->GetDevice());
|
||||
|
||||
img.resolve.DescriptorSet = resolve.descriptorPool->allocate(resolve.descriptorSetLayout.get());
|
||||
img.resolve.DescriptorSet->SetDebugName("resolve.descriptorSet");
|
||||
bakeImage.resolve.DescriptorSet = resolve.descriptorPool->allocate(resolve.descriptorSetLayout.get());
|
||||
bakeImage.resolve.DescriptorSet->SetDebugName("resolve.descriptorSet");
|
||||
|
||||
|
||||
img.blur.Image = ImageBuilder()
|
||||
bakeImage.blur.Image = ImageBuilder()
|
||||
.Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)
|
||||
.Format(VK_FORMAT_R16G16B16A16_SFLOAT)
|
||||
.Size(width, height)
|
||||
.DebugName("LightmapImage.blur.Image")
|
||||
.Create(fb->GetDevice());
|
||||
|
||||
img.blur.View = ImageViewBuilder()
|
||||
.Image(img.blur.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT)
|
||||
bakeImage.blur.View = ImageViewBuilder()
|
||||
.Image(bakeImage.blur.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT)
|
||||
.DebugName("LightmapImage.blur.View")
|
||||
.Create(fb->GetDevice());
|
||||
|
||||
img.blur.Framebuffer = FramebufferBuilder()
|
||||
bakeImage.blur.Framebuffer = FramebufferBuilder()
|
||||
.RenderPass(blur.renderPass.get())
|
||||
.Size(width, height)
|
||||
.AddAttachment(img.blur.View.get())
|
||||
.AddAttachment(bakeImage.blur.View.get())
|
||||
.DebugName("LightmapImage.blur.Framebuffer")
|
||||
.Create(fb->GetDevice());
|
||||
|
||||
img.blur.DescriptorSet[0] = blur.descriptorPool->allocate(blur.descriptorSetLayout.get());
|
||||
img.blur.DescriptorSet[0]->SetDebugName("blur.descriptorSet");
|
||||
bakeImage.blur.DescriptorSet[0] = blur.descriptorPool->allocate(blur.descriptorSetLayout.get());
|
||||
bakeImage.blur.DescriptorSet[0]->SetDebugName("blur.descriptorSet");
|
||||
|
||||
img.blur.DescriptorSet[1] = blur.descriptorPool->allocate(blur.descriptorSetLayout.get());
|
||||
img.blur.DescriptorSet[1]->SetDebugName("blur.descriptorSet");
|
||||
bakeImage.blur.DescriptorSet[1] = blur.descriptorPool->allocate(blur.descriptorSetLayout.get());
|
||||
bakeImage.blur.DescriptorSet[1]->SetDebugName("blur.descriptorSet");
|
||||
|
||||
WriteDescriptors()
|
||||
.AddCombinedImageSampler(img.resolve.DescriptorSet.get(), 0, img.raytrace.View.get(), resolve.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
.AddCombinedImageSampler(img.blur.DescriptorSet[0].get(), 0, img.resolve.View.get(), blur.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
.AddCombinedImageSampler(img.blur.DescriptorSet[1].get(), 0, img.blur.View.get(), blur.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
.AddCombinedImageSampler(bakeImage.resolve.DescriptorSet.get(), 0, bakeImage.raytrace.View.get(), resolve.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
.AddCombinedImageSampler(bakeImage.blur.DescriptorSet[0].get(), 0, bakeImage.resolve.View.get(), blur.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
.AddCombinedImageSampler(bakeImage.blur.DescriptorSet[1].get(), 0, bakeImage.blur.View.get(), blur.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
.Execute(fb->GetDevice());
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
void VkLightmap::CreateUniformBuffer()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue