updated lightmap and decal packing systems
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+84
-346
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user