Raytracing LOD support (#547)
* raytracing LOD support * software raytracing LOD * update LOD before TLAS write * version bump
This commit is contained in:
@@ -158,13 +158,16 @@ namespace wi
|
||||
{
|
||||
const MeshComponent& mesh = *scene.meshes.GetComponent(object.meshID);
|
||||
|
||||
for (size_t j = 0; j < mesh.subsets.size(); ++j)
|
||||
uint32_t first_subset = 0;
|
||||
uint32_t last_subset = 0;
|
||||
mesh.GetLODSubsetRange(object.lod, first_subset, last_subset);
|
||||
for (uint32_t subsetIndex = first_subset; subsetIndex < last_subset; ++subsetIndex)
|
||||
{
|
||||
auto& subset = mesh.subsets[j];
|
||||
const MeshComponent::MeshSubset& subset = mesh.subsets[subsetIndex];
|
||||
|
||||
BVHPushConstants push;
|
||||
push.instanceIndex = (uint)i;
|
||||
push.subsetIndex = (uint)j;
|
||||
push.subsetIndex = subsetIndex;
|
||||
push.primitiveCount = subset.indexCount / 3;
|
||||
push.primitiveOffset = primitiveCount;
|
||||
device->PushConstants(&push, sizeof(push), cmd);
|
||||
|
||||
@@ -6364,6 +6364,8 @@ using namespace vulkan_internal;
|
||||
float blendConstants[] = { 1,1,1,1 };
|
||||
vkCmdSetBlendConstants(commandlist.GetCommandBuffer(), blendConstants);
|
||||
|
||||
vkCmdSetStencilReference(commandlist.GetCommandBuffer(), VK_STENCIL_FRONT_AND_BACK, ~0u);
|
||||
|
||||
if (features2.features.depthBounds == VK_TRUE)
|
||||
{
|
||||
vkCmdSetDepthBounds(commandlist.GetCommandBuffer(), 0.0f, 1.0f);
|
||||
|
||||
@@ -514,13 +514,14 @@ void RenderPath3D::Update(float dt)
|
||||
|
||||
RenderPath2D::Update(dt);
|
||||
|
||||
const bool hw_raytrace = device->CheckCapability(GraphicsDeviceCapability::RAYTRACING);
|
||||
if (getSceneUpdateEnabled())
|
||||
{
|
||||
if (wi::renderer::GetSurfelGIEnabled() ||
|
||||
wi::renderer::GetDDGIEnabled() ||
|
||||
wi::renderer::GetRaytracedShadowsEnabled() ||
|
||||
getAO() == AO_RTAO ||
|
||||
getRaytracedReflectionEnabled())
|
||||
(hw_raytrace && wi::renderer::GetRaytracedShadowsEnabled()) ||
|
||||
(hw_raytrace && getAO() == AO_RTAO) ||
|
||||
(hw_raytrace && getRaytracedReflectionEnabled()))
|
||||
{
|
||||
scene->SetAccelerationStructureUpdateRequested(true);
|
||||
}
|
||||
|
||||
+15
-12
@@ -4253,22 +4253,25 @@ void UpdateRaytracingAccelerationStructures(const Scene& scene, CommandList cmd)
|
||||
for (size_t i = 0; i < scene.meshes.GetCount(); ++i)
|
||||
{
|
||||
const MeshComponent& mesh = scene.meshes[i];
|
||||
if (mesh.BLAS.IsValid())
|
||||
for (auto& BLAS : mesh.BLASes)
|
||||
{
|
||||
switch (mesh.BLAS_state)
|
||||
if (BLAS.IsValid())
|
||||
{
|
||||
default:
|
||||
case MeshComponent::BLAS_STATE_COMPLETE:
|
||||
break;
|
||||
case MeshComponent::BLAS_STATE_NEEDS_REBUILD:
|
||||
device->BuildRaytracingAccelerationStructure(&mesh.BLAS, cmd, nullptr);
|
||||
break;
|
||||
case MeshComponent::BLAS_STATE_NEEDS_REFIT:
|
||||
device->BuildRaytracingAccelerationStructure(&mesh.BLAS, cmd, &mesh.BLAS);
|
||||
break;
|
||||
switch (mesh.BLAS_state)
|
||||
{
|
||||
default:
|
||||
case MeshComponent::BLAS_STATE_COMPLETE:
|
||||
break;
|
||||
case MeshComponent::BLAS_STATE_NEEDS_REBUILD:
|
||||
device->BuildRaytracingAccelerationStructure(&BLAS, cmd, nullptr);
|
||||
break;
|
||||
case MeshComponent::BLAS_STATE_NEEDS_REFIT:
|
||||
device->BuildRaytracingAccelerationStructure(&BLAS, cmd, &BLAS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mesh.BLAS_state = MeshComponent::BLAS_STATE_COMPLETE;
|
||||
}
|
||||
mesh.BLAS_state = MeshComponent::BLAS_STATE_COMPLETE;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < scene.hairs.GetCount(); ++i)
|
||||
|
||||
+93
-73
@@ -699,42 +699,47 @@ namespace wi::scene
|
||||
{
|
||||
BLAS_state = MeshComponent::BLAS_STATE_NEEDS_REBUILD;
|
||||
|
||||
RaytracingAccelerationStructureDesc desc;
|
||||
desc.type = RaytracingAccelerationStructureDesc::Type::BOTTOMLEVEL;
|
||||
|
||||
if (streamoutBuffer.IsValid())
|
||||
const uint32_t lod_count = GetLODCount();
|
||||
BLASes.resize(lod_count);
|
||||
for (uint32_t lod = 0; lod < lod_count; ++lod)
|
||||
{
|
||||
desc.flags |= RaytracingAccelerationStructureDesc::FLAG_ALLOW_UPDATE;
|
||||
desc.flags |= RaytracingAccelerationStructureDesc::FLAG_PREFER_FAST_BUILD;
|
||||
}
|
||||
else
|
||||
{
|
||||
desc.flags |= RaytracingAccelerationStructureDesc::FLAG_PREFER_FAST_TRACE;
|
||||
}
|
||||
RaytracingAccelerationStructureDesc desc;
|
||||
desc.type = RaytracingAccelerationStructureDesc::Type::BOTTOMLEVEL;
|
||||
|
||||
uint32_t first_subset = 0;
|
||||
uint32_t last_subset = 0;
|
||||
GetLODSubsetRange(0, first_subset, last_subset);
|
||||
for (uint32_t subsetIndex = first_subset; subsetIndex < last_subset; ++subsetIndex)
|
||||
{
|
||||
const MeshComponent::MeshSubset& subset = subsets[subsetIndex];
|
||||
desc.bottom_level.geometries.emplace_back();
|
||||
auto& geometry = desc.bottom_level.geometries.back();
|
||||
geometry.type = RaytracingAccelerationStructureDesc::BottomLevel::Geometry::Type::TRIANGLES;
|
||||
geometry.triangles.vertex_buffer = generalBuffer;
|
||||
geometry.triangles.vertex_byte_offset = vb_pos_nor_wind.offset;
|
||||
geometry.triangles.index_buffer = generalBuffer;
|
||||
geometry.triangles.index_format = GetIndexFormat();
|
||||
geometry.triangles.index_count = subset.indexCount;
|
||||
geometry.triangles.index_offset = ib.offset / GetIndexStride() + subset.indexOffset;
|
||||
geometry.triangles.vertex_count = (uint32_t)vertex_positions.size();
|
||||
geometry.triangles.vertex_format = Format::R32G32B32_FLOAT;
|
||||
geometry.triangles.vertex_stride = sizeof(MeshComponent::Vertex_POS);
|
||||
}
|
||||
if (streamoutBuffer.IsValid())
|
||||
{
|
||||
desc.flags |= RaytracingAccelerationStructureDesc::FLAG_ALLOW_UPDATE;
|
||||
desc.flags |= RaytracingAccelerationStructureDesc::FLAG_PREFER_FAST_BUILD;
|
||||
}
|
||||
else
|
||||
{
|
||||
desc.flags |= RaytracingAccelerationStructureDesc::FLAG_PREFER_FAST_TRACE;
|
||||
}
|
||||
|
||||
bool success = device->CreateRaytracingAccelerationStructure(&desc, &BLAS);
|
||||
assert(success);
|
||||
device->SetName(&BLAS, "MeshComponent::BLAS");
|
||||
uint32_t first_subset = 0;
|
||||
uint32_t last_subset = 0;
|
||||
GetLODSubsetRange(lod, first_subset, last_subset);
|
||||
for (uint32_t subsetIndex = first_subset; subsetIndex < last_subset; ++subsetIndex)
|
||||
{
|
||||
const MeshComponent::MeshSubset& subset = subsets[subsetIndex];
|
||||
desc.bottom_level.geometries.emplace_back();
|
||||
auto& geometry = desc.bottom_level.geometries.back();
|
||||
geometry.type = RaytracingAccelerationStructureDesc::BottomLevel::Geometry::Type::TRIANGLES;
|
||||
geometry.triangles.vertex_buffer = generalBuffer;
|
||||
geometry.triangles.vertex_byte_offset = vb_pos_nor_wind.offset;
|
||||
geometry.triangles.index_buffer = generalBuffer;
|
||||
geometry.triangles.index_format = GetIndexFormat();
|
||||
geometry.triangles.index_count = subset.indexCount;
|
||||
geometry.triangles.index_offset = ib.offset / GetIndexStride() + subset.indexOffset;
|
||||
geometry.triangles.vertex_count = (uint32_t)vertex_positions.size();
|
||||
geometry.triangles.vertex_format = Format::R32G32B32_FLOAT;
|
||||
geometry.triangles.vertex_stride = sizeof(MeshComponent::Vertex_POS);
|
||||
}
|
||||
|
||||
bool success = device->CreateRaytracingAccelerationStructure(&desc, &BLASes[lod]);
|
||||
assert(success);
|
||||
device->SetName(&BLASes[lod], std::string("MeshComponent::BLAS[LOD" + std::to_string(lod) + "]").c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
void MeshComponent::CreateStreamoutRenderData()
|
||||
@@ -4223,12 +4228,39 @@ namespace wi::scene
|
||||
if (material != nullptr)
|
||||
{
|
||||
subset.materialIndex = (uint32_t)materials.GetIndex(subset.materialID);
|
||||
const uint32_t lod_index = mesh.subsets_per_lod > 0 ? subsetIndex / mesh.subsets_per_lod : 0;
|
||||
if (lod_index == 0 && mesh.BLAS.IsValid())
|
||||
}
|
||||
else
|
||||
{
|
||||
subset.materialIndex = 0;
|
||||
}
|
||||
|
||||
geometry.indexOffset = subset.indexOffset;
|
||||
geometry.materialIndex = subset.materialIndex;
|
||||
geometry.meshletOffset = mesh.meshletCount;
|
||||
geometry.meshletCount = triangle_count_to_meshlet_count(subset.indexCount / 3u);
|
||||
mesh.meshletCount += geometry.meshletCount;
|
||||
std::memcpy(geometryArrayMapped + mesh.geometryOffset + subsetIndex, &geometry, sizeof(geometry));
|
||||
subsetIndex++;
|
||||
}
|
||||
|
||||
if (!mesh.BLASes.empty() && mesh.BLASes[0].IsValid())
|
||||
{
|
||||
const uint32_t lod_count = mesh.GetLODCount();
|
||||
assert(uint32_t(mesh.BLASes.size()) == lod_count);
|
||||
for (uint32_t lod = 0; lod < lod_count; ++lod)
|
||||
{
|
||||
uint32_t first_subset = 0;
|
||||
uint32_t last_subset = 0;
|
||||
mesh.GetLODSubsetRange(lod, first_subset, last_subset);
|
||||
for (uint32_t subsetIndex = first_subset; subsetIndex < last_subset; ++subsetIndex)
|
||||
{
|
||||
auto& geometry = mesh.BLAS.desc.bottom_level.geometries[subsetIndex];
|
||||
const MeshComponent::MeshSubset& subset = mesh.subsets[subsetIndex];
|
||||
const MaterialComponent& material = materials[subset.materialIndex];
|
||||
|
||||
const uint32_t geometry_index = subsetIndex - first_subset;
|
||||
auto& geometry = mesh.BLASes[lod].desc.bottom_level.geometries[geometry_index];
|
||||
uint32_t flags = geometry.flags;
|
||||
if (material->IsAlphaTestEnabled() || (material->GetRenderTypes() & RENDERTYPE_TRANSPARENT) || !material->IsCastingShadow())
|
||||
if (material.IsAlphaTestEnabled() || (material.GetRenderTypes() & RENDERTYPE_TRANSPARENT) || !material.IsCastingShadow())
|
||||
{
|
||||
geometry.flags &= ~RaytracingAccelerationStructureDesc::BottomLevel::Geometry::FLAG_OPAQUE;
|
||||
}
|
||||
@@ -4246,24 +4278,12 @@ namespace wi::scene
|
||||
geometry.triangles.vertex_buffer = mesh.streamoutBuffer;
|
||||
geometry.triangles.vertex_byte_offset = mesh.so_pos_nor_wind.offset;
|
||||
}
|
||||
if (material->IsDoubleSided())
|
||||
if (material.IsDoubleSided())
|
||||
{
|
||||
mesh._flags |= MeshComponent::TLAS_FORCE_DOUBLE_SIDED;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
subset.materialIndex = 0;
|
||||
}
|
||||
|
||||
geometry.indexOffset = subset.indexOffset;
|
||||
geometry.materialIndex = subset.materialIndex;
|
||||
geometry.meshletOffset = mesh.meshletCount;
|
||||
geometry.meshletCount = triangle_count_to_meshlet_count(subset.indexCount / 3u);
|
||||
mesh.meshletCount += geometry.meshletCount;
|
||||
std::memcpy(geometryArrayMapped + mesh.geometryOffset + subsetIndex, &geometry, sizeof(geometry));
|
||||
subsetIndex++;
|
||||
}
|
||||
|
||||
});
|
||||
@@ -4633,6 +4653,28 @@ namespace wi::scene
|
||||
|
||||
std::memcpy(instanceArrayMapped + args.jobIndex, &inst, sizeof(inst)); // memcpy whole structure into mapped pointer to avoid read from uncached memory
|
||||
|
||||
// LOD select:
|
||||
{
|
||||
const float distsq = wi::math::DistanceSquared(camera.Eye, object.center);
|
||||
const float radius = object.radius;
|
||||
const float radiussq = radius * radius;
|
||||
if (distsq < radiussq)
|
||||
{
|
||||
object.lod = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
const MeshComponent* mesh = meshes.GetComponent(object.meshID);
|
||||
if (mesh != nullptr && mesh->subsets_per_lod > 0)
|
||||
{
|
||||
const float dist = std::sqrt(distsq);
|
||||
const float dist_to_sphere = dist - radius;
|
||||
object.lod = uint32_t(dist_to_sphere * object.lod_distance_multiplier);
|
||||
object.lod = std::min(object.lod, mesh->GetLODCount() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (TLAS_instancesMapped != nullptr)
|
||||
{
|
||||
// TLAS instance data:
|
||||
@@ -4646,7 +4688,7 @@ namespace wi::scene
|
||||
}
|
||||
instance.instance_id = args.jobIndex;
|
||||
instance.instance_mask = layerMask & 0xFF;
|
||||
instance.bottom_level = &mesh.BLAS;
|
||||
instance.bottom_level = &mesh.BLASes[object.lod];
|
||||
instance.instance_contribution_to_hit_group_index = 0;
|
||||
instance.flags = 0;
|
||||
|
||||
@@ -4706,28 +4748,6 @@ namespace wi::scene
|
||||
wi::texturehelper::CreateTexture(object.lightmap, object.lightmapTextureData.data(), object.lightmapWidth, object.lightmapHeight, object.lightmap.desc.format);
|
||||
device->SetName(&object.lightmap, "lightmap");
|
||||
}
|
||||
|
||||
// LOD select:
|
||||
{
|
||||
const float distsq = wi::math::DistanceSquared(camera.Eye, object.center);
|
||||
const float radius = object.radius;
|
||||
const float radiussq = radius * radius;
|
||||
if (distsq < radiussq)
|
||||
{
|
||||
object.lod = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
const MeshComponent* mesh = meshes.GetComponent(object.meshID);
|
||||
if (mesh != nullptr && mesh->subsets_per_lod > 0)
|
||||
{
|
||||
const float dist = std::sqrt(distsq);
|
||||
const float dist_to_sphere = dist - radius;
|
||||
object.lod = uint32_t(dist_to_sphere * object.lod_distance_multiplier);
|
||||
object.lod = std::min(object.lod, mesh->GetLODCount() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aabb.layerMask = layerMask;
|
||||
|
||||
@@ -411,7 +411,7 @@ namespace wi::scene
|
||||
uint32_t geometryOffset = 0;
|
||||
uint32_t meshletCount = 0;
|
||||
|
||||
wi::graphics::RaytracingAccelerationStructure BLAS;
|
||||
wi::vector<wi::graphics::RaytracingAccelerationStructure> BLASes; // one BLAS per LOD
|
||||
enum BLAS_STATE
|
||||
{
|
||||
BLAS_STATE_NEEDS_REBUILD,
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace wi::version
|
||||
// minor features, major updates, breaking compatibility changes
|
||||
const int minor = 71;
|
||||
// minor bug fixes, alterations, refactors, updates
|
||||
const int revision = 32;
|
||||
const int revision = 33;
|
||||
|
||||
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user