updated lightmap and decal packing systems

This commit is contained in:
Turanszki Janos
2021-04-10 20:03:02 +02:00
parent e5706f6b81
commit d2ae9d7e66
7 changed files with 283 additions and 365 deletions
+4
View File
@@ -1250,6 +1250,10 @@ void PaintToolWindow::ConsumeHistoryOperation(wiArchive& archive, bool undo)
Texture PaintToolWindow::GetEditTextureSlot(const MaterialComponent& material, int* uvset)
{
uint64_t sel = textureSlotComboBox.GetItemUserData(textureSlotComboBox.GetSelected());
if (material.textures[sel].resource == nullptr)
{
return Texture();
}
if (uvset)
*uvset = material.textures[sel].uvset;
return material.textures[sel].resource->texture;
+8
View File
@@ -5787,6 +5787,9 @@ using namespace DX12_Internal;
}
void GraphicsDevice_DX12::BindPipelineState(const PipelineState* pso, CommandList cmd)
{
active_cs[cmd] = nullptr;
active_rt[cmd] = nullptr;
size_t pipeline_hash = 0;
wiHelper::hash_combine(pipeline_hash, pso->hash);
if (active_renderpass[cmd] != nullptr)
@@ -5828,6 +5831,9 @@ using namespace DX12_Internal;
}
void GraphicsDevice_DX12::BindComputeShader(const Shader* cs, CommandList cmd)
{
active_pso[cmd] = nullptr;
active_rt[cmd] = nullptr;
assert(cs->stage == CS || cs->stage == LIB);
if (active_cs[cmd] != cs)
{
@@ -6236,6 +6242,8 @@ using namespace DX12_Internal;
}
void GraphicsDevice_DX12::BindRaytracingPipelineState(const RaytracingPipelineState* rtpso, CommandList cmd)
{
active_cs[cmd] = nullptr;
active_pso[cmd] = nullptr;
prev_pipeline_hash[cmd] = 0;
active_rt[cmd] = rtpso;
File diff suppressed because it is too large Load Diff
+2 -8
View File
@@ -651,12 +651,8 @@ namespace wiRenderer
const wiGraphics::Texture& dst, int DstMIP, int DstX, int DstY,
const wiGraphics::Texture& src, int SrcMIP,
wiGraphics::CommandList cmd,
BORDEREXPANDSTYLE borderExpand = BORDEREXPAND_DISABLE);
// New decals will be packed into a texture atlas
void ManageDecalAtlas(wiScene::Scene& scene);
// New lightmapped objects will be packed into global lightmap atlas
void ManageLightmapAtlas(wiScene::Scene& scene);
BORDEREXPANDSTYLE borderExpand = BORDEREXPAND_DISABLE
);
void PutWaterRipple(const std::string& image, const XMFLOAT3& pos);
void DrawWaterRipples(const Visibility& vis, wiGraphics::CommandList cmd);
@@ -749,8 +745,6 @@ namespace wiRenderer
void SetScreenSpaceShadowsEnabled(bool value);
bool GetScreenSpaceShadowsEnabled();
const wiGraphics::Texture* GetGlobalLightmap();
// Gets pick ray according to the current screen resolution and pointer coordinates. Can be used as input into RayIntersectWorld()
RAY GetPickRay(long cursorX, long cursorY, const wiScene::CameraComponent& camera = wiScene::GetCamera());
+170 -7
View File
@@ -9,6 +9,7 @@
#include "wiSpinLock.h"
#include "wiHelper.h"
#include "wiRenderer.h"
#include "wiBackLog.h"
#include <functional>
#include <unordered_map>
@@ -1188,9 +1189,10 @@ namespace wiScene
void ObjectComponent::ClearLightmap()
{
lightmap = Texture();
lightmap_rect = {};
lightmapWidth = 0;
lightmapHeight = 0;
globalLightMapMulAdd = XMFLOAT4(0, 0, 0, 0);
lightmapIterationCount = 0;
lightmapTextureData.clear();
SetLightmapRenderRequest(false);
@@ -1502,6 +1504,93 @@ namespace wiScene
device->SetName(&TLAS, "TLAS");
}
}
if (lightmap_refresh_needed.load())
{
InvalidateBVH();
}
if (lightmap_repack_needed.load())
{
std::vector<wiRectPacker::bin> bins;
if (wiRectPacker::pack(lightmap_rects.data(), (int)lightmap_rect_allocator.load(), 16384, bins))
{
assert(bins.size() == 1 && "The regions won't fit into the texture!");
TextureDesc desc;
desc.Width = (uint32_t)bins[0].size.w;
desc.Height = (uint32_t)bins[0].size.h;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = FORMAT_R11G11B10_FLOAT;
desc.SampleCount = 1;
desc.Usage = USAGE_DEFAULT;
desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
desc.CPUAccessFlags = 0;
desc.MiscFlags = 0;
device->CreateTexture(&desc, nullptr, &lightmap);
device->SetName(&lightmap, "Scene::lightmap");
}
else
{
wiBackLog::post("Global Lightmap atlas packing failed!");
}
}
if (!lightmap.IsValid())
{
// In case no lightmaps, still create a dummy texture
TextureDesc desc;
desc.Width = 1;
desc.Height = 1;
desc.Format = FORMAT_R11G11B10_FLOAT;
desc.BindFlags = BIND_SHADER_RESOURCE;
device->CreateTexture(&desc, nullptr, &lightmap);
}
// Update atlas texture if it is invalidated:
if (decal_repack_needed)
{
std::vector<wiRectPacker::rect_xywh*> out_rects(packedDecals.size());
int i = 0;
for (auto& it : packedDecals)
{
out_rects[i] = &it.second;
i++;
}
std::vector<wiRectPacker::bin> bins;
if (wiRectPacker::pack(out_rects.data(), (int)packedDecals.size(), 16384, bins))
{
assert(bins.size() == 1 && "The regions won't fit into the texture!");
TextureDesc desc;
desc.Width = (uint32_t)bins[0].size.w;
desc.Height = (uint32_t)bins[0].size.h;
desc.MipLevels = 0;
desc.ArraySize = 1;
desc.Format = FORMAT_R8G8B8A8_UNORM;
desc.SampleCount = 1;
desc.Usage = USAGE_DEFAULT;
desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
desc.CPUAccessFlags = 0;
desc.MiscFlags = 0;
device->CreateTexture(&desc, nullptr, &decalAtlas);
device->SetName(&decalAtlas, "Scene::decalAtlas");
for (uint32_t i = 0; i < decalAtlas.GetDesc().MipLevels; ++i)
{
int subresource_index;
subresource_index = device->CreateSubresource(&decalAtlas, UAV, 0, 1, i, 1);
assert(subresource_index == i);
}
}
else
{
wiBackLog::post("Decal atlas packing failed!");
}
}
}
void Scene::Clear()
{
@@ -1536,6 +1625,8 @@ namespace wiScene
springs.Clear();
TLAS = RaytracingAccelerationStructure();
BVH.Clear();
packedDecals.clear();
}
void Scene::Merge(Scene& other)
{
@@ -2831,6 +2922,9 @@ namespace wiScene
{
assert(objects.GetCount() == aabb_objects.GetCount());
lightmap_rects.resize(objects.GetCount());
lightmap_rect_allocator.store(0);
parallel_bounds.clear();
parallel_bounds.resize((size_t)wiJobSystem::DispatchGroupCount((uint32_t)objects.GetCount(), small_subtask_groupsize));
@@ -2983,6 +3077,63 @@ namespace wiScene
void* dest = (void*)((size_t)TLAS_instances.data() + (size_t)args.jobIndex * device->GetTopLevelAccelerationStructureInstanceSize());
device->WriteTopLevelAccelerationStructureInstance(&instance, dest);
}
// lightmap things:
if (dt > 0)
{
if (object.IsLightmapRenderRequested() && dt > 0)
{
if (!object.lightmap.IsValid())
{
{
// Unfortunately, fp128 format only correctly downloads from GPU if it is pow2 size:
object.lightmapWidth = wiMath::GetNextPowerOfTwo(object.lightmapWidth + 1) / 2;
object.lightmapHeight = wiMath::GetNextPowerOfTwo(object.lightmapHeight + 1) / 2;
}
TextureDesc desc;
desc.Width = object.lightmapWidth;
desc.Height = object.lightmapHeight;
desc.BindFlags = BIND_RENDER_TARGET | BIND_SHADER_RESOURCE;
// Note: we need the full precision format to achieve correct accumulative blending!
// But the global atlas will have less precision for good bandwidth for sampling
desc.Format = FORMAT_R32G32B32A32_FLOAT;
GraphicsDevice* device = wiRenderer::GetDevice();
device->CreateTexture(&desc, nullptr, &object.lightmap);
device->SetName(&object.lightmap, "object.lightmap");
RenderPassDesc renderpassdesc;
renderpassdesc.attachments.push_back(RenderPassAttachment::RenderTarget(&object.lightmap, RenderPassAttachment::LOADOP_CLEAR));
device->CreateRenderPass(&renderpassdesc, &object.renderpass_lightmap_clear);
renderpassdesc.attachments.back().loadop = RenderPassAttachment::LOADOP_LOAD;
device->CreateRenderPass(&renderpassdesc, &object.renderpass_lightmap_accumulate);
}
lightmap_refresh_needed.store(true);
}
if (!object.lightmapTextureData.empty() && !object.lightmap.IsValid())
{
// Create a GPU-side per object lighmap if there is none yet, so that copying into atlas can be done efficiently:
wiTextureHelper::CreateTexture(object.lightmap, object.lightmapTextureData.data(), object.lightmapWidth, object.lightmapHeight, object.GetLightmapFormat());
}
if (object.lightmap.IsValid())
{
if (object.lightmap_rect.w == 0)
{
// we need to pack this lightmap texture into the atlas
object.lightmap_rect = wiRectPacker::rect_xywh(0, 0, object.lightmap.GetDesc().Width + atlasClampBorder * 2, object.lightmap.GetDesc().Height + atlasClampBorder * 2);
lightmap_repack_needed.store(true); // will need to repack all in this case!
}
// lightmap rects' state is always updated, in case one needs repacking
uint32_t alloc = lightmap_rect_allocator.fetch_add(1);
lightmap_rects[alloc] = &object.lightmap_rect;
}
}
}
// parallel bounds computation using shared memory:
@@ -3021,10 +3172,10 @@ namespace wiScene
{
assert(decals.GetCount() == aabb_decals.GetCount());
wiJobSystem::Dispatch(ctx, (uint32_t)decals.GetCount(), small_subtask_groupsize, [&](wiJobArgs args) {
DecalComponent& decal = decals[args.jobIndex];
Entity entity = decals.GetEntity(args.jobIndex);
for (size_t i = 0; i < decals.GetCount(); ++i)
{
DecalComponent& decal = decals[i];
Entity entity = decals.GetEntity(i);
const TransformComponent& transform = *transforms.GetComponent(entity);
decal.world = transform.world;
@@ -3040,7 +3191,7 @@ namespace wiScene
XMStoreFloat3(&scale, S);
decal.range = std::max(scale.x, std::max(scale.y, scale.z)) * 2;
AABB& aabb = aabb_decals[args.jobIndex];
AABB& aabb = aabb_decals[i];
aabb.createFromHalfWidth(XMFLOAT3(0, 0, 0), XMFLOAT3(1, 1, 1));
aabb = aabb.transform(transform.world);
@@ -3049,7 +3200,19 @@ namespace wiScene
decal.emissive = material.GetEmissiveStrength();
decal.texture = material.textures[MaterialComponent::BASECOLORMAP].resource;
decal.normal = material.textures[MaterialComponent::NORMALMAP].resource;
});
// atlas part is not thread safe:
if (decal.texture != nullptr && decal.texture->texture.IsValid())
{
if (packedDecals.find(decal.texture) == packedDecals.end())
{
// we need to pack this decal texture into the atlas
wiRectPacker::rect_xywh newRect = wiRectPacker::rect_xywh(0, 0, decal.texture->texture.desc.Width + atlasClampBorder * 2, decal.texture->texture.desc.Height + atlasClampBorder * 2);
packedDecals[decal.texture] = newRect;
decal_repack_needed = true;
}
}
}
}
void Scene::RunProbeUpdateSystem(wiJobSystem::context& ctx)
{
+14 -3
View File
@@ -624,11 +624,11 @@ namespace wiScene
// Non-serialized attributes:
XMFLOAT4 globalLightMapMulAdd = XMFLOAT4(0, 0, 0, 0);
wiGraphics::Texture lightmap;
wiGraphics::RenderPass renderpass_lightmap_clear;
wiGraphics::RenderPass renderpass_lightmap_accumulate;
uint32_t lightmapIterationCount = 0;
mutable uint32_t lightmapIterationCount = 0;
wiRectPacker::rect_xywh lightmap_rect = {};
XMFLOAT3 center = XMFLOAT3(0, 0, 0);
float impostorFadeThresholdRadius;
@@ -994,7 +994,6 @@ namespace wiScene
XMFLOAT3 front;
XMFLOAT3 position;
float range;
XMFLOAT4 atlasMulAdd;
XMFLOAT4X4 world;
std::shared_ptr<wiResource> texture;
@@ -1325,6 +1324,18 @@ namespace wiScene
wiGraphics::Texture impostorArray;
std::vector<wiGraphics::RenderPass> renderpasses_impostor;
static const int atlasClampBorder = 1;
wiGraphics::Texture lightmap;
std::vector<wiRectPacker::rect_xywh*> lightmap_rects;
std::atomic<uint32_t> lightmap_rect_allocator{ 0 };
mutable std::atomic_bool lightmap_repack_needed{ false };
mutable std::atomic_bool lightmap_refresh_needed{ false };
wiGraphics::Texture decalAtlas;
mutable bool decal_repack_needed{ false };
std::unordered_map<std::shared_ptr<wiResource>, wiRectPacker::rect_xywh> packedDecals;
// Update all components by a given timestep (in seconds):
// This is an expensive function, prefer to call it only once per frame!
void Update(float dt);
+1 -1
View File
@@ -9,7 +9,7 @@ namespace wiVersion
// minor features, major updates, breaking compatibility changes
const int minor = 55;
// minor bug fixes, alterations, refactors, updates
const int revision = 23;
const int revision = 24;
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);