Add support for multiple meshes (DoomLevelSubmesh)
This commit is contained in:
parent
fae22f1bb7
commit
65929d021f
8 changed files with 292 additions and 347 deletions
|
|
@ -183,17 +183,44 @@ struct LevelMeshSurfaceStats
|
|||
Stats surfaces, pixels;
|
||||
};
|
||||
|
||||
class LevelMesh
|
||||
class LevelSubmesh
|
||||
{
|
||||
public:
|
||||
LevelMesh()
|
||||
LevelSubmesh()
|
||||
{
|
||||
// Default portal
|
||||
LevelMeshPortal portal;
|
||||
Portals.Push(portal);
|
||||
|
||||
// Default empty mesh (we can't make it completely empty since vulkan doesn't like that)
|
||||
float minval = -100001.0f;
|
||||
float maxval = -100000.0f;
|
||||
MeshVertices.Push({ minval, minval, minval });
|
||||
MeshVertices.Push({ maxval, minval, minval });
|
||||
MeshVertices.Push({ maxval, maxval, minval });
|
||||
MeshVertices.Push({ minval, minval, minval });
|
||||
MeshVertices.Push({ minval, maxval, minval });
|
||||
MeshVertices.Push({ maxval, maxval, minval });
|
||||
MeshVertices.Push({ minval, minval, maxval });
|
||||
MeshVertices.Push({ maxval, minval, maxval });
|
||||
MeshVertices.Push({ maxval, maxval, maxval });
|
||||
MeshVertices.Push({ minval, minval, maxval });
|
||||
MeshVertices.Push({ minval, maxval, maxval });
|
||||
MeshVertices.Push({ maxval, maxval, maxval });
|
||||
|
||||
MeshVertexUVs.Resize(MeshVertices.Size());
|
||||
|
||||
for (int i = 0; i < 3 * 4; i++)
|
||||
MeshElements.Push(i);
|
||||
|
||||
UpdateCollision();
|
||||
}
|
||||
|
||||
virtual ~LevelMesh() = default;
|
||||
virtual ~LevelSubmesh() = default;
|
||||
|
||||
virtual LevelMeshSurface* GetSurface(int index) { return nullptr; }
|
||||
virtual unsigned int GetSurfaceIndex(const LevelMeshSurface* surface) const { return 0xffffffff; }
|
||||
virtual int GetSurfaceCount() { return 0; }
|
||||
|
||||
TArray<FVector3> MeshVertices;
|
||||
TArray<FVector2> MeshVertexUVs;
|
||||
|
|
@ -201,26 +228,26 @@ public:
|
|||
TArray<uint32_t> MeshElements;
|
||||
TArray<int> MeshSurfaceIndexes;
|
||||
|
||||
std::unique_ptr<TriangleMeshShape> Collision;
|
||||
|
||||
virtual LevelMeshSurface* GetSurface(int index) { return nullptr; }
|
||||
virtual unsigned int GetSurfaceIndex(const LevelMeshSurface* surface) const { return 0xffffffff; }
|
||||
virtual int GetSurfaceCount() { return 0; }
|
||||
|
||||
virtual int AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLight* list, int listMaxSize) { return 0; }
|
||||
|
||||
TArray<LevelMeshPortal> Portals;
|
||||
|
||||
std::unique_ptr<TriangleMeshShape> Collision;
|
||||
|
||||
// Lightmap atlas
|
||||
int LMTextureCount = 0;
|
||||
int LMTextureSize = 0;
|
||||
TArray<uint16_t> LMTextureData; // TODO better place for this?
|
||||
TArray<uint16_t> LMTextureData;
|
||||
|
||||
inline uint32_t AtlasPixelCount() const { return uint32_t(LMTextureCount * LMTextureSize * LMTextureSize); }
|
||||
inline LevelMeshSurfaceStats GatherSurfacePixelStats() //const
|
||||
uint16_t LightmapSampleDistance = 16;
|
||||
|
||||
uint32_t AtlasPixelCount() const { return uint32_t(LMTextureCount * LMTextureSize * LMTextureSize); }
|
||||
|
||||
void UpdateCollision()
|
||||
{
|
||||
LevelMeshSurfaceStats stats;
|
||||
Collision = std::make_unique<TriangleMeshShape>(MeshVertices.Data(), MeshVertices.Size(), MeshElements.Data(), MeshElements.Size());
|
||||
}
|
||||
|
||||
void GatherSurfacePixelStats(LevelMeshSurfaceStats& stats)
|
||||
{
|
||||
int count = GetSurfaceCount();
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
|
|
@ -240,63 +267,9 @@ public:
|
|||
stats.pixels.sky += area;
|
||||
}
|
||||
}
|
||||
|
||||
stats.surfaces.total = count;
|
||||
return stats;
|
||||
stats.surfaces.total += count;
|
||||
}
|
||||
|
||||
// Map defaults
|
||||
FVector3 SunDirection = FVector3(0.0f, 0.0f, -1.0f);
|
||||
FVector3 SunColor = FVector3(0.0f, 0.0f, 0.0f);
|
||||
uint16_t LightmapSampleDistance = 16;
|
||||
|
||||
LevelMeshSurface* Trace(const FVector3& start, FVector3 direction, float maxDist)
|
||||
{
|
||||
maxDist = std::max(maxDist - 10.0f, 0.0f);
|
||||
|
||||
FVector3 origin = start;
|
||||
FVector3 end;
|
||||
|
||||
auto collision = Collision.get();
|
||||
|
||||
LevelMeshSurface* hitSurface = nullptr;
|
||||
|
||||
while (true)
|
||||
{
|
||||
end = origin + direction * maxDist;
|
||||
|
||||
auto hit = TriangleMeshShape::find_first_hit(collision, origin, end);
|
||||
|
||||
if (hit.triangle < 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
hitSurface = GetSurface(MeshSurfaceIndexes[hit.triangle]);
|
||||
auto portal = hitSurface->portalIndex;
|
||||
|
||||
if (!portal)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
auto& transformation = Portals[portal];
|
||||
|
||||
auto travelDist = hit.fraction * maxDist + 2.0f;
|
||||
if (travelDist >= maxDist)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
origin = transformation.TransformPosition(origin + direction * travelDist);
|
||||
direction = transformation.TransformRotation(direction);
|
||||
maxDist -= travelDist;
|
||||
}
|
||||
|
||||
return hitSurface; // I hit something
|
||||
}
|
||||
|
||||
protected:
|
||||
void BuildSmoothingGroups()
|
||||
{
|
||||
TArray<LevelMeshSmoothingGroup> SmoothingGroups;
|
||||
|
|
@ -346,6 +319,7 @@ protected:
|
|||
for (int i = 0, count = GetSurfaceCount(); i < count; i++)
|
||||
{
|
||||
auto targetSurface = GetSurface(i);
|
||||
targetSurface->tileSurfaces.Clear();
|
||||
for (LevelMeshSurface* surface : SmoothingGroups[targetSurface->smoothingGroupIndex].surfaces)
|
||||
{
|
||||
FVector2 minUV = ToUV(surface->bounds.min, targetSurface);
|
||||
|
|
@ -358,6 +332,7 @@ protected:
|
|||
}
|
||||
}
|
||||
|
||||
private:
|
||||
FVector2 ToUV(const FVector3& vert, const LevelMeshSurface* targetSurface)
|
||||
{
|
||||
FVector3 localPos = vert - targetSurface->translateWorldToLocal;
|
||||
|
|
@ -366,3 +341,73 @@ protected:
|
|||
return FVector2(u, v);
|
||||
}
|
||||
};
|
||||
|
||||
class LevelMesh
|
||||
{
|
||||
public:
|
||||
virtual ~LevelMesh() = default;
|
||||
|
||||
std::unique_ptr<LevelSubmesh> StaticMesh = std::make_unique<LevelSubmesh>();
|
||||
std::unique_ptr<LevelSubmesh> DynamicMesh = std::make_unique<LevelSubmesh>();
|
||||
|
||||
virtual int AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLight* list, int listMaxSize) { return 0; }
|
||||
|
||||
LevelMeshSurfaceStats GatherSurfacePixelStats()
|
||||
{
|
||||
LevelMeshSurfaceStats stats;
|
||||
StaticMesh->GatherSurfacePixelStats(stats);
|
||||
DynamicMesh->GatherSurfacePixelStats(stats);
|
||||
return stats;
|
||||
}
|
||||
|
||||
// Map defaults
|
||||
FVector3 SunDirection = FVector3(0.0f, 0.0f, -1.0f);
|
||||
FVector3 SunColor = FVector3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
LevelMeshSurface* Trace(const FVector3& start, FVector3 direction, float maxDist)
|
||||
{
|
||||
maxDist = std::max(maxDist - 10.0f, 0.0f);
|
||||
|
||||
FVector3 origin = start;
|
||||
|
||||
LevelMeshSurface* hitSurface = nullptr;
|
||||
|
||||
while (true)
|
||||
{
|
||||
FVector3 end = origin + direction * maxDist;
|
||||
|
||||
TraceHit hit0 = TriangleMeshShape::find_first_hit(StaticMesh->Collision.get(), origin, end);
|
||||
TraceHit hit1 = TriangleMeshShape::find_first_hit(DynamicMesh->Collision.get(), origin, end);
|
||||
|
||||
LevelSubmesh* hitmesh = hit0.fraction < hit1.fraction ? StaticMesh.get() : DynamicMesh.get();
|
||||
TraceHit hit = hit0.fraction < hit1.fraction ? hit0 : hit1;
|
||||
|
||||
if (hit.triangle < 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
hitSurface = hitmesh->GetSurface(hitmesh->MeshSurfaceIndexes[hit.triangle]);
|
||||
auto portal = hitSurface->portalIndex;
|
||||
|
||||
if (!portal)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
auto& transformation = hitmesh->Portals[portal];
|
||||
|
||||
auto travelDist = hit.fraction * maxDist + 2.0f;
|
||||
if (travelDist >= maxDist)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
origin = transformation.TransformPosition(origin + direction * travelDist);
|
||||
direction = transformation.TransformRotation(direction);
|
||||
maxDist -= travelDist;
|
||||
}
|
||||
|
||||
return hitSurface; // I hit something
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ void VkLightmap::Render()
|
|||
LightmapRaytracePC pc;
|
||||
pc.TileX = (float)selectedSurface.X;
|
||||
pc.TileY = (float)selectedSurface.Y;
|
||||
pc.SurfaceIndex = mesh->GetSurfaceIndex(targetSurface);
|
||||
pc.SurfaceIndex = mesh->StaticMesh->GetSurfaceIndex(targetSurface);
|
||||
pc.TextureSize = (float)bakeImageSize;
|
||||
pc.TileWidth = (float)targetSurface->texWidth;
|
||||
pc.TileHeight = (float)targetSurface->texHeight;
|
||||
|
|
|
|||
|
|
@ -32,26 +32,6 @@ VkRaytrace::VkRaytrace(VulkanRenderDevice* fb) : fb(fb)
|
|||
{
|
||||
useRayQuery = fb->GetDevice()->SupportsExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME);
|
||||
|
||||
NullMesh.MeshVertices.Push({ -1.0f, -1.0f, -1.0f });
|
||||
NullMesh.MeshVertices.Push({ 1.0f, -1.0f, -1.0f });
|
||||
NullMesh.MeshVertices.Push({ 1.0f, 1.0f, -1.0f });
|
||||
NullMesh.MeshVertices.Push({ -1.0f, -1.0f, -1.0f });
|
||||
NullMesh.MeshVertices.Push({ -1.0f, 1.0f, -1.0f });
|
||||
NullMesh.MeshVertices.Push({ 1.0f, 1.0f, -1.0f });
|
||||
NullMesh.MeshVertices.Push({ -1.0f, -1.0f, 1.0f });
|
||||
NullMesh.MeshVertices.Push({ 1.0f, -1.0f, 1.0f });
|
||||
NullMesh.MeshVertices.Push({ 1.0f, 1.0f, 1.0f });
|
||||
NullMesh.MeshVertices.Push({ -1.0f, -1.0f, 1.0f });
|
||||
NullMesh.MeshVertices.Push({ -1.0f, 1.0f, 1.0f });
|
||||
NullMesh.MeshVertices.Push({ 1.0f, 1.0f, 1.0f });
|
||||
|
||||
NullMesh.MeshVertexUVs.Resize(NullMesh.MeshVertices.Size());
|
||||
|
||||
for (int i = 0; i < 3 * 4; i++)
|
||||
NullMesh.MeshElements.Push(i);
|
||||
|
||||
NullMesh.Collision = std::make_unique<TriangleMeshShape>(NullMesh.MeshVertices.Data(), NullMesh.MeshVertices.Size(), NullMesh.MeshElements.Data(), NullMesh.MeshElements.Size());
|
||||
|
||||
SetLevelMesh(nullptr);
|
||||
}
|
||||
|
||||
|
|
@ -99,17 +79,19 @@ void VkRaytrace::CreateBuffers()
|
|||
{
|
||||
std::vector<CollisionNode> nodes = CreateCollisionNodes();
|
||||
|
||||
auto submesh = Mesh->StaticMesh.get();
|
||||
|
||||
// std430 alignment rules forces us to convert the vec3 to a vec4
|
||||
std::vector<SurfaceVertex> vertices;
|
||||
vertices.reserve(Mesh->MeshVertices.Size());
|
||||
for (int i = 0, count = Mesh->MeshVertices.Size(); i < count; ++i)
|
||||
vertices.push_back({ { Mesh->MeshVertices[i], 1.0f }, Mesh->MeshVertexUVs[i], float(i), i + 10000.0f});
|
||||
vertices.reserve(submesh->MeshVertices.Size());
|
||||
for (int i = 0, count = submesh->MeshVertices.Size(); i < count; ++i)
|
||||
vertices.push_back({ { submesh->MeshVertices[i], 1.0f }, submesh->MeshVertexUVs[i], float(i), i + 10000.0f});
|
||||
|
||||
CollisionNodeBufferHeader nodesHeader;
|
||||
nodesHeader.root = Mesh->Collision->get_root();
|
||||
nodesHeader.root = submesh->Collision->get_root();
|
||||
|
||||
TArray<PortalInfo> portalInfo;
|
||||
for (auto& portal : Mesh->Portals)
|
||||
for (auto& portal : submesh->Portals)
|
||||
{
|
||||
PortalInfo info;
|
||||
info.transformation = portal.transformation;
|
||||
|
|
@ -117,9 +99,9 @@ void VkRaytrace::CreateBuffers()
|
|||
}
|
||||
|
||||
TArray<SurfaceInfo> surfaceInfo;
|
||||
for (int i = 0, count = Mesh->GetSurfaceCount(); i < count; i++)
|
||||
for (int i = 0, count = submesh->GetSurfaceCount(); i < count; i++)
|
||||
{
|
||||
LevelMeshSurface* surface = Mesh->GetSurface(i);
|
||||
LevelMeshSurface* surface = submesh->GetSurface(i);
|
||||
|
||||
SurfaceInfo info;
|
||||
info.Normal = surface->plane.XYZ();
|
||||
|
|
@ -162,7 +144,7 @@ void VkRaytrace::CreateBuffers()
|
|||
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
|
||||
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR : 0) |
|
||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
|
||||
.Size((size_t)Mesh->MeshElements.Size() * sizeof(uint32_t))
|
||||
.Size((size_t)submesh->MeshElements.Size() * sizeof(uint32_t))
|
||||
.DebugName("IndexBuffer")
|
||||
.Create(fb->GetDevice());
|
||||
|
||||
|
|
@ -174,7 +156,7 @@ void VkRaytrace::CreateBuffers()
|
|||
|
||||
SurfaceIndexBuffer = BufferBuilder()
|
||||
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
||||
.Size(Mesh->MeshSurfaceIndexes.Size() * sizeof(int))
|
||||
.Size(submesh->MeshSurfaceIndexes.Size() * sizeof(int))
|
||||
.DebugName("SurfaceBuffer")
|
||||
.Create(fb->GetDevice());
|
||||
|
||||
|
|
@ -192,9 +174,9 @@ void VkRaytrace::CreateBuffers()
|
|||
|
||||
auto transferBuffer = BufferTransfer()
|
||||
.AddBuffer(VertexBuffer.get(), vertices.data(), vertices.size() * sizeof(SurfaceVertex))
|
||||
.AddBuffer(IndexBuffer.get(), Mesh->MeshElements.Data(), (size_t)Mesh->MeshElements.Size() * sizeof(uint32_t))
|
||||
.AddBuffer(IndexBuffer.get(), submesh->MeshElements.Data(), (size_t)submesh->MeshElements.Size() * sizeof(uint32_t))
|
||||
.AddBuffer(NodeBuffer.get(), &nodesHeader, sizeof(CollisionNodeBufferHeader), nodes.data(), nodes.size() * sizeof(CollisionNode))
|
||||
.AddBuffer(SurfaceIndexBuffer.get(), Mesh->MeshSurfaceIndexes.Data(), Mesh->MeshSurfaceIndexes.Size() * sizeof(int))
|
||||
.AddBuffer(SurfaceIndexBuffer.get(), submesh->MeshSurfaceIndexes.Data(), submesh->MeshSurfaceIndexes.Size() * sizeof(int))
|
||||
.AddBuffer(SurfaceBuffer.get(), surfaceInfo.Data(), surfaceInfo.Size() * sizeof(SurfaceInfo))
|
||||
.AddBuffer(PortalBuffer.get(), portalInfo.Data(), portalInfo.Size() * sizeof(PortalInfo))
|
||||
.Execute(fb->GetDevice(), fb->GetCommands()->GetTransferCommands());
|
||||
|
|
@ -208,6 +190,8 @@ void VkRaytrace::CreateBuffers()
|
|||
|
||||
void VkRaytrace::CreateStaticBLAS()
|
||||
{
|
||||
auto submesh = Mesh->StaticMesh.get();
|
||||
|
||||
VkAccelerationStructureBuildGeometryInfoKHR buildInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR };
|
||||
VkAccelerationStructureGeometryKHR accelStructBLDesc = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR };
|
||||
VkAccelerationStructureGeometryKHR* geometries[] = { &accelStructBLDesc };
|
||||
|
|
@ -222,7 +206,7 @@ void VkRaytrace::CreateStaticBLAS()
|
|||
accelStructBLDesc.geometry.triangles.vertexStride = sizeof(SurfaceVertex);
|
||||
accelStructBLDesc.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32;
|
||||
accelStructBLDesc.geometry.triangles.indexData.deviceAddress = IndexBuffer->GetDeviceAddress();
|
||||
accelStructBLDesc.geometry.triangles.maxVertex = Mesh->MeshVertices.Size() - 1;
|
||||
accelStructBLDesc.geometry.triangles.maxVertex = submesh->MeshVertices.Size() - 1;
|
||||
|
||||
buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
|
||||
buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
||||
|
|
@ -230,7 +214,7 @@ void VkRaytrace::CreateStaticBLAS()
|
|||
buildInfo.geometryCount = 1;
|
||||
buildInfo.ppGeometries = geometries;
|
||||
|
||||
uint32_t maxPrimitiveCount = Mesh->MeshElements.Size() / 3;
|
||||
uint32_t maxPrimitiveCount = submesh->MeshElements.Size() / 3;
|
||||
|
||||
VkAccelerationStructureBuildSizesInfoKHR sizeInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR };
|
||||
vkGetAccelerationStructureBuildSizesKHR(fb->GetDevice()->device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, &maxPrimitiveCount, &sizeInfo);
|
||||
|
|
@ -428,9 +412,11 @@ void VkRaytrace::CreateTopLevelAS()
|
|||
|
||||
std::vector<CollisionNode> VkRaytrace::CreateCollisionNodes()
|
||||
{
|
||||
auto submesh = Mesh->StaticMesh.get();
|
||||
|
||||
std::vector<CollisionNode> nodes;
|
||||
nodes.reserve(Mesh->Collision->get_nodes().size());
|
||||
for (const auto& node : Mesh->Collision->get_nodes())
|
||||
nodes.reserve(submesh->Collision->get_nodes().size());
|
||||
for (const auto& node : submesh->Collision->get_nodes())
|
||||
{
|
||||
CollisionNode info;
|
||||
info.center = node.aabb.Center;
|
||||
|
|
|
|||
|
|
@ -480,9 +480,9 @@ void VulkanRenderDevice::BeginFrame()
|
|||
levelMeshChanged = false;
|
||||
mRaytrace->SetLevelMesh(levelMesh);
|
||||
|
||||
if (levelMesh && levelMesh->GetSurfaceCount() > 0)
|
||||
if (levelMesh && levelMesh->StaticMesh->GetSurfaceCount() > 0)
|
||||
{
|
||||
GetTextureManager()->CreateLightmap(levelMesh->LMTextureSize, levelMesh->LMTextureCount, std::move(levelMesh->LMTextureData));
|
||||
GetTextureManager()->CreateLightmap(levelMesh->StaticMesh->LMTextureSize, levelMesh->StaticMesh->LMTextureCount, std::move(levelMesh->StaticMesh->LMTextureData));
|
||||
GetLightmap()->SetLevelMesh(levelMesh);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue