Add support for multiple meshes (DoomLevelSubmesh)

This commit is contained in:
Magnus Norddahl 2023-09-25 23:28:49 +02:00
commit 65929d021f
8 changed files with 292 additions and 347 deletions

View file

@ -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
}
};