From c316cea9b0e6acf6d5e4d73403845a834976893d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Sat, 27 Jan 2024 12:31:49 +0100 Subject: [PATCH] instancable (per object) vertex ao --- Editor/MeshWindow.cpp | 13 ----- Editor/ObjectWindow.cpp | 37 +++++++------ WickedEngine/shaders/ShaderInterop_Renderer.h | 13 +++-- WickedEngine/shaders/objectHF.hlsli | 16 +++--- WickedEngine/shaders/surfaceHF.hlsli | 4 +- WickedEngine/wiMath.h | 14 +++++ WickedEngine/wiScene.cpp | 2 +- WickedEngine/wiScene.h | 4 +- WickedEngine/wiScene_Components.cpp | 53 ++++++++++--------- WickedEngine/wiScene_Components.h | 18 ++++--- WickedEngine/wiScene_Serializers.cpp | 22 ++++---- 11 files changed, 106 insertions(+), 90 deletions(-) diff --git a/Editor/MeshWindow.cpp b/Editor/MeshWindow.cpp index 11ec0db833..0722dc8b8c 100644 --- a/Editor/MeshWindow.cpp +++ b/Editor/MeshWindow.cpp @@ -441,16 +441,6 @@ void MeshWindow::Create(EditorComponent* _editor) merged_mesh.vertex_colors.push_back(mesh->vertex_colors[i]); } - if (mesh->vertex_ao.empty()) - { - merged_mesh.vertex_ao.push_back(0xFF); - } - else - { - valid_ao = true; - merged_mesh.vertex_ao.push_back(mesh->vertex_ao[i]); - } - if (mesh->vertex_windweights.empty()) { merged_mesh.vertex_windweights.emplace_back(); @@ -499,8 +489,6 @@ void MeshWindow::Create(EditorComponent* _editor) merged_mesh.vertex_boneweights.clear(); if (!valid_colors) merged_mesh.vertex_colors.clear(); - if (!valid_ao) - merged_mesh.vertex_ao.clear(); if (!valid_windweights) merged_mesh.vertex_windweights.clear(); @@ -906,7 +894,6 @@ void MeshWindow::SetEntity(Entity entity, int subset) if (mesh->vb_uvs.IsValid()) ss += "\tuvsets;\n"; if (mesh->vb_atl.IsValid()) ss += "\tatlas;\n"; if (mesh->vb_col.IsValid()) ss += "\tcolor;\n"; - if (mesh->vb_ao.IsValid()) ss += "\tao;\n"; if (mesh->so_pre.IsValid()) ss += "\tprevious_position;\n"; if (mesh->vb_bon.IsValid()) ss += "\tbone;\n"; if (mesh->vb_tan.IsValid()) ss += "\ttangent;\n"; diff --git a/Editor/ObjectWindow.cpp b/Editor/ObjectWindow.cpp index 4670fdc9f2..2dd043a97e 100644 --- a/Editor/ObjectWindow.cpp +++ b/Editor/ObjectWindow.cpp @@ -678,7 +678,7 @@ void ObjectWindow::Create(EditorComponent* _editor) } } } - wi::backlog::post("Building BVHs for vertex AO took " + wi::helper::GetTimerDurationText(timer.elapsed_seconds())); + wi::backlog::post("Building BVHs for vertex AO took " + wi::helper::GetTimerDurationText((float)timer.elapsed_seconds())); } for (auto& x : this->editor->translator.selected) @@ -686,26 +686,26 @@ void ObjectWindow::Create(EditorComponent* _editor) ObjectComponent* objectcomponent = scene.objects.GetComponent(x.entity); if (objectcomponent != nullptr) { - const size_t objectcomponentIndex = scene.objects.GetIndex(x.entity); - MeshComponent* meshcomponent = scene.meshes.GetComponent(objectcomponent->meshID); - if (meshcomponent == nullptr) - continue; if (deleteAOMode) { - meshcomponent->vertex_ao.clear(); + objectcomponent->vertex_ao.clear(); } else { + const MeshComponent* meshcomponent = scene.meshes.GetComponent(objectcomponent->meshID); + if (meshcomponent == nullptr) + continue; if (meshcomponent->vertex_normals.size() != meshcomponent->vertex_positions.size()) continue; wi::Timer timer; using namespace wi::primitive; - meshcomponent->vertex_ao.resize(meshcomponent->vertex_positions.size()); + objectcomponent->vertex_ao.resize(meshcomponent->vertex_positions.size()); + const size_t objectcomponentIndex = scene.objects.GetIndex(x.entity); - uint32_t groupSizePerCore = wi::jobsystem::DispatchGroupCount((uint32_t)meshcomponent->vertex_ao.size(), wi::jobsystem::GetThreadCount()); + uint32_t groupSizePerCore = wi::jobsystem::DispatchGroupCount((uint32_t)objectcomponent->vertex_ao.size(), wi::jobsystem::GetThreadCount()); wi::jobsystem::context ctx; - wi::jobsystem::Dispatch(ctx, (uint32_t)meshcomponent->vertex_ao.size(), groupSizePerCore, [&](wi::jobsystem::JobArgs args) { + wi::jobsystem::Dispatch(ctx, (uint32_t)objectcomponent->vertex_ao.size(), groupSizePerCore, [&](wi::jobsystem::JobArgs args) { XMFLOAT3 position = meshcomponent->vertex_positions[args.jobIndex]; XMFLOAT3 normal = meshcomponent->vertex_normals[args.jobIndex]; const XMMATRIX W = XMLoadFloat4x4(&scene.matrix_objects[objectcomponentIndex]); @@ -718,7 +718,8 @@ void ObjectWindow::Create(EditorComponent* _editor) const XMVECTOR rayOrigin = XMLoadFloat3(&position); for (uint32_t sam = 0; sam < samplecount; ++sam) { - XMFLOAT3 hemi = wi::math::HemispherePoint_Cos(wi::random::GetRandom(1.0f), wi::random::GetRandom(1.0f)); + XMFLOAT2 hamm = wi::math::Hammersley2D(sam, samplecount); + XMFLOAT3 hemi = wi::math::HemispherePoint_Cos(hamm.x, hamm.y); XMVECTOR rayDirection = XMLoadFloat3(&hemi); rayDirection = XMVector3TransformNormal(rayDirection, TBN); rayDirection = XMVector3Normalize(rayDirection); @@ -742,13 +743,11 @@ void ObjectWindow::Create(EditorComponent* _editor) continue; const Entity entity = scene.objects.GetEntity(objectIndex); - const SoftBodyPhysicsComponent* softbody = scene.softbodies.GetComponent(object.meshID); const XMMATRIX objectMat = XMLoadFloat4x4(&scene.matrix_objects[objectIndex]); const XMMATRIX objectMatPrev = XMLoadFloat4x4(&scene.matrix_objects_prev[objectIndex]); const XMMATRIX objectMat_Inverse = XMMatrixInverse(nullptr, objectMat); const XMVECTOR rayOrigin_local = XMVector3Transform(rayOrigin, objectMat_Inverse); const XMVECTOR rayDirection_local = XMVector3Normalize(XMVector3TransformNormal(rayDirection, objectMat_Inverse)); - const ArmatureComponent* armature = mesh->IsSkinned() ? scene.armatures.GetComponent(mesh->armatureID) : nullptr; auto intersect_triangle = [&](uint32_t subsetIndex, uint32_t indexOffset, uint32_t triangleIndex) { @@ -785,7 +784,7 @@ void ObjectWindow::Create(EditorComponent* _editor) if (intersect_triangle(subsetIndex, indexOffset, triangleIndex)) return true; return false; - }); + }); } else { @@ -816,12 +815,12 @@ void ObjectWindow::Create(EditorComponent* _editor) accum += 1.0f; } accum /= float(samplecount); - meshcomponent->vertex_ao[args.jobIndex] = uint8_t(accum * 255); - }); + objectcomponent->vertex_ao[args.jobIndex] = uint8_t(accum * 255); + }); wi::jobsystem::Wait(ctx); - wi::backlog::post("Vertex AO baking took " + wi::helper::GetTimerDurationText(timer.elapsed_seconds())); + wi::backlog::post("Vertex AO baking took " + wi::helper::GetTimerDurationText((float)timer.elapsed_seconds())); } - meshcomponent->CreateRenderData(); + objectcomponent->CreateRenderData(); } } @@ -843,6 +842,7 @@ void ObjectWindow::Create(EditorComponent* _editor) } } + SetEntity(entity); }); AddWidget(&vertexAOButton); @@ -910,8 +910,7 @@ void ObjectWindow::SetEntity(Entity entity) if (object != nullptr) { - const MeshComponent* mesh = scene.meshes.GetComponent(object->meshID); - if (mesh != nullptr && mesh->vertex_ao.empty()) + if (object->vertex_ao.empty()) { vertexAOButton.SetText("Compute Vertex AO"); deleteAOMode = false; diff --git a/WickedEngine/shaders/ShaderInterop_Renderer.h b/WickedEngine/shaders/ShaderInterop_Renderer.h index ab3a6cb903..1017b8f622 100644 --- a/WickedEngine/shaders/ShaderInterop_Renderer.h +++ b/WickedEngine/shaders/ShaderInterop_Renderer.h @@ -454,9 +454,9 @@ struct ShaderGeometry int vb_tan; int vb_col; int vb_atl; - int vb_ao; - int vb_pre; + + int impostorSliceOffset; uint materialIndex; uint meshletOffset; // offset of this subset in meshlets (locally within the mesh) uint meshletCount; @@ -471,8 +471,8 @@ struct ShaderGeometry uint indexOffset; uint indexCount; - int impostorSliceOffset; int padding0; + int padding1; void init() { @@ -483,7 +483,6 @@ struct ShaderGeometry vb_tan = -1; vb_col = -1; vb_atl = -1; - vb_ao = -1; vb_pre = -1; materialIndex = 0; meshletOffset = 0; @@ -569,6 +568,11 @@ struct ShaderMeshInstance float3 center; float radius; + int vb_ao; + int padding0; + int padding1; + int padding2; + ShaderTransform transform; ShaderTransform transformInverseTranspose; // This correctly handles non uniform scaling for normals ShaderTransform transformPrev; @@ -589,6 +593,7 @@ struct ShaderMeshInstance fadeDistance = 0; center = float3(0, 0, 0); radius = 0; + vb_ao = -1; transform.init(); transformInverseTranspose.init(); transformPrev.init(); diff --git a/WickedEngine/shaders/objectHF.hlsli b/WickedEngine/shaders/objectHF.hlsli index 1949f3ca05..10533af254 100644 --- a/WickedEngine/shaders/objectHF.hlsli +++ b/WickedEngine/shaders/objectHF.hlsli @@ -161,14 +161,6 @@ struct VertexInput return 1; return (min16float4)bindless_buffers_float4[GetMesh().vb_col][vertexID]; } - - min16float GetVertexAO() - { - [branch] - if (GetMesh().vb_ao < 0) - return 1; - return (min16float)bindless_buffers_float[GetMesh().vb_ao][vertexID]; - } min16float3 GetNormal() { @@ -195,6 +187,14 @@ struct VertexInput inst.init(); return inst; } + + min16float GetVertexAO() + { + [branch] + if (GetInstance().vb_ao < 0) + return 1; + return (min16float)bindless_buffers_float[GetInstance().vb_ao][vertexID]; + } }; diff --git a/WickedEngine/shaders/surfaceHF.hlsli b/WickedEngine/shaders/surfaceHF.hlsli index 137cd4730e..a451752a3e 100644 --- a/WickedEngine/shaders/surfaceHF.hlsli +++ b/WickedEngine/shaders/surfaceHF.hlsli @@ -541,9 +541,9 @@ struct Surface } [branch] - if (geometry.vb_ao >= 0 && material.IsUsingVertexAO()) + if (inst.vb_ao >= 0 && material.IsUsingVertexAO()) { - Buffer buf = bindless_buffers_float[NonUniformResourceIndex(geometry.vb_ao)]; + Buffer buf = bindless_buffers_float[NonUniformResourceIndex(inst.vb_ao)]; const float ao0 = buf[i0]; const float ao1 = buf[i1]; const float ao2 = buf[i2]; diff --git a/WickedEngine/wiMath.h b/WickedEngine/wiMath.h index a9d115258e..40688a2d1e 100644 --- a/WickedEngine/wiMath.h +++ b/WickedEngine/wiMath.h @@ -274,6 +274,20 @@ namespace wi::math return ++x; } + // A uniform 2D random generator for hemisphere sampling: http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html + // idx : iteration index + // num : number of iterations in total + constexpr XMFLOAT2 Hammersley2D(uint32_t idx, uint32_t num) { + uint32_t bits = idx; + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + const float radicalInverse_VdC = float(bits) * 2.3283064365386963e-10f; // / 0x100000000 + + return XMFLOAT2(float(idx) / float(num), radicalInverse_VdC); + } inline XMMATRIX GetTangentSpace(const XMFLOAT3& N) { // Choose a helper vector for the cross product diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index 37205a956e..afa0aa44f0 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -3447,7 +3447,6 @@ namespace wi::scene geometry.vb_tan = mesh.vb_tan.descriptor_srv; } geometry.vb_col = mesh.vb_col.descriptor_srv; - geometry.vb_ao = mesh.vb_ao.descriptor_srv; geometry.vb_uvs = mesh.vb_uvs.descriptor_srv; geometry.vb_atl = mesh.vb_atl.descriptor_srv; geometry.vb_pre = mesh.so_pre.descriptor_srv; @@ -3978,6 +3977,7 @@ namespace wi::scene inst.fadeDistance = object.fadeDistance; inst.center = object.center; inst.radius = object.radius; + inst.vb_ao = object.vb_ao_srv; inst.SetUserStencilRef(object.userStencilRef); std::memcpy(instanceArrayMapped + args.jobIndex, &inst, sizeof(inst)); // memcpy whole structure into mapped pointer to avoid read from uncached memory diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index 12ac62aec0..32bfa2e81b 100644 --- a/WickedEngine/wiScene.h +++ b/WickedEngine/wiScene.h @@ -31,9 +31,9 @@ namespace wi::scene wi::ecs::ComponentManager& transforms = componentLibrary.Register("wi::scene::Scene::transforms"); wi::ecs::ComponentManager& hierarchy = componentLibrary.Register("wi::scene::Scene::hierarchy"); wi::ecs::ComponentManager& materials = componentLibrary.Register("wi::scene::Scene::materials", 2); // version = 2 - wi::ecs::ComponentManager& meshes = componentLibrary.Register("wi::scene::Scene::meshes", 3); // version = 2 + wi::ecs::ComponentManager& meshes = componentLibrary.Register("wi::scene::Scene::meshes", 2); // version = 2 wi::ecs::ComponentManager& impostors = componentLibrary.Register("wi::scene::Scene::impostors"); - wi::ecs::ComponentManager& objects = componentLibrary.Register("wi::scene::Scene::objects", 2); // version = 2 + wi::ecs::ComponentManager& objects = componentLibrary.Register("wi::scene::Scene::objects", 3); // version = 3 wi::ecs::ComponentManager& rigidbodies = componentLibrary.Register("wi::scene::Scene::rigidbodies", 1); // version = 1 wi::ecs::ComponentManager& softbodies = componentLibrary.Register("wi::scene::Scene::softbodies"); wi::ecs::ComponentManager& armatures = componentLibrary.Register("wi::scene::Scene::armatures"); diff --git a/WickedEngine/wiScene_Components.cpp b/WickedEngine/wiScene_Components.cpp index 7524983fdc..e73a64915e 100644 --- a/WickedEngine/wiScene_Components.cpp +++ b/WickedEngine/wiScene_Components.cpp @@ -470,7 +470,6 @@ namespace wi::scene vb_uvs = {}; vb_atl = {}; vb_col = {}; - vb_ao = {}; vb_bon = {}; so_pos = {}; so_nor = {}; @@ -696,7 +695,6 @@ namespace wi::scene AlignTo(uv_count * sizeof(Vertex_UVS), alignment) + AlignTo(vertex_atlas.size() * sizeof(Vertex_TEX), alignment) + AlignTo(vertex_colors.size() * sizeof(Vertex_COL), alignment) + - AlignTo(vertex_ao.size() * sizeof(Vertex_AO), alignment) + AlignTo(vertex_boneindices.size() * sizeof(Vertex_BON), alignment) ; @@ -892,21 +890,6 @@ namespace wi::scene } } - // vertexBuffer - AO (ambient occlusion) - if (!vertex_ao.empty()) - { - vb_ao.offset = buffer_offset; - vb_ao.size = vertex_ao.size() * sizeof(Vertex_AO); - Vertex_AO* vertices = (Vertex_AO*)(buffer_data + buffer_offset); - buffer_offset += AlignTo(vb_ao.size, alignment); - for (size_t i = 0; i < vertex_ao.size(); ++i) - { - Vertex_AO vert; - vert.value = vertex_ao[i]; - std::memcpy(vertices + i, &vert, sizeof(vert)); - } - } - // skinning buffers: if (!vertex_boneindices.empty()) { @@ -1030,11 +1013,6 @@ namespace wi::scene vb_col.subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, vb_col.offset, vb_col.size, &Vertex_COL::FORMAT); vb_col.descriptor_srv = device->GetDescriptorIndex(&generalBuffer, SubresourceType::SRV, vb_col.subresource_srv); } - if (vb_ao.IsValid()) - { - vb_ao.subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, vb_ao.offset, vb_ao.size, &Vertex_AO::FORMAT); - vb_ao.descriptor_srv = device->GetDescriptorIndex(&generalBuffer, SubresourceType::SRV, vb_ao.subresource_srv); - } if (vb_bon.IsValid()) { vb_bon.subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, vb_bon.offset, vb_bon.size); @@ -1589,7 +1567,6 @@ namespace wi::scene vertex_boneweights.size() * sizeof(XMFLOAT4) + vertex_atlas.size() * sizeof(XMFLOAT2) + vertex_colors.size() * sizeof(uint32_t) + - vertex_ao.size() * sizeof(uint8_t) + vertex_windweights.size() * sizeof(uint8_t) + indices.size() * sizeof(uint32_t); @@ -1626,7 +1603,6 @@ namespace wi::scene lightmapTextureData.clear(); SetLightmapRenderRequest(false); } - void ObjectComponent::SaveLightmap() { if (lightmap.IsValid() && has_flag(lightmap.desc.bind_flags, BindFlag::RENDER_TARGET)) @@ -1729,6 +1705,35 @@ namespace wi::scene lightmap.desc = desc; } } + void ObjectComponent::DeleteRenderData() + { + vb_ao = {}; + vb_ao_srv = -1; + } + void ObjectComponent::CreateRenderData() + { + DeleteRenderData(); + + GraphicsDevice* device = wi::graphics::GetDevice(); + + if (!vertex_ao.empty()) + { + GPUBufferDesc desc; + desc.bind_flags = BindFlag::SHADER_RESOURCE; + desc.size = sizeof(Vertex_AO) * vertex_ao.size(); + desc.format = Vertex_AO::FORMAT; + + auto fill_ao = [&](void* data) { + std::memcpy(data, vertex_ao.data(), vertex_ao.size()); + }; + + bool success = device->CreateBuffer2(&desc, fill_ao, &vb_ao); + assert(success); + device->SetName(&vb_ao, "ObjectComponent::vb_ao"); + + vb_ao_srv = device->GetDescriptorIndex(&vb_ao, SubresourceType::SRV); + } + } void EnvironmentProbeComponent::CreateRenderData() { diff --git a/WickedEngine/wiScene_Components.h b/WickedEngine/wiScene_Components.h index 1b22af5659..6ed317e38f 100644 --- a/WickedEngine/wiScene_Components.h +++ b/WickedEngine/wiScene_Components.h @@ -355,7 +355,6 @@ namespace wi::scene wi::vector vertex_boneweights; wi::vector vertex_atlas; wi::vector vertex_colors; - wi::vector vertex_ao; wi::vector vertex_windweights; wi::vector indices; @@ -414,7 +413,6 @@ namespace wi::scene BufferView vb_uvs; BufferView vb_atl; BufferView vb_col; - BufferView vb_ao; BufferView vb_bon; BufferView vb_mor; BufferView so_pos; @@ -691,11 +689,6 @@ namespace wi::scene uint32_t color = 0; static constexpr wi::graphics::Format FORMAT = wi::graphics::Format::R8G8B8A8_UNORM; }; - struct Vertex_AO - { - uint8_t value = 0; - static constexpr wi::graphics::Format FORMAT = wi::graphics::Format::R8_UNORM; - }; struct Vertex_NOR { int8_t x = 0; @@ -819,12 +812,15 @@ namespace wi::scene uint32_t lightmapHeight = 0; wi::vector lightmapTextureData; uint32_t sort_priority = 0; // increase to draw earlier (currently 4 bits will be used) + wi::vector vertex_ao; // Non-serialized attributes: uint32_t filterMaskDynamic = 0; wi::graphics::Texture lightmap; mutable uint32_t lightmapIterationCount = 0; + wi::graphics::GPUBuffer vb_ao; + int vb_ao_srv = -1; XMFLOAT3 center = XMFLOAT3(0, 0, 0); float radius = 0; @@ -875,6 +871,14 @@ namespace wi::scene void CompressLightmap(); // not thread safe if LIGHTMAP_BLOCK_COMPRESSION is enabled! void Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri); + + void CreateRenderData(); + void DeleteRenderData(); + struct Vertex_AO + { + uint8_t value = 0; + static constexpr wi::graphics::Format FORMAT = wi::graphics::Format::R8_UNORM; + }; }; struct RigidBodyPhysicsComponent diff --git a/WickedEngine/wiScene_Serializers.cpp b/WickedEngine/wiScene_Serializers.cpp index 334434112f..b85774f887 100644 --- a/WickedEngine/wiScene_Serializers.cpp +++ b/WickedEngine/wiScene_Serializers.cpp @@ -450,11 +450,6 @@ namespace wi::scene archive >> subsets_per_lod; } - if (seri.GetVersion() >= 3) - { - archive >> vertex_ao; - } - wi::jobsystem::Execute(seri.ctx, [&](wi::jobsystem::JobArgs args) { CreateRenderData(); @@ -537,11 +532,6 @@ namespace wi::scene archive << subsets_per_lod; } - if (seri.GetVersion() >= 3) - { - archive << vertex_ao; - } - } } void ImpostorComponent::Serialize(wi::Archive& archive, EntitySerializer& seri) @@ -603,6 +593,14 @@ namespace wi::scene { archive >> sort_priority; } + if (seri.GetVersion() >= 3) + { + archive >> vertex_ao; + } + + wi::jobsystem::Execute(seri.ctx, [&](wi::jobsystem::JobArgs args) { + CreateRenderData(); + }); } else { @@ -641,6 +639,10 @@ namespace wi::scene { archive << sort_priority; } + if (seri.GetVersion() >= 3) + { + archive << vertex_ao; + } } } void RigidBodyPhysicsComponent::Serialize(wi::Archive& archive, EntitySerializer& seri)