Atlas tile adjustments
This commit is contained in:
parent
60cdb871d2
commit
c98930a88c
5 changed files with 63 additions and 58 deletions
|
|
@ -127,13 +127,13 @@ void LevelMesh::BuildTileSurfaceLists()
|
|||
if (surface->SectorGroup == PlaneGroups[j].sectorGroup)
|
||||
{
|
||||
float direction = PlaneGroups[j].plane.XYZ() | surface->Plane.XYZ();
|
||||
if (direction >= 0.9999f && direction <= 1.001f)
|
||||
if (direction >= 0.999f && direction <= 1.01f)
|
||||
{
|
||||
auto point = (surface->Plane.XYZ() * surface->Plane.W);
|
||||
auto planeDistance = (PlaneGroups[j].plane.XYZ() | point) - PlaneGroups[j].plane.W;
|
||||
|
||||
float dist = std::abs(planeDistance);
|
||||
if (dist <= 0.01f)
|
||||
if (dist <= 0.1f)
|
||||
{
|
||||
planeGroupIndex = (int)j;
|
||||
break;
|
||||
|
|
@ -198,18 +198,14 @@ void LevelMesh::PackLightmapAtlas(int lightmapStartIndex)
|
|||
|
||||
std::sort(sortedTiles.begin(), sortedTiles.end(), [](LightmapTile* a, LightmapTile* b) { return a->AtlasLocation.Height != b->AtlasLocation.Height ? a->AtlasLocation.Height > b->AtlasLocation.Height : a->AtlasLocation.Width > b->AtlasLocation.Width; });
|
||||
|
||||
RectPacker packer(LMTextureSize, LMTextureSize, RectPacker::Spacing(0));
|
||||
// We do not need to add spacing here as this is already built into the tile size itself.
|
||||
RectPacker packer(LMTextureSize, LMTextureSize, RectPacker::Spacing(0), RectPacker::Padding(0));
|
||||
|
||||
for (LightmapTile* tile : sortedTiles)
|
||||
{
|
||||
int sampleWidth = tile->AtlasLocation.Width;
|
||||
int sampleHeight = tile->AtlasLocation.Height;
|
||||
|
||||
auto result = packer.insert(sampleWidth, sampleHeight);
|
||||
int x = result.pos.x, y = result.pos.y;
|
||||
|
||||
tile->AtlasLocation.X = x;
|
||||
tile->AtlasLocation.Y = y;
|
||||
auto result = packer.insert(tile->AtlasLocation.Width, tile->AtlasLocation.Height);
|
||||
tile->AtlasLocation.X = result.pos.x;
|
||||
tile->AtlasLocation.Y = result.pos.y;
|
||||
tile->AtlasLocation.ArrayIndex = lightmapStartIndex + (int)result.pageIndex;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ struct LightmapTile
|
|||
FVector2 ToUV(const FVector3& vert) const
|
||||
{
|
||||
FVector3 localPos = vert - Transform.TranslateWorldToLocal;
|
||||
float u = (1.0f + (localPos | Transform.ProjLocalToU)) / (AtlasLocation.Width + 2);
|
||||
float v = (1.0f + (localPos | Transform.ProjLocalToV)) / (AtlasLocation.Height + 2);
|
||||
float u = (localPos | Transform.ProjLocalToU) / AtlasLocation.Width;
|
||||
float v = (localPos | Transform.ProjLocalToV) / AtlasLocation.Height;
|
||||
return FVector2(u, v);
|
||||
}
|
||||
|
||||
|
|
@ -101,63 +101,66 @@ struct LightmapTile
|
|||
|
||||
void SetupTileTransform(int textureSize)
|
||||
{
|
||||
BBox bounds = Bounds;
|
||||
// These calculations align the tile so that there's a one texel border around the actual surface in the tile.
|
||||
//
|
||||
// This removes sampling artifacts as a linear sampler reads from a 2x2 area.
|
||||
// The tile is also aligned to the grid to keep aliasing artifacts consistent.
|
||||
|
||||
// round off dimensions
|
||||
FVector3 roundedSize;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
bounds.min[i] = SampleDimension * (floor(bounds.min[i] / SampleDimension) - 1);
|
||||
bounds.max[i] = SampleDimension * (ceil(bounds.max[i] / SampleDimension) + 1);
|
||||
roundedSize[i] = (bounds.max[i] - bounds.min[i]) / SampleDimension;
|
||||
}
|
||||
FVector3 uvMin;
|
||||
uvMin.X = std::floor(Bounds.min.X / SampleDimension) - 1.0f;
|
||||
uvMin.Y = std::floor(Bounds.min.Y / SampleDimension) - 1.0f;
|
||||
uvMin.Z = std::floor(Bounds.min.Z / SampleDimension) - 1.0f;
|
||||
|
||||
FVector3 uvMax;
|
||||
uvMax.X = std::floor(Bounds.max.X / SampleDimension) + 2.0f;
|
||||
uvMax.Y = std::floor(Bounds.max.Y / SampleDimension) + 2.0f;
|
||||
uvMax.Z = std::floor(Bounds.max.Z / SampleDimension) + 2.0f;
|
||||
|
||||
FVector3 tCoords[2] = { FVector3(0.0f, 0.0f, 0.0f), FVector3(0.0f, 0.0f, 0.0f) };
|
||||
|
||||
PlaneAxis axis = BestAxis(Plane);
|
||||
|
||||
int width;
|
||||
int height;
|
||||
switch (axis)
|
||||
int width, height;
|
||||
switch (BestAxis(Plane))
|
||||
{
|
||||
default:
|
||||
case AXIS_YZ:
|
||||
width = (int)roundedSize.Y;
|
||||
height = (int)roundedSize.Z;
|
||||
width = (int)(uvMax.Y - uvMin.Y);
|
||||
height = (int)(uvMax.Z - uvMin.Z);
|
||||
tCoords[0].Y = 1.0f / SampleDimension;
|
||||
tCoords[1].Z = 1.0f / SampleDimension;
|
||||
break;
|
||||
|
||||
case AXIS_XZ:
|
||||
width = (int)roundedSize.X;
|
||||
height = (int)roundedSize.Z;
|
||||
width = (int)(uvMax.X - uvMin.X);
|
||||
height = (int)(uvMax.Z - uvMin.Z);
|
||||
tCoords[0].X = 1.0f / SampleDimension;
|
||||
tCoords[1].Z = 1.0f / SampleDimension;
|
||||
break;
|
||||
|
||||
case AXIS_XY:
|
||||
width = (int)roundedSize.X;
|
||||
height = (int)roundedSize.Y;
|
||||
width = (int)(uvMax.X - uvMin.X);
|
||||
height = (int)(uvMax.Y - uvMin.Y);
|
||||
tCoords[0].X = 1.0f / SampleDimension;
|
||||
tCoords[1].Y = 1.0f / SampleDimension;
|
||||
break;
|
||||
}
|
||||
|
||||
// clamp width
|
||||
if (width > textureSize - 2)
|
||||
textureSize -= 6; // Lightmapper needs some padding when baking
|
||||
|
||||
// Tile can never be bigger than the texture.
|
||||
if (width > textureSize)
|
||||
{
|
||||
tCoords[0] *= ((float)(textureSize - 2) / (float)width);
|
||||
width = (textureSize - 2);
|
||||
tCoords[0] *= textureSize / (float)width;
|
||||
width = textureSize;
|
||||
}
|
||||
if (height > textureSize)
|
||||
{
|
||||
tCoords[1] *= textureSize / (float)height;
|
||||
height = textureSize;
|
||||
}
|
||||
|
||||
// clamp height
|
||||
if (height > textureSize - 2)
|
||||
{
|
||||
tCoords[1] *= ((float)(textureSize - 2) / (float)height);
|
||||
height = (textureSize - 2);
|
||||
}
|
||||
Transform.TranslateWorldToLocal.X = uvMin.X * SampleDimension;
|
||||
Transform.TranslateWorldToLocal.Y = uvMin.Y * SampleDimension;
|
||||
Transform.TranslateWorldToLocal.Z = uvMin.Z * SampleDimension;
|
||||
|
||||
Transform.TranslateWorldToLocal = bounds.min;
|
||||
Transform.ProjLocalToU = tCoords[0];
|
||||
Transform.ProjLocalToV = tCoords[1];
|
||||
|
||||
|
|
|
|||
|
|
@ -119,8 +119,8 @@ void VkLightmapper::SelectTiles(const TArray<LightmapTile*>& tiles)
|
|||
bakeImage.maxY = 0;
|
||||
selectedTiles.Clear();
|
||||
|
||||
const int spacing = 5; // Note: the spacing is here to avoid that the resolve sampler finds data from other surface tiles
|
||||
RectPacker packer(bakeImageSize - spacing, bakeImageSize - spacing, RectPacker::Spacing(spacing));
|
||||
// We use a 3 texel spacing between rectangles so that the blur pass will not pick up anything from a neighbour tile.
|
||||
RectPacker packer(bakeImageSize, bakeImageSize, RectPacker::Spacing(3), RectPacker::Padding(3));
|
||||
|
||||
for (int i = 0, count = tiles.Size(); i < count; i++)
|
||||
{
|
||||
|
|
@ -130,21 +130,25 @@ void VkLightmapper::SelectTiles(const TArray<LightmapTile*>& tiles)
|
|||
continue;
|
||||
|
||||
// Only grab surfaces until our bake texture is full
|
||||
auto result = packer.insert(tile->AtlasLocation.Width + 2, tile->AtlasLocation.Height + 2);
|
||||
auto result = packer.insert(tile->AtlasLocation.Width, tile->AtlasLocation.Height);
|
||||
if (result.pageIndex == 0)
|
||||
{
|
||||
SelectedTile selected;
|
||||
selected.Tile = tile;
|
||||
selected.X = result.pos.x + 1;
|
||||
selected.Y = result.pos.y + 1;
|
||||
selected.X = result.pos.x;
|
||||
selected.Y = result.pos.y;
|
||||
selectedTiles.Push(selected);
|
||||
|
||||
bakeImage.maxX = std::max<uint16_t>(bakeImage.maxX, uint16_t(selected.X + tile->AtlasLocation.Width + spacing));
|
||||
bakeImage.maxY = std::max<uint16_t>(bakeImage.maxY, uint16_t(selected.Y + tile->AtlasLocation.Height + spacing));
|
||||
bakeImage.maxX = std::max<uint16_t>(bakeImage.maxX, uint16_t(result.pos.x + tile->AtlasLocation.Width));
|
||||
bakeImage.maxY = std::max<uint16_t>(bakeImage.maxY, uint16_t(result.pos.y + tile->AtlasLocation.Height));
|
||||
|
||||
tile->NeedsUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Include the padding
|
||||
bakeImage.maxX += 3;
|
||||
bakeImage.maxY += 3;
|
||||
}
|
||||
|
||||
void VkLightmapper::Render()
|
||||
|
|
@ -155,7 +159,7 @@ void VkLightmapper::Render()
|
|||
|
||||
RenderPassBegin()
|
||||
.RenderPass(raytrace.renderPass.get())
|
||||
.RenderArea(0, 0, bakeImageSize, bakeImageSize)
|
||||
.RenderArea(0, 0, bakeImage.maxX, bakeImage.maxY)
|
||||
.Framebuffer(bakeImage.raytrace.Framebuffer.get())
|
||||
.AddClearColor(0.0f, 0.0f, 0.0f, 0.0f)
|
||||
.Execute(cmdbuffer);
|
||||
|
|
@ -878,6 +882,9 @@ void VkLightmapper::CreateBlurPipeline()
|
|||
.Create(fb->GetDevice());
|
||||
|
||||
blur.sampler = SamplerBuilder()
|
||||
.MinFilter(VK_FILTER_NEAREST)
|
||||
.MagFilter(VK_FILTER_NEAREST)
|
||||
.MipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST)
|
||||
.DebugName("blur.Sampler")
|
||||
.Create(fb->GetDevice());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ void main()
|
|||
uint LightEnd = surfaces[SurfaceIndex].LightEnd;
|
||||
|
||||
vec3 normal = surfaces[SurfaceIndex].Normal;
|
||||
vec3 origin = worldpos + normal * 0.01;
|
||||
vec3 origin = worldpos;
|
||||
|
||||
#if defined(USE_SUNLIGHT)
|
||||
vec3 incoming = TraceSunLight(origin, normal);
|
||||
|
|
|
|||
|
|
@ -29,9 +29,8 @@ void main()
|
|||
gl_Position = vec4(vec2(TileX + x, TileY + y) / TextureSize * 2.0 - 1.0, 0.0, 1.0);
|
||||
|
||||
// Clip all surfaces to the edge of the tile (effectly we are applying a viewport/scissor to the tile)
|
||||
// Note: the tile has a 1px border around it that we also draw into
|
||||
gl_ClipDistance[0] = x + 1.0;
|
||||
gl_ClipDistance[1] = y + 1.0;
|
||||
gl_ClipDistance[2] = TileWidth + 1.0 - x;
|
||||
gl_ClipDistance[3] = TileHeight + 1.0 - y;
|
||||
gl_ClipDistance[0] = x;
|
||||
gl_ClipDistance[1] = y;
|
||||
gl_ClipDistance[2] = TileWidth - x;
|
||||
gl_ClipDistance[3] = TileHeight - y;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue