mirror of
https://github.com/ZDoom/ZDRay.git
synced 2025-02-21 10:41:24 +00:00
Upgrade lightmapper to latest internal version
This commit is contained in:
parent
a9da46d00d
commit
a6d3958ad2
27 changed files with 1966 additions and 2288 deletions
|
@ -69,8 +69,6 @@ set(ZDRAY_SOURCES
|
||||||
src/lightmapper/vk_lightmapper.h
|
src/lightmapper/vk_lightmapper.h
|
||||||
src/lightmapper/doom_levelmesh.cpp
|
src/lightmapper/doom_levelmesh.cpp
|
||||||
src/lightmapper/doom_levelmesh.h
|
src/lightmapper/doom_levelmesh.h
|
||||||
src/lightmapper/doom_levelsubmesh.cpp
|
|
||||||
src/lightmapper/doom_levelsubmesh.h
|
|
||||||
src/lightmapper/gpuraytracer.cpp
|
src/lightmapper/gpuraytracer.cpp
|
||||||
src/lightmapper/gpuraytracer.h
|
src/lightmapper/gpuraytracer.h
|
||||||
src/lightmapper/stacktrace.cpp
|
src/lightmapper/stacktrace.cpp
|
||||||
|
@ -82,8 +80,10 @@ set(ZDRAY_SOURCES
|
||||||
src/lightmapper/glsl/frag_copy.glsl.h
|
src/lightmapper/glsl/frag_copy.glsl.h
|
||||||
src/lightmapper/glsl/frag_raytrace.glsl.h
|
src/lightmapper/glsl/frag_raytrace.glsl.h
|
||||||
src/lightmapper/glsl/frag_resolve.glsl.h
|
src/lightmapper/glsl/frag_resolve.glsl.h
|
||||||
|
src/lightmapper/glsl/montecarlo.glsl.h
|
||||||
src/lightmapper/glsl/polyfill_rayquery.glsl.h
|
src/lightmapper/glsl/polyfill_rayquery.glsl.h
|
||||||
src/lightmapper/glsl/trace_ambient_occlusion.glsl.h
|
src/lightmapper/glsl/trace_ambient_occlusion.glsl.h
|
||||||
|
src/lightmapper/glsl/trace_bounce.glsl.h
|
||||||
src/lightmapper/glsl/trace_levelmesh.glsl.h
|
src/lightmapper/glsl/trace_levelmesh.glsl.h
|
||||||
src/lightmapper/glsl/trace_light.glsl.h
|
src/lightmapper/glsl/trace_light.glsl.h
|
||||||
src/lightmapper/glsl/trace_sunlight.glsl.h
|
src/lightmapper/glsl/trace_sunlight.glsl.h
|
||||||
|
|
|
@ -414,6 +414,14 @@ struct ThingLight
|
||||||
IntSector *sector;
|
IntSector *sector;
|
||||||
MapSubsectorEx *ssect;
|
MapSubsectorEx *ssect;
|
||||||
|
|
||||||
|
// Locations in the level mesh light list. Ends with index = 0 or all entries used
|
||||||
|
enum { max_levelmesh_entries = 4 };
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
int portalgroup = 0;
|
||||||
|
} levelmesh[max_levelmesh_entries];
|
||||||
|
|
||||||
// Portal related functionality
|
// Portal related functionality
|
||||||
std::optional<FVector3> relativePosition;
|
std::optional<FVector3> relativePosition;
|
||||||
int sectorGroup = 0;
|
int sectorGroup = 0;
|
||||||
|
|
|
@ -841,8 +841,11 @@ void FProcessor::BuildLightmaps()
|
||||||
|
|
||||||
printf(" Creating level mesh\n");
|
printf(" Creating level mesh\n");
|
||||||
LightmapMesh = std::make_unique<DoomLevelMesh>(Level);
|
LightmapMesh = std::make_unique<DoomLevelMesh>(Level);
|
||||||
printf(" Surfaces: %d\n", LightmapMesh->StaticMesh->GetSurfaceCount());
|
LightmapMesh->SetupTileTransforms();
|
||||||
printf(" Tiles: %d\n", (int)LightmapMesh->StaticMesh->LightmapTiles.Size());
|
LightmapMesh->PackLightmapAtlas(0);
|
||||||
|
LightmapMesh->BeginFrame(Level);
|
||||||
|
printf(" Surfaces: %d\n", LightmapMesh->GetSurfaceCount());
|
||||||
|
printf(" Tiles: %d\n", (int)LightmapMesh->LightmapTiles.Size());
|
||||||
|
|
||||||
std::unique_ptr<GPURaytracer> gpuraytracer = std::make_unique<GPURaytracer>();
|
std::unique_ptr<GPURaytracer> gpuraytracer = std::make_unique<GPURaytracer>();
|
||||||
gpuraytracer->Raytrace(LightmapMesh.get());
|
gpuraytracer->Raytrace(LightmapMesh.get());
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,61 +2,20 @@
|
||||||
|
|
||||||
#include "framework/zstring.h"
|
#include "framework/zstring.h"
|
||||||
#include "hw_levelmesh.h"
|
#include "hw_levelmesh.h"
|
||||||
|
#include "hw_lightmaptile.h"
|
||||||
#include "level/doomdata.h"
|
#include "level/doomdata.h"
|
||||||
|
#include <map>
|
||||||
|
|
||||||
struct FLevel;
|
struct FLevel;
|
||||||
class FWadWriter;
|
class FWadWriter;
|
||||||
|
struct FPolyObj;
|
||||||
class DoomLevelMesh : public LevelMesh
|
struct HWWallDispatcher;
|
||||||
{
|
class DoomLevelMesh;
|
||||||
public:
|
class MeshBuilder;
|
||||||
DoomLevelMesh(FLevel& doomMap);
|
|
||||||
|
|
||||||
int AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLight* list, int listMaxSize) override;
|
|
||||||
|
|
||||||
void BeginFrame(FLevel& doomMap);
|
|
||||||
bool TraceSky(const FVector3& start, FVector3 direction, float dist);
|
|
||||||
void DumpMesh(const FString& objFilename, const FString& mtlFilename) const;
|
|
||||||
void AddLightmapLump(FLevel& doomMap, FWadWriter& out);
|
|
||||||
|
|
||||||
void BuildSectorGroups(const FLevel& doomMap);
|
|
||||||
|
|
||||||
TArray<int> sectorGroup; // index is sector, value is sectorGroup
|
|
||||||
TArray<int> sectorPortals[2]; // index is sector+plane, value is index into the portal list
|
|
||||||
TArray<int> linePortals; // index is linedef, value is index into the portal list
|
|
||||||
|
|
||||||
private:
|
|
||||||
void CreatePortals(FLevel& doomMap);
|
|
||||||
void BuildLightLists(FLevel& doomMap);
|
|
||||||
void PropagateLight(FLevel& doomMap, ThingLight* light, int recursiveDepth = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
class DoomLevelMesh : public LevelMesh
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DoomLevelMesh(FLevel& level, int samples, int lmdims);
|
|
||||||
|
|
||||||
int AddSurfaceLights(const LevelMeshSurface* surface, LevelMeshLight* list, int listMaxSize) override;
|
|
||||||
void DumpMesh(const FString& objFilename, const FString& mtlFilename) const;
|
|
||||||
void AddLightmapLump(FLevel& doomMap, FWadWriter& out);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void BuildLightLists(FLevel& doomMap);
|
|
||||||
void PropagateLight(FLevel& doomMap, ThingLight* light, int recursiveDepth = 0);
|
|
||||||
|
|
||||||
// Portal to portals[] index
|
|
||||||
//std::map<Portal, int, IdenticalPortalComparator> portalCache;
|
|
||||||
|
|
||||||
// Portal lights
|
|
||||||
//std::vector<std::unique_ptr<ThingLight>> portalLights;
|
|
||||||
//std::set<Portal, RecursivePortalComparator> touchedPortals;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum DoomLevelMeshSurfaceType
|
enum DoomLevelMeshSurfaceType
|
||||||
{
|
{
|
||||||
ST_UNKNOWN,
|
ST_NONE,
|
||||||
ST_MIDDLESIDE,
|
ST_MIDDLESIDE,
|
||||||
ST_UPPERSIDE,
|
ST_UPPERSIDE,
|
||||||
ST_LOWERSIDE,
|
ST_LOWERSIDE,
|
||||||
|
@ -66,62 +25,99 @@ enum DoomLevelMeshSurfaceType
|
||||||
|
|
||||||
struct DoomLevelMeshSurface : public LevelMeshSurface
|
struct DoomLevelMeshSurface : public LevelMeshSurface
|
||||||
{
|
{
|
||||||
DoomLevelMeshSurfaceType Type = ST_UNKNOWN;
|
DoomLevelMeshSurfaceType Type = ST_NONE;
|
||||||
int TypeIndex = 0;
|
int TypeIndex = 0;
|
||||||
|
|
||||||
MapSubsectorEx* Subsector = nullptr;
|
MapSubsectorEx* Subsector = nullptr;
|
||||||
IntSideDef* Side = nullptr;
|
IntSideDef* Side = nullptr;
|
||||||
IntSector* ControlSector = nullptr;
|
IntSector* ControlSector = nullptr;
|
||||||
|
|
||||||
float* TexCoords = nullptr;
|
int PipelineID = 0;
|
||||||
|
|
||||||
std::vector<ThingLight*> LightList;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DoomLevelSubmesh : public LevelSubmesh
|
struct SideSurfaceRange
|
||||||
|
{
|
||||||
|
int StartSurface = 0;
|
||||||
|
int SurfaceCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FlatSurfaceRange
|
||||||
|
{
|
||||||
|
int StartSurface = 0;
|
||||||
|
int SurfaceCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DoomLevelMesh : public LevelMesh
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void CreateStatic(FLevel& doomMap);
|
DoomLevelMesh(FLevel& doomMap);
|
||||||
|
|
||||||
LevelMeshSurface* GetSurface(int index) override { return &Surfaces[index]; }
|
LevelMeshSurface* GetSurface(int index) override { return &Surfaces[index]; }
|
||||||
unsigned int GetSurfaceIndex(const LevelMeshSurface* surface) const override { return (unsigned int)(ptrdiff_t)(static_cast<const DoomLevelMeshSurface*>(surface) - Surfaces.Data()); }
|
unsigned int GetSurfaceIndex(const LevelMeshSurface* surface) const override { return (unsigned int)(ptrdiff_t)(static_cast<const DoomLevelMeshSurface*>(surface) - Surfaces.Data()); }
|
||||||
int GetSurfaceCount() override { return Surfaces.Size(); }
|
int GetSurfaceCount() override { return Surfaces.Size(); }
|
||||||
|
|
||||||
|
void BeginFrame(FLevel& doomMap);
|
||||||
|
bool TraceSky(const FVector3& start, FVector3 direction, float dist);
|
||||||
void DumpMesh(const FString& objFilename, const FString& mtlFilename) const;
|
void DumpMesh(const FString& objFilename, const FString& mtlFilename) const;
|
||||||
|
|
||||||
// Used by Maploader
|
|
||||||
void BindLightmapSurfacesToGeometry(FLevel& doomMap);
|
|
||||||
void PackLightmapAtlas(int lightmapStartIndex);
|
|
||||||
void CreatePortals(FLevel& doomMap);
|
|
||||||
|
|
||||||
TArray<DoomLevelMeshSurface> Surfaces;
|
|
||||||
TArray<FVector2> LightmapUvs;
|
|
||||||
TArray<int> sectorGroup; // index is sector, value is sectorGroup
|
|
||||||
|
|
||||||
private:
|
|
||||||
void BuildSectorGroups(const FLevel& doomMap);
|
void BuildSectorGroups(const FLevel& doomMap);
|
||||||
|
|
||||||
void CreateSubsectorSurfaces(FLevel& doomMap);
|
void AddLightmapLump(FLevel& doomMap, FWadWriter& wadFile);
|
||||||
void CreateCeilingSurface(FLevel& doomMap, MapSubsectorEx* sub, IntSector* sector, IntSector* controlSector, int typeIndex);
|
|
||||||
void CreateFloorSurface(FLevel& doomMap, MapSubsectorEx* sub, IntSector* sector, IntSector* controlSector, int typeIndex);
|
TArray<DoomLevelMeshSurface> Surfaces;
|
||||||
|
|
||||||
|
TArray<int> sectorGroup; // index is sector, value is sectorGroup
|
||||||
|
TArray<int> sectorPortals[2]; // index is sector+plane, value is index into the portal list
|
||||||
|
TArray<int> linePortals; // index is linedef, value is index into the portal list
|
||||||
|
|
||||||
|
void CreateLights(FLevel& doomMap);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void CreateSurfaces(FLevel& doomMap);
|
||||||
|
|
||||||
void CreateSideSurfaces(FLevel& doomMap, IntSideDef* side);
|
void CreateSideSurfaces(FLevel& doomMap, IntSideDef* side);
|
||||||
void CreateLinePortalSurface(FLevel& doomMap, IntSideDef* side);
|
|
||||||
void CreateLineHorizonSurface(FLevel& doomMap, IntSideDef* side);
|
void CreateLineHorizonSurface(FLevel& doomMap, IntSideDef* side);
|
||||||
void CreateFrontWallSurface(FLevel& doomMap, IntSideDef* side);
|
void CreateFrontWallSurface(FLevel& doomMap, IntSideDef* side);
|
||||||
void CreateTopWallSurface(FLevel& doomMap, IntSideDef* side);
|
|
||||||
void CreateMidWallSurface(FLevel& doomMap, IntSideDef* side);
|
void CreateMidWallSurface(FLevel& doomMap, IntSideDef* side);
|
||||||
void CreateBottomWallSurface(FLevel& doomMap, IntSideDef* side);
|
|
||||||
void Create3DFloorWallSurfaces(FLevel& doomMap, IntSideDef* side);
|
void Create3DFloorWallSurfaces(FLevel& doomMap, IntSideDef* side);
|
||||||
|
void CreateTopWallSurface(FLevel& doomMap, IntSideDef* side);
|
||||||
|
void CreateBottomWallSurface(FLevel& doomMap, IntSideDef* side);
|
||||||
|
void AddWallVertices(DoomLevelMeshSurface& surf, FFlatVertex* verts);
|
||||||
void SetSideTextureUVs(DoomLevelMeshSurface& surface, IntSideDef* side, WallPart texpart, float v1TopZ, float v1BottomZ, float v2TopZ, float v2BottomZ);
|
void SetSideTextureUVs(DoomLevelMeshSurface& surface, IntSideDef* side, WallPart texpart, float v1TopZ, float v1BottomZ, float v2TopZ, float v2BottomZ);
|
||||||
|
|
||||||
void SetupLightmapUvs(FLevel& doomMap);
|
void CreateFloorSurface(FLevel& doomMap, MapSubsectorEx* sub, IntSector* sector, IntSector* controlSector, int typeIndex);
|
||||||
|
void CreateCeilingSurface(FLevel& doomMap, MapSubsectorEx* sub, IntSector* sector, IntSector* controlSector, int typeIndex);
|
||||||
|
|
||||||
void CreateIndexes();
|
void AddSurfaceToTile(DoomLevelMeshSurface& surf, FLevel& doomMap, uint16_t sampleDimension);
|
||||||
|
int GetSampleDimension(const DoomLevelMeshSurface& surf, uint16_t sampleDimension);
|
||||||
|
|
||||||
static bool IsTopSideSky(IntSector* frontsector, IntSector* backsector, IntSideDef* side);
|
static bool IsTopSideSky(IntSector* frontsector, IntSector* backsector, IntSideDef* side);
|
||||||
static bool IsTopSideVisible(IntSideDef* side);
|
static bool IsTopSideVisible(IntSideDef* side);
|
||||||
static bool IsBottomSideVisible(IntSideDef* side);
|
static bool IsBottomSideVisible(IntSideDef* side);
|
||||||
static bool IsSkySector(IntSector* sector, SecPlaneType plane);
|
static bool IsSkySector(IntSector* sector, SecPlaneType plane);
|
||||||
|
static bool IsDegenerate(const FVector3& v0, const FVector3& v1, const FVector3& v2);
|
||||||
|
|
||||||
|
void SortIndexes();
|
||||||
|
|
||||||
|
BBox GetBoundsFromSurface(const LevelMeshSurface& surface) const;
|
||||||
|
|
||||||
|
int AddSurfaceToTile(const DoomLevelMeshSurface& surf);
|
||||||
|
int GetSampleDimension(const DoomLevelMeshSurface& surf);
|
||||||
|
|
||||||
|
void CreatePortals(FLevel& doomMap);
|
||||||
|
|
||||||
|
void PropagateLight(FLevel& doomMap, ThingLight* light, int recursiveDepth);
|
||||||
|
int GetLightIndex(ThingLight* light, int portalgroup);
|
||||||
|
|
||||||
|
static FVector4 ToPlane(const FFlatVertex& pt1, const FFlatVertex& pt2, const FFlatVertex& pt3)
|
||||||
|
{
|
||||||
|
return ToPlane(FVector3(pt1.x, pt1.y, pt1.z), FVector3(pt2.x, pt2.y, pt2.z), FVector3(pt3.x, pt3.y, pt3.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
static FVector4 ToPlane(const FFlatVertex& pt1, const FFlatVertex& pt2, const FFlatVertex& pt3, const FFlatVertex& pt4)
|
||||||
|
{
|
||||||
|
return ToPlane(FVector3(pt1.x, pt1.y, pt1.z), FVector3(pt2.x, pt2.y, pt2.z), FVector3(pt3.x, pt3.y, pt3.z), FVector3(pt4.x, pt4.y, pt4.z));
|
||||||
|
}
|
||||||
|
|
||||||
static FVector4 ToPlane(const FVector3& pt1, const FVector3& pt2, const FVector3& pt3)
|
static FVector4 ToPlane(const FVector3& pt1, const FVector3& pt2, const FVector3& pt3)
|
||||||
{
|
{
|
||||||
|
@ -144,27 +140,7 @@ private:
|
||||||
return ToPlane(pt1, pt2, pt3);
|
return ToPlane(pt1, pt2, pt3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lightmapper
|
TArray<SideSurfaceRange> Sides;
|
||||||
|
TArray<FlatSurfaceRange> Flats;
|
||||||
enum PlaneAxis
|
std::map<LightmapTileBinding, int> bindings;
|
||||||
{
|
|
||||||
AXIS_YZ = 0,
|
|
||||||
AXIS_XZ,
|
|
||||||
AXIS_XY
|
|
||||||
};
|
|
||||||
|
|
||||||
static PlaneAxis BestAxis(const FVector4& p);
|
|
||||||
BBox GetBoundsFromSurface(const LevelMeshSurface& surface) const;
|
|
||||||
|
|
||||||
inline int AllocUvs(int amount) { return LightmapUvs.Reserve(amount); }
|
|
||||||
|
|
||||||
void BuildSurfaceParams(int lightMapTextureWidth, int lightMapTextureHeight, LevelMeshSurface& surface);
|
|
||||||
|
|
||||||
static bool IsDegenerate(const FVector3& v0, const FVector3& v1, const FVector3& v2);
|
|
||||||
|
|
||||||
static FVector2 ToFVector2(const DVector2& v) { return FVector2((float)v.X, (float)v.Y); }
|
|
||||||
static FVector3 ToFVector3(const DVector3& v) { return FVector3((float)v.X, (float)v.Y, (float)v.Z); }
|
|
||||||
static FVector4 ToFVector4(const DVector4& v) { return FVector4((float)v.X, (float)v.Y, (float)v.Z, (float)v.W); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,136 +0,0 @@
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "hw_levelmesh.h"
|
|
||||||
#include "framework/tarray.h"
|
|
||||||
#include "framework/vectors.h"
|
|
||||||
#include "framework/bounds.h"
|
|
||||||
#include "level/level.h"
|
|
||||||
#include <dp_rect_pack/dp_rect_pack.h>
|
|
||||||
#include <set>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
typedef dp::rect_pack::RectPacker<int> RectPacker;
|
|
||||||
|
|
||||||
struct FLevel;
|
|
||||||
struct FPolyObj;
|
|
||||||
struct HWWallDispatcher;
|
|
||||||
class DoomLevelMesh;
|
|
||||||
class MeshBuilder;
|
|
||||||
|
|
||||||
enum DoomLevelMeshSurfaceType
|
|
||||||
{
|
|
||||||
ST_NONE,
|
|
||||||
ST_MIDDLESIDE,
|
|
||||||
ST_UPPERSIDE,
|
|
||||||
ST_LOWERSIDE,
|
|
||||||
ST_CEILING,
|
|
||||||
ST_FLOOR
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DoomLevelMeshSurface : public LevelMeshSurface
|
|
||||||
{
|
|
||||||
DoomLevelMeshSurfaceType Type = ST_NONE;
|
|
||||||
int TypeIndex = 0;
|
|
||||||
|
|
||||||
MapSubsectorEx* Subsector = nullptr;
|
|
||||||
IntSideDef* Side = nullptr;
|
|
||||||
IntSector* ControlSector = nullptr;
|
|
||||||
|
|
||||||
int PipelineID = 0;
|
|
||||||
|
|
||||||
std::vector<ThingLight*> LightList;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DoomLevelSubmesh : public LevelSubmesh
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DoomLevelSubmesh(DoomLevelMesh* mesh, FLevel& doomMap, bool staticMesh);
|
|
||||||
|
|
||||||
void Update(FLevel& doomMap, int lightmapStartIndex);
|
|
||||||
|
|
||||||
LevelMeshSurface* GetSurface(int index) override { return &Surfaces[index]; }
|
|
||||||
unsigned int GetSurfaceIndex(const LevelMeshSurface* surface) const override { return (unsigned int)(ptrdiff_t)(static_cast<const DoomLevelMeshSurface*>(surface) - Surfaces.Data()); }
|
|
||||||
int GetSurfaceCount() override { return Surfaces.Size(); }
|
|
||||||
|
|
||||||
TArray<DoomLevelMeshSurface> Surfaces;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void Reset();
|
|
||||||
|
|
||||||
void CreateStaticSurfaces(FLevel& doomMap);
|
|
||||||
void CreateDynamicSurfaces(FLevel& doomMap);
|
|
||||||
|
|
||||||
void CreateSideSurfaces(std::map<LightmapTileBinding, int>& bindings, FLevel& doomMap, IntSideDef* side);
|
|
||||||
void CreateLineHorizonSurface(std::map<LightmapTileBinding, int>& bindings, FLevel& doomMap, IntSideDef* side);
|
|
||||||
void CreateFrontWallSurface(std::map<LightmapTileBinding, int>& bindings, FLevel& doomMap, IntSideDef* side);
|
|
||||||
void CreateMidWallSurface(std::map<LightmapTileBinding, int>& bindings, FLevel& doomMap, IntSideDef* side);
|
|
||||||
void Create3DFloorWallSurfaces(std::map<LightmapTileBinding, int>& bindings, FLevel& doomMap, IntSideDef* side);
|
|
||||||
void CreateTopWallSurface(std::map<LightmapTileBinding, int>& bindings, FLevel& doomMap, IntSideDef* side);
|
|
||||||
void CreateBottomWallSurface(std::map<LightmapTileBinding, int>& bindings, FLevel& doomMap, IntSideDef* side);
|
|
||||||
void SetSideTextureUVs(DoomLevelMeshSurface& surface, IntSideDef* side, WallPart texpart, float v1TopZ, float v1BottomZ, float v2TopZ, float v2BottomZ);
|
|
||||||
void CreateFloorSurface(std::map<LightmapTileBinding, int>& bindings, FLevel& doomMap, MapSubsectorEx* sub, IntSector* sector, IntSector* controlSector, int typeIndex);
|
|
||||||
void CreateCeilingSurface(std::map<LightmapTileBinding, int>& bindings, FLevel& doomMap, MapSubsectorEx* sub, IntSector* sector, IntSector* controlSector, int typeIndex);
|
|
||||||
|
|
||||||
void AddWallVertices(DoomLevelMeshSurface& surf, FFlatVertex* verts);
|
|
||||||
|
|
||||||
static bool IsTopSideSky(IntSector* frontsector, IntSector* backsector, IntSideDef* side);
|
|
||||||
static bool IsTopSideVisible(IntSideDef* side);
|
|
||||||
static bool IsBottomSideVisible(IntSideDef* side);
|
|
||||||
static bool IsSkySector(IntSector* sector, SecPlaneType plane);
|
|
||||||
static bool IsDegenerate(const FVector3& v0, const FVector3& v1, const FVector3& v2);
|
|
||||||
|
|
||||||
static FVector4 ToPlane(const FFlatVertex& pt1, const FFlatVertex& pt2, const FFlatVertex& pt3)
|
|
||||||
{
|
|
||||||
return ToPlane(FVector3(pt1.x, pt1.y, pt1.z), FVector3(pt2.x, pt2.y, pt2.z), FVector3(pt3.x, pt3.y, pt3.z));
|
|
||||||
}
|
|
||||||
|
|
||||||
static FVector4 ToPlane(const FFlatVertex& pt1, const FFlatVertex& pt2, const FFlatVertex& pt3, const FFlatVertex& pt4)
|
|
||||||
{
|
|
||||||
return ToPlane(FVector3(pt1.x, pt1.y, pt1.z), FVector3(pt2.x, pt2.y, pt2.z), FVector3(pt3.x, pt3.y, pt3.z), FVector3(pt4.x, pt4.y, pt4.z));
|
|
||||||
}
|
|
||||||
|
|
||||||
static FVector4 ToPlane(const FVector3& pt1, const FVector3& pt2, const FVector3& pt3)
|
|
||||||
{
|
|
||||||
FVector3 n = ((pt2 - pt1) ^ (pt3 - pt2)).Unit();
|
|
||||||
float d = pt1 | n;
|
|
||||||
return FVector4(n.X, n.Y, n.Z, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FVector4 ToPlane(const FVector3& pt1, const FVector3& pt2, const FVector3& pt3, const FVector3& pt4)
|
|
||||||
{
|
|
||||||
if (pt1.ApproximatelyEquals(pt3))
|
|
||||||
{
|
|
||||||
return ToPlane(pt1, pt2, pt4);
|
|
||||||
}
|
|
||||||
else if (pt1.ApproximatelyEquals(pt2) || pt2.ApproximatelyEquals(pt3))
|
|
||||||
{
|
|
||||||
return ToPlane(pt1, pt3, pt4);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ToPlane(pt1, pt2, pt3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SortIndexes();
|
|
||||||
|
|
||||||
void PackLightmapAtlas(FLevel& doomMap, int lightmapStartIndex);
|
|
||||||
|
|
||||||
enum PlaneAxis
|
|
||||||
{
|
|
||||||
AXIS_YZ = 0,
|
|
||||||
AXIS_XZ,
|
|
||||||
AXIS_XY
|
|
||||||
};
|
|
||||||
|
|
||||||
static PlaneAxis BestAxis(const FVector4& p);
|
|
||||||
BBox GetBoundsFromSurface(const LevelMeshSurface& surface) const;
|
|
||||||
|
|
||||||
void SetupTileTransform(int lightMapTextureWidth, int lightMapTextureHeight, LightmapTile& tile);
|
|
||||||
void AddSurfaceToTile(DoomLevelMeshSurface& surf, std::map<LightmapTileBinding, int>& bindings, FLevel& doomMap, uint16_t sampleDimension);
|
|
||||||
int GetSampleDimension(const DoomLevelMeshSurface& surf, uint16_t sampleDimension);
|
|
||||||
|
|
||||||
DoomLevelMesh* LevelMesh = nullptr;
|
|
||||||
bool StaticMesh = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(alignof(FVector2) == alignof(float[2]) && sizeof(FVector2) == sizeof(float) * 2);
|
|
|
@ -15,7 +15,11 @@ struct SurfaceInfo
|
||||||
uint PortalIndex;
|
uint PortalIndex;
|
||||||
int TextureIndex;
|
int TextureIndex;
|
||||||
float Alpha;
|
float Alpha;
|
||||||
float Padding;
|
float Padding0;
|
||||||
|
uint LightStart;
|
||||||
|
uint LightEnd;
|
||||||
|
uint Padding1;
|
||||||
|
uint Padding2;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PortalInfo
|
struct PortalInfo
|
||||||
|
@ -42,50 +46,27 @@ struct LightInfo
|
||||||
layout(set = 0, binding = 1) buffer SurfaceIndexBuffer { uint surfaceIndices[]; };
|
layout(set = 0, binding = 1) buffer SurfaceIndexBuffer { uint surfaceIndices[]; };
|
||||||
layout(set = 0, binding = 2) buffer SurfaceBuffer { SurfaceInfo surfaces[]; };
|
layout(set = 0, binding = 2) buffer SurfaceBuffer { SurfaceInfo surfaces[]; };
|
||||||
layout(set = 0, binding = 3) buffer LightBuffer { LightInfo lights[]; };
|
layout(set = 0, binding = 3) buffer LightBuffer { LightInfo lights[]; };
|
||||||
layout(set = 0, binding = 4) buffer PortalBuffer { PortalInfo portals[]; };
|
layout(set = 0, binding = 4) buffer LightIndexBuffer { int lightIndexes[]; };
|
||||||
|
layout(set = 0, binding = 5) buffer PortalBuffer { PortalInfo portals[]; };
|
||||||
#if defined(USE_DRAWINDIRECT)
|
|
||||||
|
|
||||||
struct LightmapRaytracePC
|
struct LightmapRaytracePC
|
||||||
{
|
{
|
||||||
uint LightStart;
|
|
||||||
uint LightEnd;
|
|
||||||
int SurfaceIndex;
|
int SurfaceIndex;
|
||||||
int PushPadding1;
|
int Padding0;
|
||||||
|
int Padding1;
|
||||||
|
int Padding2;
|
||||||
vec3 WorldToLocal;
|
vec3 WorldToLocal;
|
||||||
float TextureSize;
|
float TextureSize;
|
||||||
vec3 ProjLocalToU;
|
vec3 ProjLocalToU;
|
||||||
float PushPadding2;
|
float Padding3;
|
||||||
vec3 ProjLocalToV;
|
vec3 ProjLocalToV;
|
||||||
float PushPadding3;
|
float Padding4;
|
||||||
float TileX;
|
float TileX;
|
||||||
float TileY;
|
float TileY;
|
||||||
float TileWidth;
|
float TileWidth;
|
||||||
float TileHeight;
|
float TileHeight;
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(std430, set = 0, binding = 5) buffer ConstantsBuffer { LightmapRaytracePC constants[]; };
|
layout(std430, set = 0, binding = 6) buffer ConstantsBuffer { LightmapRaytracePC constants[]; };
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
layout(push_constant) uniform LightmapRaytracePC
|
|
||||||
{
|
|
||||||
uint LightStart;
|
|
||||||
uint LightEnd;
|
|
||||||
int SurfaceIndex;
|
|
||||||
int PushPadding1;
|
|
||||||
vec3 WorldToLocal;
|
|
||||||
float TextureSize;
|
|
||||||
vec3 ProjLocalToU;
|
|
||||||
float PushPadding2;
|
|
||||||
vec3 ProjLocalToV;
|
|
||||||
float PushPadding3;
|
|
||||||
float TileX;
|
|
||||||
float TileY;
|
|
||||||
float TileWidth;
|
|
||||||
float TileHeight;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
)glsl";
|
)glsl";
|
||||||
|
|
|
@ -8,38 +8,37 @@ static const char* frag_raytrace_glsl = R"glsl(
|
||||||
#include <shaders/lightmap/trace_sunlight.glsl>
|
#include <shaders/lightmap/trace_sunlight.glsl>
|
||||||
#include <shaders/lightmap/trace_light.glsl>
|
#include <shaders/lightmap/trace_light.glsl>
|
||||||
#include <shaders/lightmap/trace_ambient_occlusion.glsl>
|
#include <shaders/lightmap/trace_ambient_occlusion.glsl>
|
||||||
|
#include <shaders/lightmap/trace_bounce.glsl>
|
||||||
#if defined(USE_DRAWINDIRECT)
|
|
||||||
|
|
||||||
layout(location = 1) in flat int InstanceIndex;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
layout(location = 0) centroid in vec3 worldpos;
|
layout(location = 0) centroid in vec3 worldpos;
|
||||||
|
layout(location = 1) in flat int InstanceIndex;
|
||||||
|
|
||||||
layout(location = 0) out vec4 fragcolor;
|
layout(location = 0) out vec4 fragcolor;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
#if defined(USE_DRAWINDIRECT)
|
|
||||||
uint LightStart = constants[InstanceIndex].LightStart;
|
|
||||||
uint LightEnd = constants[InstanceIndex].LightEnd;
|
|
||||||
int SurfaceIndex = constants[InstanceIndex].SurfaceIndex;
|
int SurfaceIndex = constants[InstanceIndex].SurfaceIndex;
|
||||||
#endif
|
uint LightStart = surfaces[SurfaceIndex].LightStart;
|
||||||
|
uint LightEnd = surfaces[SurfaceIndex].LightEnd;
|
||||||
|
|
||||||
vec3 normal = surfaces[SurfaceIndex].Normal;
|
vec3 normal = surfaces[SurfaceIndex].Normal;
|
||||||
vec3 origin = worldpos + normal * 0.1;
|
vec3 origin = worldpos;
|
||||||
|
|
||||||
#if defined(USE_SUNLIGHT)
|
#if defined(USE_SUNLIGHT)
|
||||||
vec3 incoming = TraceSunLight(origin, normal, SurfaceIndex);
|
vec3 incoming = TraceSunLight(origin, normal);
|
||||||
#else
|
#else
|
||||||
vec3 incoming = vec3(0.0);
|
vec3 incoming = vec3(0.0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (uint j = LightStart; j < LightEnd; j++)
|
for (uint j = LightStart; j < LightEnd; j++)
|
||||||
{
|
{
|
||||||
incoming += TraceLight(origin, normal, lights[j], SurfaceIndex);
|
incoming += TraceLight(origin, normal, lights[lightIndexes[j]], 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(USE_BOUNCE)
|
||||||
|
incoming += TraceBounceLight(origin, normal);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(USE_AO)
|
#if defined(USE_AO)
|
||||||
incoming.rgb *= TraceAmbientOcclusion(origin, normal);
|
incoming.rgb *= TraceAmbientOcclusion(origin, normal);
|
||||||
#endif
|
#endif
|
||||||
|
|
33
src/lightmapper/glsl/montecarlo.glsl.h
Normal file
33
src/lightmapper/glsl/montecarlo.glsl.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
static const char* montecarlo_glsl = R"glsl(
|
||||||
|
|
||||||
|
float RadicalInverse_VdC(uint bits)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
return float(bits) * 2.3283064365386963e-10f; // / 0x100000000
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 Hammersley(uint i, uint N)
|
||||||
|
{
|
||||||
|
return vec2(float(i) / float(N), RadicalInverse_VdC(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 getVogelDiskSample(int sampleIndex, int sampleCount, float phi)
|
||||||
|
{
|
||||||
|
const float goldenAngle = radians(180.0) * (3.0 - sqrt(5.0));
|
||||||
|
float sampleIndexF = float(sampleIndex);
|
||||||
|
float sampleCountF = float(sampleCount);
|
||||||
|
|
||||||
|
float r = sqrt((sampleIndexF + 0.5) / sampleCountF); // Assuming index and count are positive
|
||||||
|
float theta = sampleIndexF * goldenAngle + phi;
|
||||||
|
|
||||||
|
float sine = sin(theta);
|
||||||
|
float cosine = cos(theta);
|
||||||
|
|
||||||
|
return vec2(cosine, sine) * r;
|
||||||
|
}
|
||||||
|
|
||||||
|
)glsl";
|
|
@ -1,9 +1,18 @@
|
||||||
static const char* polyfill_rayquery_glsl = R"glsl(
|
static const char* polyfill_rayquery_glsl = R"glsl(
|
||||||
|
|
||||||
|
struct TraceResult
|
||||||
|
{
|
||||||
|
float t;
|
||||||
|
vec3 primitiveWeights;
|
||||||
|
int primitiveIndex;
|
||||||
|
};
|
||||||
|
|
||||||
#if defined(USE_RAYQUERY)
|
#if defined(USE_RAYQUERY)
|
||||||
|
|
||||||
int TraceFirstHitTriangleNoPortal(vec3 origin, float tmin, vec3 dir, float tmax, out float t, out vec3 primitiveWeights)
|
TraceResult TraceFirstHit(vec3 origin, float tmin, vec3 dir, float tmax)
|
||||||
{
|
{
|
||||||
|
TraceResult result;
|
||||||
|
|
||||||
rayQueryEXT rayQuery;
|
rayQueryEXT rayQuery;
|
||||||
rayQueryInitializeEXT(rayQuery, acc, gl_RayFlagsCullBackFacingTrianglesEXT, 0xFF, origin, tmin, dir, tmax);
|
rayQueryInitializeEXT(rayQuery, acc, gl_RayFlagsCullBackFacingTrianglesEXT, 0xFF, origin, tmin, dir, tmax);
|
||||||
|
|
||||||
|
@ -17,18 +26,20 @@ int TraceFirstHitTriangleNoPortal(vec3 origin, float tmin, vec3 dir, float tmax,
|
||||||
|
|
||||||
if (rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionTriangleEXT)
|
if (rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionTriangleEXT)
|
||||||
{
|
{
|
||||||
t = rayQueryGetIntersectionTEXT(rayQuery, true);
|
result.t = rayQueryGetIntersectionTEXT(rayQuery, true);
|
||||||
|
|
||||||
primitiveWeights.xy = rayQueryGetIntersectionBarycentricsEXT(rayQuery, true);
|
result.primitiveWeights.xy = rayQueryGetIntersectionBarycentricsEXT(rayQuery, true);
|
||||||
primitiveWeights.z = 1.0 - primitiveWeights.x - primitiveWeights.y;
|
result.primitiveWeights.z = 1.0 - result.primitiveWeights.x - result.primitiveWeights.y;
|
||||||
|
|
||||||
return rayQueryGetIntersectionPrimitiveIndexEXT(rayQuery, true);
|
result.primitiveIndex = rayQueryGetIntersectionPrimitiveIndexEXT(rayQuery, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
t = tmax;
|
result.t = tmax;
|
||||||
return -1;
|
result.primitiveIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -235,8 +246,10 @@ TraceHit find_first_hit(RayBBox ray)
|
||||||
return hit;
|
return hit;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TraceFirstHitTriangleNoPortal(vec3 origin, float tmin, vec3 dir, float tmax, out float tparam, out vec3 primitiveWeights)
|
TraceResult TraceFirstHit(vec3 origin, float tmin, vec3 dir, float tmax)
|
||||||
{
|
{
|
||||||
|
TraceResult result;
|
||||||
|
|
||||||
// Perform segmented tracing to keep the ray AABB box smaller
|
// Perform segmented tracing to keep the ray AABB box smaller
|
||||||
vec3 ray_start = origin;
|
vec3 ray_start = origin;
|
||||||
vec3 ray_end = origin + dir * tmax;
|
vec3 ray_end = origin + dir * tmax;
|
||||||
|
@ -252,16 +265,18 @@ int TraceFirstHitTriangleNoPortal(vec3 origin, float tmin, vec3 dir, float tmax,
|
||||||
TraceHit hit = find_first_hit(ray);
|
TraceHit hit = find_first_hit(ray);
|
||||||
if (hit.fraction < 1.0)
|
if (hit.fraction < 1.0)
|
||||||
{
|
{
|
||||||
tparam = hit.fraction = segstart * (1.0 - hit.fraction) + segend * hit.fraction;
|
result.t = mix(segstart, segend, hit.fraction);
|
||||||
primitiveWeights.x = hit.b;
|
result.primitiveWeights.x = hit.b;
|
||||||
primitiveWeights.y = hit.c;
|
result.primitiveWeights.y = hit.c;
|
||||||
primitiveWeights.z = 1.0 - hit.b - hit.c;
|
result.primitiveWeights.z = 1.0 - hit.b - hit.c;
|
||||||
return hit.triangle;
|
result.primitiveIndex = hit.triangle;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tparam = tracedist;
|
result.t = tracedist;
|
||||||
return -1;
|
result.primitiveIndex = -1;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
static const char* trace_ambient_occlusion_glsl = R"glsl(
|
static const char* trace_ambient_occlusion_glsl = R"glsl(
|
||||||
|
|
||||||
vec2 Hammersley(uint i, uint N);
|
#include <shaders/lightmap/montecarlo.glsl>
|
||||||
float RadicalInverse_VdC(uint bits);
|
|
||||||
|
float TraceAORay(vec3 origin, float tmin, vec3 dir, float tmax);
|
||||||
|
|
||||||
float TraceAmbientOcclusion(vec3 origin, vec3 normal)
|
float TraceAmbientOcclusion(vec3 origin, vec3 normal)
|
||||||
{
|
{
|
||||||
const float minDistance = 0.05;
|
const float minDistance = 0.01;
|
||||||
const float aoDistance = 100;
|
const float aoDistance = 100;
|
||||||
const int SampleCount = 128;
|
const int SampleCount = 128;
|
||||||
|
|
||||||
|
@ -20,38 +21,42 @@ float TraceAmbientOcclusion(vec3 origin, vec3 normal)
|
||||||
vec2 Xi = Hammersley(i, SampleCount);
|
vec2 Xi = Hammersley(i, SampleCount);
|
||||||
vec3 H = normalize(vec3(Xi.x * 2.0f - 1.0f, Xi.y * 2.0f - 1.0f, 1.5 - length(Xi)));
|
vec3 H = normalize(vec3(Xi.x * 2.0f - 1.0f, Xi.y * 2.0f - 1.0f, 1.5 - length(Xi)));
|
||||||
vec3 L = H.x * tangent + H.y * bitangent + H.z * N;
|
vec3 L = H.x * tangent + H.y * bitangent + H.z * N;
|
||||||
|
ambience += clamp(TraceAORay(origin, minDistance, L, aoDistance) / aoDistance, 0.0, 1.0);
|
||||||
float hitDistance;
|
|
||||||
int primitiveID = TraceFirstHitTriangleT(origin, minDistance, L, aoDistance, hitDistance);
|
|
||||||
if (primitiveID != -1)
|
|
||||||
{
|
|
||||||
SurfaceInfo surface = surfaces[surfaceIndices[primitiveID]];
|
|
||||||
if (surface.Sky == 0.0)
|
|
||||||
{
|
|
||||||
ambience += clamp(hitDistance / aoDistance, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ambience += 1.0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ambience / float(SampleCount);
|
return ambience / float(SampleCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec2 Hammersley(uint i, uint N)
|
float TraceAORay(vec3 origin, float tmin, vec3 dir, float tmax)
|
||||||
{
|
{
|
||||||
return vec2(float(i) / float(N), RadicalInverse_VdC(i));
|
float tcur = 0.0;
|
||||||
}
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
TraceResult result = TraceFirstHit(origin, tmin, dir, tmax - tcur);
|
||||||
|
if (result.primitiveIndex == -1)
|
||||||
|
return tmax;
|
||||||
|
|
||||||
float RadicalInverse_VdC(uint bits)
|
SurfaceInfo surface = GetSurface(result.primitiveIndex);
|
||||||
{
|
|
||||||
bits = (bits << 16u) | (bits >> 16u);
|
// Stop if hit sky portal
|
||||||
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
if (surface.Sky > 0.0)
|
||||||
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
return tmax;
|
||||||
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
|
||||||
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
// Stop if opaque surface
|
||||||
return float(bits) * 2.3283064365386963e-10f; // / 0x100000000
|
if (surface.PortalIndex == 0 /*surface.TextureIndex == 0*/)
|
||||||
|
{
|
||||||
|
return tcur + result.t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to surface hit point
|
||||||
|
origin += dir * result.t;
|
||||||
|
tcur += result.t;
|
||||||
|
if (tcur >= tmax)
|
||||||
|
return tmax;
|
||||||
|
|
||||||
|
// Move through the portal, if any
|
||||||
|
TransformRay(surface.PortalIndex, origin, dir);
|
||||||
|
}
|
||||||
|
return tmax;
|
||||||
}
|
}
|
||||||
|
|
||||||
)glsl";
|
)glsl";
|
||||||
|
|
48
src/lightmapper/glsl/trace_bounce.glsl.h
Normal file
48
src/lightmapper/glsl/trace_bounce.glsl.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
static const char* trace_bounce_glsl = R"glsl(
|
||||||
|
|
||||||
|
#include <shaders/lightmap/montecarlo.glsl>
|
||||||
|
|
||||||
|
vec3 TraceBounceLight(vec3 origin, vec3 normal)
|
||||||
|
{
|
||||||
|
const float minDistance = 0.01;
|
||||||
|
const float maxDistance = 1000.0;
|
||||||
|
const int SampleCount = 8;
|
||||||
|
|
||||||
|
vec3 N = normal;
|
||||||
|
vec3 up = abs(N.x) < abs(N.y) ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0);
|
||||||
|
vec3 tangent = normalize(cross(up, N));
|
||||||
|
vec3 bitangent = cross(N, tangent);
|
||||||
|
vec3 incoming = vec3(0.0);
|
||||||
|
|
||||||
|
for (uint i = 0; i < SampleCount; i++)
|
||||||
|
{
|
||||||
|
vec2 Xi = Hammersley(i, SampleCount);
|
||||||
|
vec3 H = normalize(vec3(Xi.x * 2.0f - 1.0f, Xi.y * 2.0f - 1.0f, 1.5 - length(Xi)));
|
||||||
|
vec3 L = H.x * tangent + H.y * bitangent + H.z * N;
|
||||||
|
|
||||||
|
TraceResult result = TraceFirstHit(origin, minDistance, L, maxDistance);
|
||||||
|
|
||||||
|
// We hit nothing.
|
||||||
|
if (result.primitiveIndex == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SurfaceInfo surface = GetSurface(result.primitiveIndex);
|
||||||
|
uint LightStart = surface.LightStart;
|
||||||
|
uint LightEnd = surface.LightEnd;
|
||||||
|
vec3 surfacepos = origin + L * result.t;
|
||||||
|
|
||||||
|
float angleAttenuation = max(dot(normal, L), 0.0);
|
||||||
|
|
||||||
|
#if defined(USE_SUNLIGHT)
|
||||||
|
incoming += TraceSunLight(surfacepos, surface.Normal) * angleAttenuation;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (uint j = LightStart; j < LightEnd; j++)
|
||||||
|
{
|
||||||
|
incoming += TraceLight(surfacepos, surface.Normal, lights[lightIndexes[j]], result.t) * angleAttenuation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return incoming / float(SampleCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
)glsl";
|
|
@ -1,127 +1,39 @@
|
||||||
static const char* trace_levelmesh_glsl = R"glsl(
|
static const char* trace_levelmesh_glsl = R"glsl(
|
||||||
|
|
||||||
vec4 rayColor;
|
|
||||||
|
|
||||||
vec4 alphaBlend(vec4 a, vec4 b);
|
|
||||||
vec4 BeerLambertSimple(vec4 medium, vec4 ray_color);
|
vec4 BeerLambertSimple(vec4 medium, vec4 ray_color);
|
||||||
vec4 blend(vec4 a, vec4 b);
|
|
||||||
|
|
||||||
int TraceFirstHitTriangleT(vec3 origin, float tmin, vec3 dir, float tmax, out float t)
|
SurfaceInfo GetSurface(int primitiveIndex)
|
||||||
{
|
{
|
||||||
int primitiveID = -1;
|
return surfaces[surfaceIndices[primitiveIndex]];
|
||||||
vec3 primitiveWeights;
|
}
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
|
vec2 GetSurfaceUV(int primitiveIndex, vec3 primitiveWeights)
|
||||||
|
{
|
||||||
|
int index = primitiveIndex * 3;
|
||||||
|
return
|
||||||
|
vertices[elements[index + 1]].uv * primitiveWeights.x +
|
||||||
|
vertices[elements[index + 2]].uv * primitiveWeights.y +
|
||||||
|
vertices[elements[index + 0]].uv * primitiveWeights.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 BlendTexture(SurfaceInfo surface, vec2 uv, vec4 rayColor)
|
||||||
|
{
|
||||||
|
if (surface.TextureIndex == 0)
|
||||||
{
|
{
|
||||||
primitiveID = TraceFirstHitTriangleNoPortal(origin, tmin, dir, tmax, t, primitiveWeights);
|
return rayColor;
|
||||||
|
|
||||||
if(primitiveID < 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
SurfaceInfo surface = surfaces[surfaceIndices[primitiveID]];
|
|
||||||
|
|
||||||
if(surface.PortalIndex == 0)
|
|
||||||
{
|
|
||||||
int index = primitiveID * 3;
|
|
||||||
vec2 uv = vertices[elements[index + 1]].uv * primitiveWeights.x + vertices[elements[index + 2]].uv * primitiveWeights.y + vertices[elements[index + 0]].uv * primitiveWeights.z;
|
|
||||||
|
|
||||||
if (surface.TextureIndex == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 color = texture(textures[surface.TextureIndex], uv);
|
|
||||||
color.w *= surface.Alpha;
|
|
||||||
|
|
||||||
if (color.w > 0.999 || all(lessThan(rayColor.rgb, vec3(0.001))))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
rayColor = blend(color, rayColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Portal was hit: Apply transformation onto the ray
|
|
||||||
mat4 transformationMatrix = portals[surface.PortalIndex].Transformation;
|
|
||||||
|
|
||||||
origin = (transformationMatrix * vec4(origin + dir * t, 1.0)).xyz;
|
|
||||||
dir = (transformationMatrix * vec4(dir, 0.0)).xyz;
|
|
||||||
tmax -= t;
|
|
||||||
}
|
}
|
||||||
return primitiveID;
|
else
|
||||||
}
|
|
||||||
|
|
||||||
int TraceFirstHitTriangle(vec3 origin, float tmin, vec3 dir, float tmax)
|
|
||||||
{
|
|
||||||
float t;
|
|
||||||
return TraceFirstHitTriangleT(origin, tmin, dir, tmax, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TraceAnyHit(vec3 origin, float tmin, vec3 dir, float tmax)
|
|
||||||
{
|
|
||||||
return TraceFirstHitTriangle(origin, tmin, dir, tmax) >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TracePoint(vec3 origin, vec3 target, float tmin, vec3 dir, float tmax)
|
|
||||||
{
|
|
||||||
int primitiveID;
|
|
||||||
float t;
|
|
||||||
vec3 primitiveWeights;
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
{
|
{
|
||||||
t = tmax;
|
vec4 color = texture(textures[surface.TextureIndex], uv);
|
||||||
primitiveID = TraceFirstHitTriangleNoPortal(origin, tmin, dir, tmax, t, primitiveWeights);
|
return BeerLambertSimple(vec4(1.0 - color.rgb, color.a * surface.Alpha), rayColor);
|
||||||
|
|
||||||
origin += dir * t;
|
|
||||||
tmax -= t;
|
|
||||||
|
|
||||||
if(primitiveID < 0)
|
|
||||||
{
|
|
||||||
// We didn't hit anything
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
SurfaceInfo surface = surfaces[surfaceIndices[primitiveID]];
|
|
||||||
|
|
||||||
if (surface.PortalIndex == 0)
|
|
||||||
{
|
|
||||||
int index = primitiveID * 3;
|
|
||||||
vec2 uv = vertices[elements[index + 1]].uv * primitiveWeights.x + vertices[elements[index + 2]].uv * primitiveWeights.y + vertices[elements[index + 0]].uv * primitiveWeights.z;
|
|
||||||
|
|
||||||
if (surface.TextureIndex == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 color = texture(textures[surface.TextureIndex], uv);
|
|
||||||
color.w *= surface.Alpha;
|
|
||||||
|
|
||||||
if (color.w > 0.999 || all(lessThan(rayColor.rgb, vec3(0.001))))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
rayColor = blend(color, rayColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(dot(surface.Normal, dir) >= 0.0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
mat4 transformationMatrix = portals[surface.PortalIndex].Transformation;
|
|
||||||
origin = (transformationMatrix * vec4(origin, 1.0)).xyz;
|
|
||||||
dir = (transformationMatrix * vec4(dir, 0.0)).xyz;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return distance(origin, target) <= 1.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 alphaBlend(vec4 a, vec4 b)
|
void TransformRay(uint portalIndex, inout vec3 origin, inout vec3 dir)
|
||||||
{
|
{
|
||||||
float na = a.w + b.w * (1.0 - a.w);
|
mat4 transformationMatrix = portals[portalIndex].Transformation;
|
||||||
return vec4((a.xyz * a.w + b.xyz * b.w * (1.0 - a.w)) / na, max(0.001, na));
|
origin = (transformationMatrix * vec4(origin, 1.0)).xyz;
|
||||||
|
dir = (transformationMatrix * vec4(dir, 0.0)).xyz;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 BeerLambertSimple(vec4 medium, vec4 ray_color) // based on Beer-Lambert law
|
vec4 BeerLambertSimple(vec4 medium, vec4 ray_color) // based on Beer-Lambert law
|
||||||
|
@ -131,9 +43,4 @@ vec4 BeerLambertSimple(vec4 medium, vec4 ray_color) // based on Beer-Lambert law
|
||||||
return ray_color;
|
return ray_color;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 blend(vec4 a, vec4 b)
|
|
||||||
{
|
|
||||||
return BeerLambertSimple(vec4(1.0 - a.rgb, a.w), b);
|
|
||||||
}
|
|
||||||
|
|
||||||
)glsl";
|
)glsl";
|
||||||
|
|
|
@ -1,22 +1,20 @@
|
||||||
static const char* trace_light_glsl = R"glsl(
|
static const char* trace_light_glsl = R"glsl(
|
||||||
|
|
||||||
vec2 getVogelDiskSample(int sampleIndex, int sampleCount, float phi);
|
#include <shaders/lightmap/montecarlo.glsl>
|
||||||
|
|
||||||
vec3 TraceLight(vec3 origin, vec3 normal, LightInfo light, int surfaceIndex)
|
vec4 TracePointLightRay(vec3 origin, vec3 lightpos, float tmin, vec4 rayColor);
|
||||||
|
|
||||||
|
vec3 TraceLight(vec3 origin, vec3 normal, LightInfo light, float extraDistance)
|
||||||
{
|
{
|
||||||
const float minDistance = 0.01;
|
const float minDistance = 0.01;
|
||||||
vec3 incoming = vec3(0.0);
|
vec3 incoming = vec3(0.0);
|
||||||
float dist = distance(light.RelativeOrigin, origin);
|
float dist = distance(light.RelativeOrigin, origin) + extraDistance;
|
||||||
if (dist > minDistance && dist < light.Radius)
|
if (dist > minDistance && dist < light.Radius)
|
||||||
{
|
{
|
||||||
vec3 dir = normalize(light.RelativeOrigin - origin);
|
vec3 dir = normalize(light.RelativeOrigin - origin);
|
||||||
|
|
||||||
float distAttenuation = max(1.0 - (dist / light.Radius), 0.0);
|
float distAttenuation = max(1.0 - (dist / light.Radius), 0.0);
|
||||||
float angleAttenuation = 1.0f;
|
float angleAttenuation = max(dot(normal, dir), 0.0);
|
||||||
if (surfaceIndex >= 0)
|
|
||||||
{
|
|
||||||
angleAttenuation = max(dot(normal, dir), 0.0);
|
|
||||||
}
|
|
||||||
float spotAttenuation = 1.0;
|
float spotAttenuation = 1.0;
|
||||||
if (light.OuterAngleCos > -1.0)
|
if (light.OuterAngleCos > -1.0)
|
||||||
{
|
{
|
||||||
|
@ -28,6 +26,8 @@ vec3 TraceLight(vec3 origin, vec3 normal, LightInfo light, int surfaceIndex)
|
||||||
float attenuation = distAttenuation * angleAttenuation * spotAttenuation;
|
float attenuation = distAttenuation * angleAttenuation * spotAttenuation;
|
||||||
if (attenuation > 0.0)
|
if (attenuation > 0.0)
|
||||||
{
|
{
|
||||||
|
vec4 rayColor = vec4(light.Color.rgb * (attenuation * light.Intensity), 1.0);
|
||||||
|
|
||||||
#if defined(USE_SOFTSHADOWS)
|
#if defined(USE_SOFTSHADOWS)
|
||||||
|
|
||||||
vec3 v = (abs(dir.x) > abs(dir.y)) ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);
|
vec3 v = (abs(dir.x) > abs(dir.y)) ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);
|
||||||
|
@ -41,19 +41,11 @@ vec3 TraceLight(vec3 origin, vec3 normal, LightInfo light, int surfaceIndex)
|
||||||
vec2 gridoffset = getVogelDiskSample(i, step_count, gl_FragCoord.x + gl_FragCoord.y * 13.37) * lightsize;
|
vec2 gridoffset = getVogelDiskSample(i, step_count, gl_FragCoord.x + gl_FragCoord.y * 13.37) * lightsize;
|
||||||
vec3 pos = light.Origin + xdir * gridoffset.x + ydir * gridoffset.y;
|
vec3 pos = light.Origin + xdir * gridoffset.x + ydir * gridoffset.y;
|
||||||
|
|
||||||
rayColor = vec4(light.Color.rgb, 1.0);
|
incoming.rgb += TracePointLightRay(origin, pos, minDistance, rayColor).rgb / float(step_count);
|
||||||
if (TracePoint(origin, pos, minDistance, normalize(pos - origin), distance(origin, pos)))
|
|
||||||
{
|
|
||||||
incoming.rgb += (rayColor.rgb * rayColor.w) * (attenuation * light.Intensity) / float(step_count);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
rayColor = vec4(light.Color.rgb, 1.0);
|
incoming.rgb += TracePointLightRay(origin, light.Origin, minDistance, rayColor).rgb;
|
||||||
if(TracePoint(origin, light.Origin, minDistance, dir, dist))
|
|
||||||
{
|
|
||||||
incoming.rgb += (rayColor.rgb * rayColor.w) * (attenuation * light.Intensity);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,19 +53,36 @@ vec3 TraceLight(vec3 origin, vec3 normal, LightInfo light, int surfaceIndex)
|
||||||
return incoming;
|
return incoming;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec2 getVogelDiskSample(int sampleIndex, int sampleCount, float phi)
|
vec4 TracePointLightRay(vec3 origin, vec3 lightpos, float tmin, vec4 rayColor)
|
||||||
{
|
{
|
||||||
const float goldenAngle = radians(180.0) * (3.0 - sqrt(5.0));
|
vec3 dir = normalize(lightpos - origin);
|
||||||
float sampleIndexF = float(sampleIndex);
|
float tmax = distance(origin, lightpos);
|
||||||
float sampleCountF = float(sampleCount);
|
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
float r = sqrt((sampleIndexF + 0.5) / sampleCountF); // Assuming index and count are positive
|
{
|
||||||
float theta = sampleIndexF * goldenAngle + phi;
|
TraceResult result = TraceFirstHit(origin, tmin, dir, tmax);
|
||||||
|
|
||||||
float sine = sin(theta);
|
// We hit nothing. Point light is visible.
|
||||||
float cosine = cos(theta);
|
if (result.primitiveIndex == -1)
|
||||||
|
return rayColor;
|
||||||
return vec2(cosine, sine) * r;
|
|
||||||
|
SurfaceInfo surface = GetSurface(result.primitiveIndex);
|
||||||
|
|
||||||
|
// Blend with surface texture
|
||||||
|
rayColor = BlendTexture(surface, GetSurfaceUV(result.primitiveIndex, result.primitiveWeights), rayColor);
|
||||||
|
|
||||||
|
// Stop if it isn't a portal, or there is no light left
|
||||||
|
if (surface.PortalIndex == 0 || rayColor.r + rayColor.g + rayColor.b <= 0.0)
|
||||||
|
return vec4(0.0);
|
||||||
|
|
||||||
|
// Move to surface hit point
|
||||||
|
origin += dir * result.t;
|
||||||
|
tmax -= result.t;
|
||||||
|
|
||||||
|
// Move through the portal, if any
|
||||||
|
TransformRay(surface.PortalIndex, origin, dir);
|
||||||
|
}
|
||||||
|
return vec4(0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
)glsl";
|
)glsl";
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
static const char* trace_sunlight_glsl = R"glsl(
|
static const char* trace_sunlight_glsl = R"glsl(
|
||||||
|
|
||||||
vec2 getVogelDiskSample(int sampleIndex, int sampleCount, float phi);
|
#include <shaders/lightmap/montecarlo.glsl>
|
||||||
|
|
||||||
vec3 TraceSunLight(vec3 origin, vec3 normal, int surfaceIndex)
|
vec4 TraceSunRay(vec3 origin, float tmin, vec3 dir, float tmax, vec4 rayColor);
|
||||||
|
|
||||||
|
vec3 TraceSunLight(vec3 origin, vec3 normal)
|
||||||
{
|
{
|
||||||
float angleAttenuation = 1.0f;
|
float angleAttenuation = max(dot(normal, SunDir), 0.0);
|
||||||
if (surfaceIndex >= 0)
|
if (angleAttenuation == 0.0)
|
||||||
{
|
return vec3(0.0);
|
||||||
angleAttenuation = max(dot(normal, SunDir), 0.0);
|
|
||||||
if (angleAttenuation == 0.0)
|
|
||||||
return vec3(0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const float minDistance = 0.01;
|
const float minDistance = 0.01;
|
||||||
vec3 incoming = vec3(0.0);
|
vec3 incoming = vec3(0.0);
|
||||||
const float dist = 65536.0;
|
const float dist = 65536.0;
|
||||||
|
|
||||||
|
vec4 rayColor = vec4(SunColor.rgb * SunIntensity, 1.0);
|
||||||
|
|
||||||
#if defined(USE_SOFTSHADOWS)
|
#if defined(USE_SOFTSHADOWS)
|
||||||
|
|
||||||
vec3 target = origin + SunDir * dist;
|
vec3 target = origin + SunDir * dist;
|
||||||
|
@ -30,31 +30,47 @@ vec3 TraceSunLight(vec3 origin, vec3 normal, int surfaceIndex)
|
||||||
{
|
{
|
||||||
vec2 gridoffset = getVogelDiskSample(i, step_count, gl_FragCoord.x + gl_FragCoord.y * 13.37) * lightsize;
|
vec2 gridoffset = getVogelDiskSample(i, step_count, gl_FragCoord.x + gl_FragCoord.y * 13.37) * lightsize;
|
||||||
vec3 pos = target + xdir * gridoffset.x + ydir * gridoffset.y;
|
vec3 pos = target + xdir * gridoffset.x + ydir * gridoffset.y;
|
||||||
|
incoming.rgb += TraceSunRay(origin, minDistance, normalize(pos - origin), dist, rayColor).rgb / float(step_count);
|
||||||
rayColor = vec4(SunColor.rgb * SunIntensity, 1.0);
|
|
||||||
|
|
||||||
int primitiveID = TraceFirstHitTriangle(origin, minDistance, normalize(pos - origin), dist);
|
|
||||||
if (primitiveID != -1)
|
|
||||||
{
|
|
||||||
SurfaceInfo surface = surfaces[surfaceIndices[primitiveID]];
|
|
||||||
incoming.rgb += rayColor.rgb * rayColor.w * surface.Sky / float(step_count);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
rayColor = vec4(SunColor.rgb * SunIntensity, 1.0);
|
incoming.rgb = TraceSunRay(origin, minDistance, SunDir, dist, rayColor).rgb;
|
||||||
|
|
||||||
int primitiveID = TraceFirstHitTriangle(origin, minDistance, SunDir, dist);
|
|
||||||
if (primitiveID != -1)
|
|
||||||
{
|
|
||||||
SurfaceInfo surface = surfaces[surfaceIndices[primitiveID]];
|
|
||||||
incoming.rgb = rayColor.rgb * rayColor.w * surface.Sky;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return incoming * angleAttenuation;
|
return incoming * angleAttenuation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec4 TraceSunRay(vec3 origin, float tmin, vec3 dir, float tmax, vec4 rayColor)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
TraceResult result = TraceFirstHit(origin, tmin, dir, tmax);
|
||||||
|
|
||||||
|
// We hit nothing. We have to hit a sky surface to hit the sky.
|
||||||
|
if (result.primitiveIndex == -1)
|
||||||
|
return vec4(0.0);
|
||||||
|
|
||||||
|
SurfaceInfo surface = GetSurface(result.primitiveIndex);
|
||||||
|
|
||||||
|
// Blend with surface texture
|
||||||
|
rayColor = BlendTexture(surface, GetSurfaceUV(result.primitiveIndex, result.primitiveWeights), rayColor);
|
||||||
|
|
||||||
|
// Stop if it isn't a portal, or there is no light left
|
||||||
|
if (surface.PortalIndex == 0 || rayColor.r + rayColor.g + rayColor.b <= 0.0)
|
||||||
|
return rayColor * surface.Sky;
|
||||||
|
|
||||||
|
// Move to surface hit point
|
||||||
|
origin += dir * result.t;
|
||||||
|
tmax -= result.t;
|
||||||
|
if (tmax <= tmin)
|
||||||
|
return vec4(0.0);
|
||||||
|
|
||||||
|
// Move through the portal, if any
|
||||||
|
TransformRay(surface.PortalIndex, origin, dir);
|
||||||
|
}
|
||||||
|
return vec4(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
)glsl";
|
)glsl";
|
||||||
|
|
|
@ -5,13 +5,10 @@ static const char* vert_raytrace_glsl = R"glsl(
|
||||||
layout(location = 0) in vec3 aPosition;
|
layout(location = 0) in vec3 aPosition;
|
||||||
layout(location = 0) out vec3 worldpos;
|
layout(location = 0) out vec3 worldpos;
|
||||||
|
|
||||||
#if defined(USE_DRAWINDIRECT)
|
|
||||||
layout(location = 1) out flat int InstanceIndex;
|
layout(location = 1) out flat int InstanceIndex;
|
||||||
#endif
|
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
#if defined(USE_DRAWINDIRECT)
|
|
||||||
vec3 WorldToLocal = constants[gl_InstanceIndex].WorldToLocal;
|
vec3 WorldToLocal = constants[gl_InstanceIndex].WorldToLocal;
|
||||||
float TextureSize = constants[gl_InstanceIndex].TextureSize;
|
float TextureSize = constants[gl_InstanceIndex].TextureSize;
|
||||||
vec3 ProjLocalToU = constants[gl_InstanceIndex].ProjLocalToU;
|
vec3 ProjLocalToU = constants[gl_InstanceIndex].ProjLocalToU;
|
||||||
|
@ -21,7 +18,6 @@ void main()
|
||||||
float TileWidth = constants[gl_InstanceIndex].TileWidth;
|
float TileWidth = constants[gl_InstanceIndex].TileWidth;
|
||||||
float TileHeight = constants[gl_InstanceIndex].TileHeight;
|
float TileHeight = constants[gl_InstanceIndex].TileHeight;
|
||||||
InstanceIndex = gl_InstanceIndex;
|
InstanceIndex = gl_InstanceIndex;
|
||||||
#endif
|
|
||||||
|
|
||||||
worldpos = aPosition;
|
worldpos = aPosition;
|
||||||
|
|
||||||
|
@ -34,11 +30,10 @@ void main()
|
||||||
gl_Position = vec4(vec2(TileX + x, TileY + y) / TextureSize * 2.0 - 1.0, 0.0, 1.0);
|
gl_Position = vec4(vec2(TileX + x, TileY + y) / TextureSize * 2.0 - 1.0, 0.0, 1.0);
|
||||||
|
|
||||||
// Clip all surfaces to the edge of the tile (effectly we are applying a viewport/scissor to the tile)
|
// Clip all surfaces to the edge of the tile (effectly we are applying a viewport/scissor to the tile)
|
||||||
// Note: the tile has a 1px border around it that we also draw into
|
gl_ClipDistance[0] = x;
|
||||||
gl_ClipDistance[0] = x + 1.0;
|
gl_ClipDistance[1] = y;
|
||||||
gl_ClipDistance[1] = y + 1.0;
|
gl_ClipDistance[2] = TileWidth - x;
|
||||||
gl_ClipDistance[2] = TileWidth + 1.0 - x;
|
gl_ClipDistance[3] = TileHeight - y;
|
||||||
gl_ClipDistance[3] = TileHeight + 1.0 - y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
)glsl";
|
)glsl";
|
||||||
|
|
|
@ -36,11 +36,10 @@ void GPURaytracer::Raytrace(DoomLevelMesh* mesh)
|
||||||
{
|
{
|
||||||
auto levelmesh = mDevice->GetLevelMesh();
|
auto levelmesh = mDevice->GetLevelMesh();
|
||||||
auto lightmapper = mDevice->GetLightmapper();
|
auto lightmapper = mDevice->GetLightmapper();
|
||||||
auto submesh = mesh->StaticMesh.get();
|
|
||||||
|
|
||||||
printf(" Map uses %u lightmap textures\n", submesh->LMTextureCount);
|
printf(" Map uses %u lightmap textures\n", mesh->LMTextureCount);
|
||||||
|
|
||||||
mDevice->GetTextureManager()->CreateLightmap(submesh->LMTextureSize, submesh->LMTextureCount);
|
mDevice->GetTextureManager()->CreateLightmap(mesh->LMTextureSize, mesh->LMTextureCount);
|
||||||
|
|
||||||
levelmesh->SetLevelMesh(mesh);
|
levelmesh->SetLevelMesh(mesh);
|
||||||
lightmapper->SetLevelMesh(mesh);
|
lightmapper->SetLevelMesh(mesh);
|
||||||
|
@ -52,9 +51,9 @@ void GPURaytracer::Raytrace(DoomLevelMesh* mesh)
|
||||||
lightmapper->BeginFrame();
|
lightmapper->BeginFrame();
|
||||||
|
|
||||||
TArray<LightmapTile*> tiles;
|
TArray<LightmapTile*> tiles;
|
||||||
for (unsigned int i = 0, count = submesh->LightmapTiles.Size(); i < count; i++)
|
for (unsigned int i = 0, count = mesh->LightmapTiles.Size(); i < count; i++)
|
||||||
{
|
{
|
||||||
LightmapTile* tile = &submesh->LightmapTiles[i];
|
LightmapTile* tile = &mesh->LightmapTiles[i];
|
||||||
if (tile->NeedsUpdate)
|
if (tile->NeedsUpdate)
|
||||||
{
|
{
|
||||||
tiles.Push(tile);
|
tiles.Push(tile);
|
||||||
|
@ -64,19 +63,19 @@ void GPURaytracer::Raytrace(DoomLevelMesh* mesh)
|
||||||
if (tiles.Size() == 0)
|
if (tiles.Size() == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
printf(" Ray tracing tiles: %u / %u\r", submesh->LightmapTiles.Size() - tiles.Size(), submesh->LightmapTiles.Size());
|
printf(" Ray tracing tiles: %u / %u\r", mesh->LightmapTiles.Size() - tiles.Size(), mesh->LightmapTiles.Size());
|
||||||
|
|
||||||
lightmapper->Raytrace(tiles);
|
lightmapper->Raytrace(tiles);
|
||||||
|
|
||||||
mDevice->GetCommands()->SubmitAndWait();
|
mDevice->GetCommands()->SubmitAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(" Ray tracing tiles: %u / %u\n", submesh->LightmapTiles.Size(), submesh->LightmapTiles.Size());
|
printf(" Ray tracing tiles: %u / %u\n", mesh->LightmapTiles.Size(), mesh->LightmapTiles.Size());
|
||||||
|
|
||||||
submesh->LMTextureData.Resize(submesh->LMTextureSize * submesh->LMTextureSize * submesh->LMTextureCount * 4);
|
mesh->LMTextureData.Resize(mesh->LMTextureSize * mesh->LMTextureSize * mesh->LMTextureCount * 4);
|
||||||
for (int arrayIndex = 0; arrayIndex < submesh->LMTextureCount; arrayIndex++)
|
for (int arrayIndex = 0; arrayIndex < mesh->LMTextureCount; arrayIndex++)
|
||||||
{
|
{
|
||||||
mDevice->GetTextureManager()->DownloadLightmap(arrayIndex, submesh->LMTextureData.Data() + arrayIndex * submesh->LMTextureSize * submesh->LMTextureSize * 4);
|
mDevice->GetTextureManager()->DownloadLightmap(arrayIndex, mesh->LMTextureData.Data() + arrayIndex * mesh->LMTextureSize * mesh->LMTextureSize * 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
|
|
|
@ -6,6 +6,31 @@ LevelMesh::LevelMesh()
|
||||||
// Default portal
|
// Default portal
|
||||||
LevelMeshPortal portal;
|
LevelMeshPortal portal;
|
||||||
Portals.Push(portal);
|
Portals.Push(portal);
|
||||||
|
|
||||||
|
AddEmptyMesh();
|
||||||
|
UpdateCollision();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LevelMesh::AddEmptyMesh()
|
||||||
|
{
|
||||||
|
// Default empty mesh (we can't make it completely empty since vulkan doesn't like that)
|
||||||
|
float minval = -100001.0f;
|
||||||
|
float maxval = -100000.0f;
|
||||||
|
Mesh.Vertices.Push({ minval, minval, minval });
|
||||||
|
Mesh.Vertices.Push({ maxval, minval, minval });
|
||||||
|
Mesh.Vertices.Push({ maxval, maxval, minval });
|
||||||
|
Mesh.Vertices.Push({ minval, minval, minval });
|
||||||
|
Mesh.Vertices.Push({ minval, maxval, minval });
|
||||||
|
Mesh.Vertices.Push({ maxval, maxval, minval });
|
||||||
|
Mesh.Vertices.Push({ minval, minval, maxval });
|
||||||
|
Mesh.Vertices.Push({ maxval, minval, maxval });
|
||||||
|
Mesh.Vertices.Push({ maxval, maxval, maxval });
|
||||||
|
Mesh.Vertices.Push({ minval, minval, maxval });
|
||||||
|
Mesh.Vertices.Push({ minval, maxval, maxval });
|
||||||
|
Mesh.Vertices.Push({ maxval, maxval, maxval });
|
||||||
|
|
||||||
|
for (int i = 0; i < 3 * 4; i++)
|
||||||
|
Mesh.Indexes.Push(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
LevelMeshSurface* LevelMesh::Trace(const FVector3& start, FVector3 direction, float maxDist)
|
LevelMeshSurface* LevelMesh::Trace(const FVector3& start, FVector3 direction, float maxDist)
|
||||||
|
@ -20,18 +45,14 @@ LevelMeshSurface* LevelMesh::Trace(const FVector3& start, FVector3 direction, fl
|
||||||
{
|
{
|
||||||
FVector3 end = origin + direction * maxDist;
|
FVector3 end = origin + direction * maxDist;
|
||||||
|
|
||||||
TraceHit hit0 = TriangleMeshShape::find_first_hit(StaticMesh->Collision.get(), origin, end);
|
TraceHit hit = TriangleMeshShape::find_first_hit(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)
|
if (hit.triangle < 0)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
hitSurface = hitmesh->GetSurface(hitmesh->Mesh.SurfaceIndexes[hit.triangle]);
|
hitSurface = GetSurface(Mesh.SurfaceIndexes[hit.triangle]);
|
||||||
|
|
||||||
int portal = hitSurface->PortalIndex;
|
int portal = hitSurface->PortalIndex;
|
||||||
if (!portal)
|
if (!portal)
|
||||||
|
@ -58,44 +79,6 @@ LevelMeshSurface* LevelMesh::Trace(const FVector3& start, FVector3 direction, fl
|
||||||
LevelMeshTileStats LevelMesh::GatherTilePixelStats()
|
LevelMeshTileStats LevelMesh::GatherTilePixelStats()
|
||||||
{
|
{
|
||||||
LevelMeshTileStats stats;
|
LevelMeshTileStats stats;
|
||||||
StaticMesh->GatherTilePixelStats(stats);
|
|
||||||
DynamicMesh->GatherTilePixelStats(stats);
|
|
||||||
return stats;
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
LevelSubmesh::LevelSubmesh()
|
|
||||||
{
|
|
||||||
// Default empty mesh (we can't make it completely empty since vulkan doesn't like that)
|
|
||||||
float minval = -100001.0f;
|
|
||||||
float maxval = -100000.0f;
|
|
||||||
Mesh.Vertices.Push({ minval, minval, minval });
|
|
||||||
Mesh.Vertices.Push({ maxval, minval, minval });
|
|
||||||
Mesh.Vertices.Push({ maxval, maxval, minval });
|
|
||||||
Mesh.Vertices.Push({ minval, minval, minval });
|
|
||||||
Mesh.Vertices.Push({ minval, maxval, minval });
|
|
||||||
Mesh.Vertices.Push({ maxval, maxval, minval });
|
|
||||||
Mesh.Vertices.Push({ minval, minval, maxval });
|
|
||||||
Mesh.Vertices.Push({ maxval, minval, maxval });
|
|
||||||
Mesh.Vertices.Push({ maxval, maxval, maxval });
|
|
||||||
Mesh.Vertices.Push({ minval, minval, maxval });
|
|
||||||
Mesh.Vertices.Push({ minval, maxval, maxval });
|
|
||||||
Mesh.Vertices.Push({ maxval, maxval, maxval });
|
|
||||||
|
|
||||||
for (int i = 0; i < 3 * 4; i++)
|
|
||||||
Mesh.Indexes.Push(i);
|
|
||||||
|
|
||||||
UpdateCollision();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LevelSubmesh::UpdateCollision()
|
|
||||||
{
|
|
||||||
Collision = std::make_unique<TriangleMeshShape>(Mesh.Vertices.Data(), Mesh.Vertices.Size(), Mesh.Indexes.Data(), Mesh.Indexes.Size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void LevelSubmesh::GatherTilePixelStats(LevelMeshTileStats& stats)
|
|
||||||
{
|
|
||||||
int count = GetSurfaceCount();
|
int count = GetSurfaceCount();
|
||||||
for (const LightmapTile& tile : LightmapTiles)
|
for (const LightmapTile& tile : LightmapTiles)
|
||||||
{
|
{
|
||||||
|
@ -110,6 +93,12 @@ void LevelSubmesh::GatherTilePixelStats(LevelMeshTileStats& stats)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stats.tiles.total += LightmapTiles.Size();
|
stats.tiles.total += LightmapTiles.Size();
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LevelMesh::UpdateCollision()
|
||||||
|
{
|
||||||
|
Collision = std::make_unique<TriangleMeshShape>(Mesh.Vertices.Data(), Mesh.Vertices.Size(), Mesh.Indexes.Data(), Mesh.Indexes.Size());
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LevelMeshPlaneGroup
|
struct LevelMeshPlaneGroup
|
||||||
|
@ -119,7 +108,7 @@ struct LevelMeshPlaneGroup
|
||||||
std::vector<LevelMeshSurface*> surfaces;
|
std::vector<LevelMeshSurface*> surfaces;
|
||||||
};
|
};
|
||||||
|
|
||||||
void LevelSubmesh::BuildTileSurfaceLists()
|
void LevelMesh::BuildTileSurfaceLists()
|
||||||
{
|
{
|
||||||
// Plane group surface is to be rendered with
|
// Plane group surface is to be rendered with
|
||||||
TArray<LevelMeshPlaneGroup> PlaneGroups;
|
TArray<LevelMeshPlaneGroup> PlaneGroups;
|
||||||
|
@ -137,13 +126,13 @@ void LevelSubmesh::BuildTileSurfaceLists()
|
||||||
if (surface->SectorGroup == PlaneGroups[j].sectorGroup)
|
if (surface->SectorGroup == PlaneGroups[j].sectorGroup)
|
||||||
{
|
{
|
||||||
float direction = PlaneGroups[j].plane.XYZ() | surface->Plane.XYZ();
|
float direction = PlaneGroups[j].plane.XYZ() | surface->Plane.XYZ();
|
||||||
if (direction >= 0.9999f && direction <= 1.001f)
|
if (direction >= 0.999f && direction <= 1.01f)
|
||||||
{
|
{
|
||||||
auto point = (surface->Plane.XYZ() * surface->Plane.W);
|
auto point = (surface->Plane.XYZ() * surface->Plane.W);
|
||||||
auto planeDistance = (PlaneGroups[j].plane.XYZ() | point) - PlaneGroups[j].plane.W;
|
auto planeDistance = (PlaneGroups[j].plane.XYZ() | point) - PlaneGroups[j].plane.W;
|
||||||
|
|
||||||
float dist = std::abs(planeDistance);
|
float dist = std::abs(planeDistance);
|
||||||
if (dist <= 0.01f)
|
if (dist <= 0.1f)
|
||||||
{
|
{
|
||||||
planeGroupIndex = (int)j;
|
planeGroupIndex = (int)j;
|
||||||
break;
|
break;
|
||||||
|
@ -183,7 +172,105 @@ void LevelSubmesh::BuildTileSurfaceLists()
|
||||||
if (surface != targetSurface && (maxUV.X < 0.0f || maxUV.Y < 0.0f || minUV.X > 1.0f || minUV.Y > 1.0f))
|
if (surface != targetSurface && (maxUV.X < 0.0f || maxUV.Y < 0.0f || minUV.X > 1.0f || minUV.Y > 1.0f))
|
||||||
continue; // Bounding box not visible
|
continue; // Bounding box not visible
|
||||||
|
|
||||||
tile->Surfaces.Push(surface);
|
tile->Surfaces.Push(GetSurfaceIndex(surface));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LevelMesh::SetupTileTransforms()
|
||||||
|
{
|
||||||
|
for (auto& tile : LightmapTiles)
|
||||||
|
{
|
||||||
|
tile.SetupTileTransform(LMTextureSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LevelMesh::PackLightmapAtlas(int lightmapStartIndex)
|
||||||
|
{
|
||||||
|
std::vector<LightmapTile*> sortedTiles;
|
||||||
|
sortedTiles.reserve(LightmapTiles.Size());
|
||||||
|
|
||||||
|
for (auto& tile : LightmapTiles)
|
||||||
|
{
|
||||||
|
sortedTiles.push_back(&tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(sortedTiles.begin(), sortedTiles.end(), [](LightmapTile* a, LightmapTile* b) { return a->AtlasLocation.Height != b->AtlasLocation.Height ? a->AtlasLocation.Height > b->AtlasLocation.Height : a->AtlasLocation.Width > b->AtlasLocation.Width; });
|
||||||
|
|
||||||
|
// We do not need to add spacing here as this is already built into the tile size itself.
|
||||||
|
RectPacker packer(LMTextureSize, LMTextureSize, RectPacker::Spacing(0), RectPacker::Padding(0));
|
||||||
|
|
||||||
|
for (LightmapTile* tile : sortedTiles)
|
||||||
|
{
|
||||||
|
auto result = packer.insert(tile->AtlasLocation.Width, tile->AtlasLocation.Height);
|
||||||
|
tile->AtlasLocation.X = result.pos.x;
|
||||||
|
tile->AtlasLocation.Y = result.pos.y;
|
||||||
|
tile->AtlasLocation.ArrayIndex = lightmapStartIndex + (int)result.pageIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
LMTextureCount = (int)packer.getNumPages();
|
||||||
|
|
||||||
|
// Calculate final texture coordinates
|
||||||
|
for (int i = 0, count = GetSurfaceCount(); i < count; i++)
|
||||||
|
{
|
||||||
|
auto surface = GetSurface(i);
|
||||||
|
if (surface->LightmapTileIndex >= 0)
|
||||||
|
{
|
||||||
|
const LightmapTile& tile = LightmapTiles[surface->LightmapTileIndex];
|
||||||
|
for (int i = 0; i < surface->MeshLocation.NumVerts; i++)
|
||||||
|
{
|
||||||
|
auto& vertex = Mesh.Vertices[surface->MeshLocation.StartVertIndex + i];
|
||||||
|
FVector2 uv = tile.ToUV(vertex.fPos(), (float)LMTextureSize);
|
||||||
|
vertex.lu = uv.X;
|
||||||
|
vertex.lv = uv.Y;
|
||||||
|
vertex.lindex = (float)tile.AtlasLocation.ArrayIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0 // Debug atlas tile locations:
|
||||||
|
float colors[30] =
|
||||||
|
{
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 1.0f, 0.0f,
|
||||||
|
1.0f, 1.0f, 0.0f,
|
||||||
|
0.0f, 1.0f, 1.0f,
|
||||||
|
1.0f, 0.0f, 1.0f,
|
||||||
|
0.5f, 0.0f, 0.0f,
|
||||||
|
0.0f, 0.5f, 0.0f,
|
||||||
|
0.5f, 0.5f, 0.0f,
|
||||||
|
0.0f, 0.5f, 0.5f,
|
||||||
|
0.5f, 0.0f, 0.5f
|
||||||
|
};
|
||||||
|
LMTextureData.Resize(LMTextureSize * LMTextureSize * LMTextureCount * 3);
|
||||||
|
uint16_t* pixels = LMTextureData.Data();
|
||||||
|
for (LightmapTile& tile : LightmapTiles)
|
||||||
|
{
|
||||||
|
tile.NeedsUpdate = false;
|
||||||
|
|
||||||
|
int index = tile.Binding.TypeIndex;
|
||||||
|
float* color = colors + (index % 10) * 3;
|
||||||
|
|
||||||
|
int x = tile.AtlasLocation.X;
|
||||||
|
int y = tile.AtlasLocation.Y;
|
||||||
|
int w = tile.AtlasLocation.Width;
|
||||||
|
int h = tile.AtlasLocation.Height;
|
||||||
|
for (int yy = y; yy < y + h; yy++)
|
||||||
|
{
|
||||||
|
uint16_t* line = pixels + tile.AtlasLocation.ArrayIndex * LMTextureSize * LMTextureSize + yy * LMTextureSize * 3;
|
||||||
|
for (int xx = x; xx < x + w; xx++)
|
||||||
|
{
|
||||||
|
float gray = (yy - y) / (float)h;
|
||||||
|
line[xx * 3] = floatToHalf(color[0] * gray);
|
||||||
|
line[xx * 3 + 1] = floatToHalf(color[1] * gray);
|
||||||
|
line[xx * 3 + 2] = floatToHalf(color[2] * gray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0, count = GetSurfaceCount(); i < count; i++)
|
||||||
|
{
|
||||||
|
auto surface = GetSurface(i);
|
||||||
|
surface->AlwaysUpdate = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
#include "hw_surfaceuniforms.h"
|
#include "hw_surfaceuniforms.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include <dp_rect_pack/dp_rect_pack.h>
|
||||||
|
typedef dp::rect_pack::RectPacker<int> RectPacker;
|
||||||
|
|
||||||
struct LevelMeshTileStats;
|
struct LevelMeshTileStats;
|
||||||
|
|
||||||
struct LevelSubmeshDrawRange
|
struct LevelSubmeshDrawRange
|
||||||
|
@ -22,24 +25,54 @@ struct LevelSubmeshDrawRange
|
||||||
int Count;
|
int Count;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LevelSubmesh
|
class LevelMesh
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LevelSubmesh();
|
LevelMesh();
|
||||||
virtual ~LevelSubmesh() = default;
|
virtual ~LevelMesh() = default;
|
||||||
|
|
||||||
virtual LevelMeshSurface* GetSurface(int index) { return nullptr; }
|
virtual LevelMeshSurface* GetSurface(int index) { return nullptr; }
|
||||||
virtual unsigned int GetSurfaceIndex(const LevelMeshSurface* surface) const { return 0xffffffff; }
|
virtual unsigned int GetSurfaceIndex(const LevelMeshSurface* surface) const { return 0xffffffff; }
|
||||||
virtual int GetSurfaceCount() { return 0; }
|
virtual int GetSurfaceCount() { return 0; }
|
||||||
|
|
||||||
|
LevelMeshSurface* Trace(const FVector3& start, FVector3 direction, float maxDist);
|
||||||
|
|
||||||
|
LevelMeshTileStats GatherTilePixelStats();
|
||||||
|
|
||||||
|
// Map defaults
|
||||||
|
FVector3 SunDirection = FVector3(0.0f, 0.0f, -1.0f);
|
||||||
|
FVector3 SunColor = FVector3(0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
TArray<LevelMeshPortal> Portals;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
// Vertex data
|
||||||
TArray<FFlatVertex> Vertices;
|
TArray<FFlatVertex> Vertices;
|
||||||
TArray<uint32_t> Indexes;
|
|
||||||
TArray<int> SurfaceIndexes;
|
|
||||||
TArray<int> UniformIndexes;
|
TArray<int> UniformIndexes;
|
||||||
|
|
||||||
|
// Surface info
|
||||||
TArray<SurfaceUniforms> Uniforms;
|
TArray<SurfaceUniforms> Uniforms;
|
||||||
TArray<FMaterialState> Materials;
|
TArray<FMaterialState> Materials;
|
||||||
|
TArray<int32_t> LightIndexes;
|
||||||
|
|
||||||
|
// Lights
|
||||||
|
TArray<LevelMeshLight> Lights;
|
||||||
|
|
||||||
|
// Index data
|
||||||
|
TArray<uint32_t> Indexes;
|
||||||
|
TArray<int> SurfaceIndexes;
|
||||||
|
int DynamicIndexStart = 0;
|
||||||
|
|
||||||
|
// Above data must not be resized beyond these limits as that's the size of the GPU buffers)
|
||||||
|
int MaxVertices = 0;
|
||||||
|
int MaxIndexes = 0;
|
||||||
|
int MaxSurfaces = 0;
|
||||||
|
int MaxUniforms = 0;
|
||||||
|
int MaxSurfaceIndexes = 0;
|
||||||
|
int MaxNodes = 0;
|
||||||
|
int MaxLights = 0;
|
||||||
|
int MaxLightIndexes = 0;
|
||||||
} Mesh;
|
} Mesh;
|
||||||
|
|
||||||
std::unique_ptr<TriangleMeshShape> Collision;
|
std::unique_ptr<TriangleMeshShape> Collision;
|
||||||
|
@ -59,33 +92,11 @@ public:
|
||||||
uint32_t AtlasPixelCount() const { return uint32_t(LMTextureCount * LMTextureSize * LMTextureSize); }
|
uint32_t AtlasPixelCount() const { return uint32_t(LMTextureCount * LMTextureSize * LMTextureSize); }
|
||||||
|
|
||||||
void UpdateCollision();
|
void UpdateCollision();
|
||||||
void GatherTilePixelStats(LevelMeshTileStats& stats);
|
|
||||||
void BuildTileSurfaceLists();
|
void BuildTileSurfaceLists();
|
||||||
|
void SetupTileTransforms();
|
||||||
|
void PackLightmapAtlas(int lightmapStartIndex);
|
||||||
|
|
||||||
private:
|
void AddEmptyMesh();
|
||||||
FVector2 ToUV(const FVector3& vert, const LightmapTile* tile);
|
|
||||||
};
|
|
||||||
|
|
||||||
class LevelMesh
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LevelMesh();
|
|
||||||
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; }
|
|
||||||
|
|
||||||
LevelMeshSurface* Trace(const FVector3& start, FVector3 direction, float maxDist);
|
|
||||||
|
|
||||||
LevelMeshTileStats GatherTilePixelStats();
|
|
||||||
|
|
||||||
// Map defaults
|
|
||||||
FVector3 SunDirection = FVector3(0.0f, 0.0f, -1.0f);
|
|
||||||
FVector3 SunColor = FVector3(0.0f, 0.0f, 0.0f);
|
|
||||||
|
|
||||||
TArray<LevelMeshPortal> Portals;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LevelMeshTileStats
|
struct LevelMeshTileStats
|
||||||
|
|
|
@ -9,11 +9,10 @@
|
||||||
|
|
||||||
class LevelSubmesh;
|
class LevelSubmesh;
|
||||||
struct LevelMeshSurface;
|
struct LevelMeshSurface;
|
||||||
|
struct ThingLight;
|
||||||
|
|
||||||
struct LevelMeshSurface
|
struct LevelMeshSurface
|
||||||
{
|
{
|
||||||
LevelSubmesh* Submesh = nullptr;
|
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
unsigned int StartVertIndex = 0;
|
unsigned int StartVertIndex = 0;
|
||||||
|
@ -28,9 +27,9 @@ struct LevelMeshSurface
|
||||||
|
|
||||||
bool AlwaysUpdate = false;
|
bool AlwaysUpdate = false;
|
||||||
|
|
||||||
FTextureID Texture = FNullTextureID();
|
FTextureID Texture = FNullTextureID(); // FGameTexture* Texture = nullptr;
|
||||||
float Alpha = 1.0;
|
float Alpha = 1.0;
|
||||||
|
|
||||||
bool IsSky = false;
|
bool IsSky = false;
|
||||||
int PortalIndex = 0;
|
int PortalIndex = 0;
|
||||||
int SectorGroup = 0;
|
int SectorGroup = 0;
|
||||||
|
@ -38,8 +37,9 @@ struct LevelMeshSurface
|
||||||
// Light list location in the lightmapper GPU buffers
|
// Light list location in the lightmapper GPU buffers
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
int Pos = -1;
|
int Pos = 0;
|
||||||
int Count = 0;
|
int Count = 0;
|
||||||
int ResetCounter = -1;
|
|
||||||
} LightList;
|
} LightList;
|
||||||
|
|
||||||
|
TArray<ThingLight*> Lights;
|
||||||
};
|
};
|
||||||
|
|
|
@ -45,7 +45,7 @@ struct LightmapTile
|
||||||
LightmapTileBinding Binding;
|
LightmapTileBinding Binding;
|
||||||
|
|
||||||
// Surfaces that are visible within the lightmap tile
|
// Surfaces that are visible within the lightmap tile
|
||||||
TArray<LevelMeshSurface*> Surfaces;
|
TArray<int> Surfaces;
|
||||||
|
|
||||||
BBox Bounds;
|
BBox Bounds;
|
||||||
uint16_t SampleDimension = 0;
|
uint16_t SampleDimension = 0;
|
||||||
|
@ -57,16 +57,114 @@ struct LightmapTile
|
||||||
FVector2 ToUV(const FVector3& vert) const
|
FVector2 ToUV(const FVector3& vert) const
|
||||||
{
|
{
|
||||||
FVector3 localPos = vert - Transform.TranslateWorldToLocal;
|
FVector3 localPos = vert - Transform.TranslateWorldToLocal;
|
||||||
float u = (1.0f + (localPos | Transform.ProjLocalToU)) / (AtlasLocation.Width + 2);
|
float u = (localPos | Transform.ProjLocalToU) / AtlasLocation.Width;
|
||||||
float v = (1.0f + (localPos | Transform.ProjLocalToV)) / (AtlasLocation.Height + 2);
|
float v = (localPos | Transform.ProjLocalToV) / AtlasLocation.Height;
|
||||||
return FVector2(u, v);
|
return FVector2(u, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
FVector2 ToUV(const FVector3& vert, float textureSize) const
|
FVector2 ToUV(const FVector3& vert, float textureSize) const
|
||||||
{
|
{
|
||||||
|
// Clamp in case the wall moved outside the tile (happens if a lift moves with a static lightmap on it)
|
||||||
FVector3 localPos = vert - Transform.TranslateWorldToLocal;
|
FVector3 localPos = vert - Transform.TranslateWorldToLocal;
|
||||||
float u = (AtlasLocation.X + (localPos | Transform.ProjLocalToU)) / textureSize;
|
float u = std::max(std::min(localPos | Transform.ProjLocalToU, (float)AtlasLocation.Width), 0.0f);
|
||||||
float v = (AtlasLocation.Y + (localPos | Transform.ProjLocalToV)) / textureSize;
|
float v = std::max(std::min(localPos | Transform.ProjLocalToV, (float)AtlasLocation.Height), 0.0f);
|
||||||
|
u = (AtlasLocation.X + u) / textureSize;
|
||||||
|
v = (AtlasLocation.Y + v) / textureSize;
|
||||||
return FVector2(u, v);
|
return FVector2(u, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum PlaneAxis
|
||||||
|
{
|
||||||
|
AXIS_YZ = 0,
|
||||||
|
AXIS_XZ,
|
||||||
|
AXIS_XY
|
||||||
|
};
|
||||||
|
|
||||||
|
static PlaneAxis BestAxis(const FVector4& p)
|
||||||
|
{
|
||||||
|
float na = fabs(float(p.X));
|
||||||
|
float nb = fabs(float(p.Y));
|
||||||
|
float nc = fabs(float(p.Z));
|
||||||
|
|
||||||
|
// figure out what axis the plane lies on
|
||||||
|
if (na >= nb && na >= nc)
|
||||||
|
{
|
||||||
|
return AXIS_YZ;
|
||||||
|
}
|
||||||
|
else if (nb >= na && nb >= nc)
|
||||||
|
{
|
||||||
|
return AXIS_XZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AXIS_XY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupTileTransform(int textureSize)
|
||||||
|
{
|
||||||
|
// These calculations align the tile so that there's a one texel border around the actual surface in the tile.
|
||||||
|
//
|
||||||
|
// This removes sampling artifacts as a linear sampler reads from a 2x2 area.
|
||||||
|
// The tile is also aligned to the grid to keep aliasing artifacts consistent.
|
||||||
|
|
||||||
|
FVector3 uvMin;
|
||||||
|
uvMin.X = std::floor(Bounds.min.X / SampleDimension) - 1.0f;
|
||||||
|
uvMin.Y = std::floor(Bounds.min.Y / SampleDimension) - 1.0f;
|
||||||
|
uvMin.Z = std::floor(Bounds.min.Z / SampleDimension) - 1.0f;
|
||||||
|
|
||||||
|
FVector3 uvMax;
|
||||||
|
uvMax.X = std::floor(Bounds.max.X / SampleDimension) + 2.0f;
|
||||||
|
uvMax.Y = std::floor(Bounds.max.Y / SampleDimension) + 2.0f;
|
||||||
|
uvMax.Z = std::floor(Bounds.max.Z / SampleDimension) + 2.0f;
|
||||||
|
|
||||||
|
FVector3 tCoords[2] = { FVector3(0.0f, 0.0f, 0.0f), FVector3(0.0f, 0.0f, 0.0f) };
|
||||||
|
int width, height;
|
||||||
|
switch (BestAxis(Plane))
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case AXIS_YZ:
|
||||||
|
width = (int)(uvMax.Y - uvMin.Y);
|
||||||
|
height = (int)(uvMax.Z - uvMin.Z);
|
||||||
|
tCoords[0].Y = 1.0f / SampleDimension;
|
||||||
|
tCoords[1].Z = 1.0f / SampleDimension;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AXIS_XZ:
|
||||||
|
width = (int)(uvMax.X - uvMin.X);
|
||||||
|
height = (int)(uvMax.Z - uvMin.Z);
|
||||||
|
tCoords[0].X = 1.0f / SampleDimension;
|
||||||
|
tCoords[1].Z = 1.0f / SampleDimension;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AXIS_XY:
|
||||||
|
width = (int)(uvMax.X - uvMin.X);
|
||||||
|
height = (int)(uvMax.Y - uvMin.Y);
|
||||||
|
tCoords[0].X = 1.0f / SampleDimension;
|
||||||
|
tCoords[1].Y = 1.0f / SampleDimension;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
textureSize -= 6; // Lightmapper needs some padding when baking
|
||||||
|
|
||||||
|
// Tile can never be bigger than the texture.
|
||||||
|
if (width > textureSize)
|
||||||
|
{
|
||||||
|
tCoords[0] *= textureSize / (float)width;
|
||||||
|
width = textureSize;
|
||||||
|
}
|
||||||
|
if (height > textureSize)
|
||||||
|
{
|
||||||
|
tCoords[1] *= textureSize / (float)height;
|
||||||
|
height = textureSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform.TranslateWorldToLocal.X = uvMin.X * SampleDimension;
|
||||||
|
Transform.TranslateWorldToLocal.Y = uvMin.Y * SampleDimension;
|
||||||
|
Transform.TranslateWorldToLocal.Z = uvMin.Z * SampleDimension;
|
||||||
|
|
||||||
|
Transform.ProjLocalToU = tCoords[0];
|
||||||
|
Transform.ProjLocalToV = tCoords[1];
|
||||||
|
|
||||||
|
AtlasLocation.Width = width;
|
||||||
|
AtlasLocation.Height = height;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
VkLevelMesh::VkLevelMesh(VulkanRenderDevice* fb) : fb(fb)
|
VkLevelMesh::VkLevelMesh(VulkanRenderDevice* fb) : fb(fb)
|
||||||
{
|
{
|
||||||
useRayQuery = fb->GetDevice()->SupportsExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME) && fb->GetDevice()->PhysicalDevice.Features.RayQuery.rayQuery;
|
useRayQuery = fb->IsRayQueryEnabled();
|
||||||
|
|
||||||
SetLevelMesh(nullptr);
|
SetLevelMesh(nullptr);
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,8 @@ void VkLevelMesh::Reset()
|
||||||
deletelist->Add(std::move(UniformsBuffer));
|
deletelist->Add(std::move(UniformsBuffer));
|
||||||
deletelist->Add(std::move(SurfaceIndexBuffer));
|
deletelist->Add(std::move(SurfaceIndexBuffer));
|
||||||
deletelist->Add(std::move(PortalBuffer));
|
deletelist->Add(std::move(PortalBuffer));
|
||||||
|
deletelist->Add(std::move(LightBuffer));
|
||||||
|
deletelist->Add(std::move(LightIndexBuffer));
|
||||||
deletelist->Add(std::move(StaticBLAS.ScratchBuffer));
|
deletelist->Add(std::move(StaticBLAS.ScratchBuffer));
|
||||||
deletelist->Add(std::move(StaticBLAS.AccelStructBuffer));
|
deletelist->Add(std::move(StaticBLAS.AccelStructBuffer));
|
||||||
deletelist->Add(std::move(StaticBLAS.AccelStruct));
|
deletelist->Add(std::move(StaticBLAS.AccelStruct));
|
||||||
|
@ -89,7 +91,7 @@ void VkLevelMesh::CreateVulkanObjects()
|
||||||
.AddMemory(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR | VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_SHADER_READ_BIT)
|
.AddMemory(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR | VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_SHADER_READ_BIT)
|
||||||
.Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR);
|
.Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR);
|
||||||
|
|
||||||
CreateTopLevelAS();
|
CreateTopLevelAS(DynamicBLAS.AccelStruct ? 2 : 1);
|
||||||
|
|
||||||
// Finish building the accel struct before using it from the shaders
|
// Finish building the accel struct before using it from the shaders
|
||||||
PipelineBarrier()
|
PipelineBarrier()
|
||||||
|
@ -126,7 +128,8 @@ void VkLevelMesh::BeginFrame()
|
||||||
deletelist->Add(std::move(TopLevelAS.TransferBuffer));
|
deletelist->Add(std::move(TopLevelAS.TransferBuffer));
|
||||||
deletelist->Add(std::move(TopLevelAS.InstanceBuffer));
|
deletelist->Add(std::move(TopLevelAS.InstanceBuffer));
|
||||||
|
|
||||||
DynamicBLAS = CreateBLAS(Mesh->DynamicMesh.get(), true, Mesh->StaticMesh->Mesh.Vertices.Size(), Mesh->StaticMesh->Mesh.Indexes.Size());
|
if (Mesh->Mesh.DynamicIndexStart < (int)Mesh->Mesh.Indexes.Size())
|
||||||
|
DynamicBLAS = CreateBLAS(true, Mesh->Mesh.DynamicIndexStart, Mesh->Mesh.Indexes.Size() - Mesh->Mesh.DynamicIndexStart);
|
||||||
|
|
||||||
CreateTLASInstanceBuffer();
|
CreateTLASInstanceBuffer();
|
||||||
UploadTLASInstanceBuffer();
|
UploadTLASInstanceBuffer();
|
||||||
|
@ -136,7 +139,7 @@ void VkLevelMesh::BeginFrame()
|
||||||
.AddMemory(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR | VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_SHADER_READ_BIT)
|
.AddMemory(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR | VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_SHADER_READ_BIT)
|
||||||
.Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR);
|
.Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR);
|
||||||
|
|
||||||
UpdateTopLevelAS();
|
UpdateTopLevelAS(DynamicBLAS.AccelStruct ? 2 : 1);
|
||||||
|
|
||||||
// Finish building the accel struct before using it from the shaders
|
// Finish building the accel struct before using it from the shaders
|
||||||
PipelineBarrier()
|
PipelineBarrier()
|
||||||
|
@ -154,38 +157,27 @@ void VkLevelMesh::BeginFrame()
|
||||||
|
|
||||||
void VkLevelMesh::UploadMeshes(bool dynamicOnly)
|
void VkLevelMesh::UploadMeshes(bool dynamicOnly)
|
||||||
{
|
{
|
||||||
|
if (dynamicOnly)
|
||||||
|
{
|
||||||
|
Locations.Index.Push({ Mesh->Mesh.DynamicIndexStart, (int)(Mesh->Mesh.Indexes.Size() - Mesh->Mesh.DynamicIndexStart) });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!useRayQuery)
|
||||||
|
Locations.Node.Push({ 0, (int)Mesh->Collision->get_nodes().size() });
|
||||||
|
Locations.Vertex.Push({ 0, (int)Mesh->Mesh.Vertices.Size() });
|
||||||
|
Locations.Index.Push({ 0, (int)Mesh->Mesh.Indexes.Size() });
|
||||||
|
Locations.SurfaceIndex.Push({ 0, (int)Mesh->Mesh.SurfaceIndexes.Size() });
|
||||||
|
Locations.Surface.Push({ 0, Mesh->GetSurfaceCount() });
|
||||||
|
Locations.UniformIndexes.Push({ 0, (int)Mesh->Mesh.UniformIndexes.Size() });
|
||||||
|
Locations.Uniforms.Push({ 0, (int)Mesh->Mesh.Uniforms.Size() });
|
||||||
|
Locations.Portals.Push({ 0, (int)Mesh->Portals.Size() });
|
||||||
|
Locations.Light.Push({ 0, (int)Mesh->Mesh.Lights.Size() });
|
||||||
|
Locations.LightIndex.Push({ 0, (int)Mesh->Mesh.LightIndexes.Size() });
|
||||||
|
}
|
||||||
|
|
||||||
VkLevelMeshUploader uploader(this);
|
VkLevelMeshUploader uploader(this);
|
||||||
uploader.Upload(dynamicOnly);
|
uploader.Upload();
|
||||||
}
|
|
||||||
|
|
||||||
int VkLevelMesh::GetMaxVertexBufferSize()
|
|
||||||
{
|
|
||||||
return Mesh->StaticMesh->Mesh.Vertices.Size() + MaxDynamicVertices;
|
|
||||||
}
|
|
||||||
|
|
||||||
int VkLevelMesh::GetMaxIndexBufferSize()
|
|
||||||
{
|
|
||||||
return Mesh->StaticMesh->Mesh.Indexes.Size() + MaxDynamicIndexes;
|
|
||||||
}
|
|
||||||
|
|
||||||
int VkLevelMesh::GetMaxNodeBufferSize()
|
|
||||||
{
|
|
||||||
return (int)Mesh->StaticMesh->Collision->get_nodes().size() + MaxDynamicNodes + 1; // + 1 for the merge root node
|
|
||||||
}
|
|
||||||
|
|
||||||
int VkLevelMesh::GetMaxSurfaceBufferSize()
|
|
||||||
{
|
|
||||||
return Mesh->StaticMesh->GetSurfaceCount() + MaxDynamicSurfaces;
|
|
||||||
}
|
|
||||||
|
|
||||||
int VkLevelMesh::GetMaxUniformsBufferSize()
|
|
||||||
{
|
|
||||||
return Mesh->StaticMesh->Mesh.Uniforms.Size() + MaxDynamicUniforms;
|
|
||||||
}
|
|
||||||
|
|
||||||
int VkLevelMesh::GetMaxSurfaceIndexBufferSize()
|
|
||||||
{
|
|
||||||
return Mesh->StaticMesh->Mesh.SurfaceIndexes.Size() + MaxDynamicSurfaceIndexes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkLevelMesh::CreateBuffers()
|
void VkLevelMesh::CreateBuffers()
|
||||||
|
@ -198,7 +190,7 @@ void VkLevelMesh::CreateBuffers()
|
||||||
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
|
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
|
||||||
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR : 0) |
|
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR : 0) |
|
||||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
|
||||||
.Size(GetMaxVertexBufferSize() * sizeof(FFlatVertex))
|
.Size(Mesh->Mesh.MaxVertices * sizeof(FFlatVertex))
|
||||||
.DebugName("VertexBuffer")
|
.DebugName("VertexBuffer")
|
||||||
.Create(fb->GetDevice());
|
.Create(fb->GetDevice());
|
||||||
|
|
||||||
|
@ -206,7 +198,7 @@ void VkLevelMesh::CreateBuffers()
|
||||||
.Usage(
|
.Usage(
|
||||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
|
||||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
||||||
.Size(GetMaxVertexBufferSize() * sizeof(int))
|
.Size(Mesh->Mesh.MaxVertices * sizeof(int))
|
||||||
.DebugName("UniformIndexes")
|
.DebugName("UniformIndexes")
|
||||||
.Create(fb->GetDevice());
|
.Create(fb->GetDevice());
|
||||||
|
|
||||||
|
@ -218,31 +210,31 @@ void VkLevelMesh::CreateBuffers()
|
||||||
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
|
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
|
||||||
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR : 0) |
|
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR : 0) |
|
||||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
|
||||||
.Size((size_t)GetMaxIndexBufferSize() * sizeof(uint32_t))
|
.Size((size_t)Mesh->Mesh.MaxIndexes * sizeof(uint32_t))
|
||||||
.DebugName("IndexBuffer")
|
.DebugName("IndexBuffer")
|
||||||
.Create(fb->GetDevice());
|
.Create(fb->GetDevice());
|
||||||
|
|
||||||
NodeBuffer = BufferBuilder()
|
NodeBuffer = BufferBuilder()
|
||||||
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
||||||
.Size(sizeof(CollisionNodeBufferHeader) + GetMaxNodeBufferSize() * sizeof(CollisionNode))
|
.Size(sizeof(CollisionNodeBufferHeader) + Mesh->Mesh.MaxNodes * sizeof(CollisionNode))
|
||||||
.DebugName("NodeBuffer")
|
.DebugName("NodeBuffer")
|
||||||
.Create(fb->GetDevice());
|
.Create(fb->GetDevice());
|
||||||
|
|
||||||
SurfaceIndexBuffer = BufferBuilder()
|
SurfaceIndexBuffer = BufferBuilder()
|
||||||
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
||||||
.Size(GetMaxSurfaceIndexBufferSize() * sizeof(int))
|
.Size(Mesh->Mesh.MaxSurfaceIndexes * sizeof(int))
|
||||||
.DebugName("SurfaceBuffer")
|
.DebugName("SurfaceBuffer")
|
||||||
.Create(fb->GetDevice());
|
.Create(fb->GetDevice());
|
||||||
|
|
||||||
SurfaceBuffer = BufferBuilder()
|
SurfaceBuffer = BufferBuilder()
|
||||||
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
||||||
.Size(GetMaxSurfaceBufferSize() * sizeof(SurfaceInfo))
|
.Size(Mesh->Mesh.MaxSurfaces * sizeof(SurfaceInfo))
|
||||||
.DebugName("SurfaceBuffer")
|
.DebugName("SurfaceBuffer")
|
||||||
.Create(fb->GetDevice());
|
.Create(fb->GetDevice());
|
||||||
|
|
||||||
UniformsBuffer = BufferBuilder()
|
UniformsBuffer = BufferBuilder()
|
||||||
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
||||||
.Size(GetMaxUniformsBufferSize() * sizeof(SurfaceUniforms))
|
.Size(Mesh->Mesh.MaxUniforms * sizeof(SurfaceUniforms))
|
||||||
.DebugName("SurfaceUniformsBuffer")
|
.DebugName("SurfaceUniformsBuffer")
|
||||||
.Create(fb->GetDevice());
|
.Create(fb->GetDevice());
|
||||||
|
|
||||||
|
@ -251,9 +243,21 @@ void VkLevelMesh::CreateBuffers()
|
||||||
.Size(Mesh->Portals.Size() * sizeof(PortalInfo))
|
.Size(Mesh->Portals.Size() * sizeof(PortalInfo))
|
||||||
.DebugName("PortalBuffer")
|
.DebugName("PortalBuffer")
|
||||||
.Create(fb->GetDevice());
|
.Create(fb->GetDevice());
|
||||||
|
|
||||||
|
LightBuffer = BufferBuilder()
|
||||||
|
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
||||||
|
.Size(Mesh->Mesh.MaxLights * sizeof(LightInfo))
|
||||||
|
.DebugName("LightBuffer")
|
||||||
|
.Create(fb->GetDevice());
|
||||||
|
|
||||||
|
LightIndexBuffer = BufferBuilder()
|
||||||
|
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
||||||
|
.Size(Mesh->Mesh.MaxLightIndexes * sizeof(int32_t))
|
||||||
|
.DebugName("LightIndexBuffer")
|
||||||
|
.Create(fb->GetDevice());
|
||||||
}
|
}
|
||||||
|
|
||||||
VkLevelMesh::BLAS VkLevelMesh::CreateBLAS(LevelSubmesh* submesh, bool preferFastBuild, int vertexOffset, int indexOffset)
|
VkLevelMesh::BLAS VkLevelMesh::CreateBLAS(bool preferFastBuild, int indexOffset, int indexCount)
|
||||||
{
|
{
|
||||||
BLAS blas;
|
BLAS blas;
|
||||||
|
|
||||||
|
@ -269,7 +273,7 @@ VkLevelMesh::BLAS VkLevelMesh::CreateBLAS(LevelSubmesh* submesh, bool preferFast
|
||||||
accelStructBLDesc.geometry.triangles.vertexStride = sizeof(FFlatVertex);
|
accelStructBLDesc.geometry.triangles.vertexStride = sizeof(FFlatVertex);
|
||||||
accelStructBLDesc.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32;
|
accelStructBLDesc.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32;
|
||||||
accelStructBLDesc.geometry.triangles.indexData.deviceAddress = IndexBuffer->GetDeviceAddress() + indexOffset * sizeof(uint32_t);
|
accelStructBLDesc.geometry.triangles.indexData.deviceAddress = IndexBuffer->GetDeviceAddress() + indexOffset * sizeof(uint32_t);
|
||||||
accelStructBLDesc.geometry.triangles.maxVertex = vertexOffset + submesh->Mesh.Vertices.Size() - 1;
|
accelStructBLDesc.geometry.triangles.maxVertex = Mesh->Mesh.Vertices.Size() - 1;
|
||||||
|
|
||||||
buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
|
buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
|
||||||
buildInfo.flags = preferFastBuild ? VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR : VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
buildInfo.flags = preferFastBuild ? VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR : VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
||||||
|
@ -277,7 +281,7 @@ VkLevelMesh::BLAS VkLevelMesh::CreateBLAS(LevelSubmesh* submesh, bool preferFast
|
||||||
buildInfo.geometryCount = 1;
|
buildInfo.geometryCount = 1;
|
||||||
buildInfo.ppGeometries = geometries;
|
buildInfo.ppGeometries = geometries;
|
||||||
|
|
||||||
uint32_t maxPrimitiveCount = submesh->Mesh.Indexes.Size() / 3;
|
uint32_t maxPrimitiveCount = indexCount / 3;
|
||||||
|
|
||||||
VkAccelerationStructureBuildSizesInfoKHR sizeInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR };
|
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);
|
vkGetAccelerationStructureBuildSizesKHR(fb->GetDevice()->device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, &maxPrimitiveCount, &sizeInfo);
|
||||||
|
@ -315,12 +319,13 @@ VkLevelMesh::BLAS VkLevelMesh::CreateBLAS(LevelSubmesh* submesh, bool preferFast
|
||||||
|
|
||||||
void VkLevelMesh::CreateStaticBLAS()
|
void VkLevelMesh::CreateStaticBLAS()
|
||||||
{
|
{
|
||||||
StaticBLAS = CreateBLAS(Mesh->StaticMesh.get(), false, 0, 0);
|
StaticBLAS = CreateBLAS(false, 0, Mesh->Mesh.DynamicIndexStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkLevelMesh::CreateDynamicBLAS()
|
void VkLevelMesh::CreateDynamicBLAS()
|
||||||
{
|
{
|
||||||
DynamicBLAS = CreateBLAS(Mesh->DynamicMesh.get(), true, Mesh->StaticMesh->Mesh.Vertices.Size(), Mesh->StaticMesh->Mesh.Indexes.Size());
|
if (Mesh->Mesh.DynamicIndexStart < (int)Mesh->Mesh.Indexes.Size())
|
||||||
|
DynamicBLAS = CreateBLAS(true, Mesh->Mesh.DynamicIndexStart, Mesh->Mesh.Indexes.Size() - Mesh->Mesh.DynamicIndexStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkLevelMesh::CreateTLASInstanceBuffer()
|
void VkLevelMesh::CreateTLASInstanceBuffer()
|
||||||
|
@ -338,7 +343,7 @@ void VkLevelMesh::CreateTLASInstanceBuffer()
|
||||||
.Create(fb->GetDevice());
|
.Create(fb->GetDevice());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkLevelMesh::CreateTopLevelAS()
|
void VkLevelMesh::CreateTopLevelAS(int instanceCount)
|
||||||
{
|
{
|
||||||
VkAccelerationStructureBuildGeometryInfoKHR buildInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR };
|
VkAccelerationStructureBuildGeometryInfoKHR buildInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR };
|
||||||
VkAccelerationStructureGeometryKHR accelStructTLDesc = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR };
|
VkAccelerationStructureGeometryKHR accelStructTLDesc = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR };
|
||||||
|
@ -383,12 +388,12 @@ void VkLevelMesh::CreateTopLevelAS()
|
||||||
|
|
||||||
VkAccelerationStructureBuildRangeInfoKHR rangeInfo = {};
|
VkAccelerationStructureBuildRangeInfoKHR rangeInfo = {};
|
||||||
VkAccelerationStructureBuildRangeInfoKHR* rangeInfos[] = { &rangeInfo };
|
VkAccelerationStructureBuildRangeInfoKHR* rangeInfos[] = { &rangeInfo };
|
||||||
rangeInfo.primitiveCount = 2;
|
rangeInfo.primitiveCount = instanceCount;
|
||||||
|
|
||||||
fb->GetCommands()->GetTransferCommands()->buildAccelerationStructures(1, &buildInfo, rangeInfos);
|
fb->GetCommands()->GetTransferCommands()->buildAccelerationStructures(1, &buildInfo, rangeInfos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkLevelMesh::UpdateTopLevelAS()
|
void VkLevelMesh::UpdateTopLevelAS(int instanceCount)
|
||||||
{
|
{
|
||||||
VkAccelerationStructureBuildGeometryInfoKHR buildInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR };
|
VkAccelerationStructureBuildGeometryInfoKHR buildInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR };
|
||||||
VkAccelerationStructureGeometryKHR accelStructTLDesc = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR };
|
VkAccelerationStructureGeometryKHR accelStructTLDesc = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR };
|
||||||
|
@ -409,7 +414,7 @@ void VkLevelMesh::UpdateTopLevelAS()
|
||||||
|
|
||||||
VkAccelerationStructureBuildRangeInfoKHR rangeInfo = {};
|
VkAccelerationStructureBuildRangeInfoKHR rangeInfo = {};
|
||||||
VkAccelerationStructureBuildRangeInfoKHR* rangeInfos[] = { &rangeInfo };
|
VkAccelerationStructureBuildRangeInfoKHR* rangeInfos[] = { &rangeInfo };
|
||||||
rangeInfo.primitiveCount = 2;
|
rangeInfo.primitiveCount = instanceCount;
|
||||||
|
|
||||||
fb->GetCommands()->GetTransferCommands()->buildAccelerationStructures(1, &buildInfo, rangeInfos);
|
fb->GetCommands()->GetTransferCommands()->buildAccelerationStructures(1, &buildInfo, rangeInfos);
|
||||||
}
|
}
|
||||||
|
@ -424,12 +429,15 @@ void VkLevelMesh::UploadTLASInstanceBuffer()
|
||||||
instances[0].flags = 0;
|
instances[0].flags = 0;
|
||||||
instances[0].accelerationStructureReference = StaticBLAS.AccelStruct->GetDeviceAddress();
|
instances[0].accelerationStructureReference = StaticBLAS.AccelStruct->GetDeviceAddress();
|
||||||
|
|
||||||
instances[1].transform.matrix[0][0] = 1.0f;
|
if (DynamicBLAS.AccelStruct)
|
||||||
instances[1].transform.matrix[1][1] = 1.0f;
|
{
|
||||||
instances[1].transform.matrix[2][2] = 1.0f;
|
instances[1].transform.matrix[0][0] = 1.0f;
|
||||||
instances[1].mask = 0xff;
|
instances[1].transform.matrix[1][1] = 1.0f;
|
||||||
instances[1].flags = 0;
|
instances[1].transform.matrix[2][2] = 1.0f;
|
||||||
instances[1].accelerationStructureReference = DynamicBLAS.AccelStruct->GetDeviceAddress();
|
instances[1].mask = 0xff;
|
||||||
|
instances[1].flags = 0;
|
||||||
|
instances[1].accelerationStructureReference = DynamicBLAS.AccelStruct->GetDeviceAddress();
|
||||||
|
}
|
||||||
|
|
||||||
auto data = (uint8_t*)TopLevelAS.TransferBuffer->Map(0, sizeof(VkAccelerationStructureInstanceKHR) * 2);
|
auto data = (uint8_t*)TopLevelAS.TransferBuffer->Map(0, sizeof(VkAccelerationStructureInstanceKHR) * 2);
|
||||||
memcpy(data, instances, sizeof(VkAccelerationStructureInstanceKHR) * 2);
|
memcpy(data, instances, sizeof(VkAccelerationStructureInstanceKHR) * 2);
|
||||||
|
@ -444,30 +452,44 @@ VkLevelMeshUploader::VkLevelMeshUploader(VkLevelMesh* mesh) : Mesh(mesh)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkLevelMeshUploader::Upload(bool dynamicOnly)
|
void VkLevelMeshUploader::Upload()
|
||||||
{
|
{
|
||||||
UpdateSizes();
|
|
||||||
UpdateLocations();
|
|
||||||
|
|
||||||
start = dynamicOnly;
|
|
||||||
end = locations.Size();
|
|
||||||
|
|
||||||
size_t transferBufferSize = GetTransferSize();
|
size_t transferBufferSize = GetTransferSize();
|
||||||
if (transferBufferSize == 0)
|
if (transferBufferSize == 0)
|
||||||
|
{
|
||||||
|
ClearRanges();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
BeginTransfer(transferBufferSize);
|
BeginTransfer(transferBufferSize);
|
||||||
|
|
||||||
UploadNodes();
|
UploadNodes();
|
||||||
UploadVertices();
|
UploadRanges(Mesh->Locations.Vertex, Mesh->Mesh->Mesh.Vertices.Data(), Mesh->VertexBuffer.get());
|
||||||
UploadUniformIndexes();
|
UploadRanges(Mesh->Locations.UniformIndexes, Mesh->Mesh->Mesh.UniformIndexes.Data(), Mesh->UniformIndexBuffer.get());
|
||||||
UploadIndexes();
|
UploadRanges(Mesh->Locations.Index, Mesh->Mesh->Mesh.Indexes.Data(), Mesh->IndexBuffer.get());
|
||||||
UploadSurfaceIndexes();
|
UploadRanges(Mesh->Locations.SurfaceIndex, Mesh->Mesh->Mesh.SurfaceIndexes.Data(), Mesh->SurfaceIndexBuffer.get());
|
||||||
|
UploadRanges(Mesh->Locations.LightIndex, Mesh->Mesh->Mesh.LightIndexes.Data(), Mesh->LightIndexBuffer.get());
|
||||||
UploadSurfaces();
|
UploadSurfaces();
|
||||||
UploadUniforms();
|
UploadUniforms();
|
||||||
UploadPortals();
|
UploadPortals();
|
||||||
|
UploadLights();
|
||||||
|
|
||||||
EndTransfer(transferBufferSize);
|
EndTransfer(transferBufferSize);
|
||||||
|
ClearRanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkLevelMeshUploader::ClearRanges()
|
||||||
|
{
|
||||||
|
Mesh->Locations.Vertex.Clear();
|
||||||
|
Mesh->Locations.Index.Clear();
|
||||||
|
Mesh->Locations.Node.Clear();
|
||||||
|
Mesh->Locations.SurfaceIndex.Clear();
|
||||||
|
Mesh->Locations.Surface.Clear();
|
||||||
|
Mesh->Locations.UniformIndexes.Clear();
|
||||||
|
Mesh->Locations.Uniforms.Clear();
|
||||||
|
Mesh->Locations.Portals.Clear();
|
||||||
|
Mesh->Locations.Light.Clear();
|
||||||
|
Mesh->Locations.LightIndex.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkLevelMeshUploader::BeginTransfer(size_t transferBufferSize)
|
void VkLevelMeshUploader::BeginTransfer(size_t transferBufferSize)
|
||||||
|
@ -498,146 +520,63 @@ static FVector3 SwapYZ(const FVector3& v)
|
||||||
|
|
||||||
void VkLevelMeshUploader::UploadNodes()
|
void VkLevelMeshUploader::UploadNodes()
|
||||||
{
|
{
|
||||||
// Copy node buffer header and create a root node that merges the static and dynamic AABB trees
|
// Always update the header struct of the collision storage buffer block if something changed
|
||||||
if (locations[1].Submesh->Collision->get_root() != -1)
|
if (Mesh->Locations.Node.Size() > 0)
|
||||||
{
|
|
||||||
int root0 = locations[0].Submesh->Collision->get_root();
|
|
||||||
int root1 = locations[1].Submesh->Collision->get_root();
|
|
||||||
const auto& node0 = locations[0].Submesh->Collision->get_nodes()[root0];
|
|
||||||
const auto& node1 = locations[1].Submesh->Collision->get_nodes()[root1];
|
|
||||||
|
|
||||||
FVector3 aabbMin(std::min(node0.aabb.min.X, node1.aabb.min.X), std::min(node0.aabb.min.Y, node1.aabb.min.Y), std::min(node0.aabb.min.Z, node1.aabb.min.Z));
|
|
||||||
FVector3 aabbMax(std::max(node0.aabb.max.X, node1.aabb.max.X), std::max(node0.aabb.max.Y, node1.aabb.max.Y), std::max(node0.aabb.max.Z, node1.aabb.max.Z));
|
|
||||||
CollisionBBox bbox(aabbMin, aabbMax);
|
|
||||||
|
|
||||||
CollisionNodeBufferHeader nodesHeader;
|
|
||||||
nodesHeader.root = locations[1].Node.Offset + locations[1].Node.Size;
|
|
||||||
|
|
||||||
CollisionNode info;
|
|
||||||
info.center = SwapYZ(bbox.Center);
|
|
||||||
info.extents = SwapYZ(bbox.Extents);
|
|
||||||
info.left = locations[0].Node.Offset + root0;
|
|
||||||
info.right = locations[1].Node.Offset + root1;
|
|
||||||
info.element_index = -1;
|
|
||||||
|
|
||||||
*((CollisionNodeBufferHeader*)(data + datapos)) = nodesHeader;
|
|
||||||
*((CollisionNode*)(data + datapos + sizeof(CollisionNodeBufferHeader))) = info;
|
|
||||||
|
|
||||||
cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->NodeBuffer.get(), datapos, 0, sizeof(CollisionNodeBufferHeader));
|
|
||||||
cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->NodeBuffer.get(), datapos + sizeof(CollisionNodeBufferHeader), sizeof(CollisionNodeBufferHeader) + nodesHeader.root * sizeof(CollisionNode), sizeof(CollisionNode));
|
|
||||||
}
|
|
||||||
else // second submesh is empty, just point the header at the first one
|
|
||||||
{
|
{
|
||||||
CollisionNodeBufferHeader nodesHeader;
|
CollisionNodeBufferHeader nodesHeader;
|
||||||
nodesHeader.root = locations[0].Submesh->Collision->get_root();
|
nodesHeader.root = Mesh->Mesh->Collision->get_root();
|
||||||
|
|
||||||
*((CollisionNodeBufferHeader*)(data + datapos)) = nodesHeader;
|
*((CollisionNodeBufferHeader*)(data + datapos)) = nodesHeader;
|
||||||
cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->NodeBuffer.get(), datapos, 0, sizeof(CollisionNodeBufferHeader));
|
cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->NodeBuffer.get(), datapos, 0, sizeof(CollisionNodeBufferHeader));
|
||||||
|
|
||||||
|
datapos += sizeof(CollisionNodeBufferHeader) + sizeof(CollisionNode);
|
||||||
}
|
}
|
||||||
datapos += sizeof(CollisionNodeBufferHeader) + sizeof(CollisionNode);
|
|
||||||
|
|
||||||
// Copy collision nodes
|
// Copy collision nodes
|
||||||
for (unsigned int i = start; i < end; i++)
|
for (const MeshBufferRange& range : Mesh->Locations.Node)
|
||||||
{
|
{
|
||||||
const SubmeshBufferLocation& cur = locations[i];
|
const auto& srcnodes = Mesh->Mesh->Collision->get_nodes();
|
||||||
auto submesh = cur.Submesh;
|
|
||||||
|
|
||||||
CollisionNode* nodes = (CollisionNode*)(data + datapos);
|
CollisionNode* nodes = (CollisionNode*)(data + datapos);
|
||||||
for (auto& node : submesh->Collision->get_nodes())
|
for (int i = 0, count = range.Size; i < count; i++)
|
||||||
{
|
{
|
||||||
|
const auto& node = srcnodes[range.Offset + i];
|
||||||
CollisionNode info;
|
CollisionNode info;
|
||||||
info.center = SwapYZ(node.aabb.Center);
|
info.center = SwapYZ(node.aabb.Center);
|
||||||
info.extents = SwapYZ(node.aabb.Extents);
|
info.extents = SwapYZ(node.aabb.Extents);
|
||||||
info.left = node.left != -1 ? node.left + cur.Node.Offset : -1;
|
info.left = node.left;
|
||||||
info.right = node.right != -1 ? node.right + cur.Node.Offset : -1;
|
info.right = node.right;
|
||||||
info.element_index = node.element_index != -1 ? node.element_index + cur.Index.Offset : -1;
|
info.element_index = node.element_index;
|
||||||
*(nodes++) = info;
|
*(nodes++) = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t copysize = submesh->Collision->get_nodes().size() * sizeof(CollisionNode);
|
size_t copysize = range.Size * sizeof(CollisionNode);
|
||||||
if (copysize > 0)
|
if (copysize > 0)
|
||||||
cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->NodeBuffer.get(), datapos, sizeof(CollisionNodeBufferHeader) + cur.Node.Offset * sizeof(CollisionNode), copysize);
|
cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->NodeBuffer.get(), datapos, sizeof(CollisionNodeBufferHeader) + range.Offset * sizeof(CollisionNode), copysize);
|
||||||
datapos += copysize;
|
datapos += copysize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkLevelMeshUploader::UploadVertices()
|
template<typename T>
|
||||||
|
void VkLevelMeshUploader::UploadRanges(const TArray<MeshBufferRange>& ranges, const T* srcbuffer, VulkanBuffer* destbuffer)
|
||||||
{
|
{
|
||||||
for (unsigned int i = start; i < end; i++)
|
for (const MeshBufferRange& range : ranges)
|
||||||
{
|
{
|
||||||
const SubmeshBufferLocation& cur = locations[i];
|
size_t copysize = range.Size * sizeof(T);
|
||||||
auto submesh = cur.Submesh;
|
memcpy(data + datapos, srcbuffer + range.Offset, copysize);
|
||||||
|
|
||||||
size_t copysize = submesh->Mesh.Vertices.Size() * sizeof(FFlatVertex);
|
|
||||||
memcpy(data + datapos, submesh->Mesh.Vertices.Data(), copysize);
|
|
||||||
if (copysize > 0)
|
if (copysize > 0)
|
||||||
cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->VertexBuffer.get(), datapos, cur.Vertex.Offset * sizeof(FFlatVertex), copysize);
|
cmdbuffer->copyBuffer(transferBuffer.get(), destbuffer, datapos, range.Offset * sizeof(T), copysize);
|
||||||
datapos += copysize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VkLevelMeshUploader::UploadUniformIndexes()
|
|
||||||
{
|
|
||||||
for (unsigned int i = start; i < end; i++)
|
|
||||||
{
|
|
||||||
const SubmeshBufferLocation& cur = locations[i];
|
|
||||||
auto submesh = cur.Submesh;
|
|
||||||
|
|
||||||
size_t copysize = submesh->Mesh.UniformIndexes.Size() * sizeof(int);
|
|
||||||
memcpy(data + datapos, submesh->Mesh.UniformIndexes.Data(), copysize);
|
|
||||||
if (copysize > 0)
|
|
||||||
cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->UniformIndexBuffer.get(), datapos, cur.UniformIndexes.Offset * sizeof(int), copysize);
|
|
||||||
datapos += copysize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VkLevelMeshUploader::UploadIndexes()
|
|
||||||
{
|
|
||||||
for (unsigned int i = start; i < end; i++)
|
|
||||||
{
|
|
||||||
const SubmeshBufferLocation& cur = locations[i];
|
|
||||||
auto submesh = cur.Submesh;
|
|
||||||
|
|
||||||
uint32_t* indexes = (uint32_t*)(data + datapos);
|
|
||||||
for (int j = 0, count = submesh->Mesh.Indexes.Size(); j < count; ++j)
|
|
||||||
*(indexes++) = cur.Vertex.Offset + submesh->Mesh.Indexes[j];
|
|
||||||
|
|
||||||
size_t copysize = submesh->Mesh.Indexes.Size() * sizeof(uint32_t);
|
|
||||||
if (copysize > 0)
|
|
||||||
cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->IndexBuffer.get(), datapos, cur.Index.Offset * sizeof(uint32_t), copysize);
|
|
||||||
datapos += copysize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VkLevelMeshUploader::UploadSurfaceIndexes()
|
|
||||||
{
|
|
||||||
for (unsigned int i = start; i < end; i++)
|
|
||||||
{
|
|
||||||
const SubmeshBufferLocation& cur = locations[i];
|
|
||||||
auto submesh = cur.Submesh;
|
|
||||||
|
|
||||||
int* indexes = (int*)(data + datapos);
|
|
||||||
for (int j = 0, count = submesh->Mesh.SurfaceIndexes.Size(); j < count; ++j)
|
|
||||||
*(indexes++) = cur.SurfaceIndex.Offset + submesh->Mesh.SurfaceIndexes[j];
|
|
||||||
|
|
||||||
size_t copysize = submesh->Mesh.SurfaceIndexes.Size() * sizeof(int);
|
|
||||||
if (copysize > 0)
|
|
||||||
cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->SurfaceIndexBuffer.get(), datapos, cur.SurfaceIndex.Offset * sizeof(int), copysize);
|
|
||||||
datapos += copysize;
|
datapos += copysize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkLevelMeshUploader::UploadSurfaces()
|
void VkLevelMeshUploader::UploadSurfaces()
|
||||||
{
|
{
|
||||||
for (unsigned int i = start; i < end; i++)
|
for (const MeshBufferRange& range : Mesh->Locations.Surface)
|
||||||
{
|
{
|
||||||
const SubmeshBufferLocation& cur = locations[i];
|
|
||||||
auto submesh = cur.Submesh;
|
|
||||||
|
|
||||||
SurfaceInfo* surfaces = (SurfaceInfo*)(data + datapos);
|
SurfaceInfo* surfaces = (SurfaceInfo*)(data + datapos);
|
||||||
for (int j = 0, count = submesh->GetSurfaceCount(); j < count; ++j)
|
for (int j = 0, count = range.Size; j < count; j++)
|
||||||
{
|
{
|
||||||
LevelMeshSurface* surface = submesh->GetSurface(j);
|
LevelMeshSurface* surface = Mesh->Mesh->GetSurface(range.Offset + j);
|
||||||
|
|
||||||
SurfaceInfo info;
|
SurfaceInfo info;
|
||||||
info.Normal = FVector3(surface->Plane.X, surface->Plane.Z, surface->Plane.Y);
|
info.Normal = FVector3(surface->Plane.X, surface->Plane.Z, surface->Plane.Y);
|
||||||
|
@ -646,144 +585,115 @@ void VkLevelMeshUploader::UploadSurfaces()
|
||||||
info.Alpha = surface->Alpha;
|
info.Alpha = surface->Alpha;
|
||||||
if (surface->Texture.isValid())
|
if (surface->Texture.isValid())
|
||||||
{
|
{
|
||||||
#ifdef NEEDS_PORTING
|
info.TextureIndex = Mesh->fb->GetBindlessTextureIndex(surface->Texture);
|
||||||
auto mat = FMaterial::ValidateTexture(surface->Texture, 0);
|
|
||||||
info.TextureIndex = Mesh->fb->GetBindlessTextureIndex(mat, CLAMP_NONE, 0);
|
|
||||||
#else
|
|
||||||
info.TextureIndex = 0;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
info.TextureIndex = 0;
|
info.TextureIndex = 0;
|
||||||
}
|
}
|
||||||
|
info.LightStart = surface->LightList.Pos;
|
||||||
|
info.LightEnd = surface->LightList.Pos + surface->LightList.Count;
|
||||||
|
|
||||||
*(surfaces++) = info;
|
*(surfaces++) = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t copysize = submesh->GetSurfaceCount() * sizeof(SurfaceInfo);
|
size_t copysize = range.Size * sizeof(SurfaceInfo);
|
||||||
if (copysize > 0)
|
if (copysize > 0)
|
||||||
cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->SurfaceBuffer.get(), datapos, cur.Surface.Offset * sizeof(SurfaceInfo), copysize);
|
cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->SurfaceBuffer.get(), datapos, range.Offset * sizeof(SurfaceInfo), copysize);
|
||||||
datapos += copysize;
|
datapos += copysize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkLevelMeshUploader::UploadUniforms()
|
void VkLevelMeshUploader::UploadUniforms()
|
||||||
{
|
{
|
||||||
for (unsigned int i = start; i < end; i++)
|
for (const MeshBufferRange& range : Mesh->Locations.Uniforms)
|
||||||
{
|
{
|
||||||
const SubmeshBufferLocation& cur = locations[i];
|
for (int j = 0, count = range.Size; j < count; j++)
|
||||||
auto submesh = cur.Submesh;
|
|
||||||
|
|
||||||
for (int j = 0, count = submesh->Mesh.Uniforms.Size(); j < count; j++)
|
|
||||||
{
|
{
|
||||||
auto& surfaceUniforms = submesh->Mesh.Uniforms[j];
|
auto& surfaceUniforms = Mesh->Mesh->Mesh.Uniforms[range.Offset + j];
|
||||||
auto& material = submesh->Mesh.Materials[j];
|
auto& material = Mesh->Mesh->Mesh.Materials[range.Offset + j];
|
||||||
if (material.mMaterial)
|
/*if (material.mMaterial)
|
||||||
{
|
{
|
||||||
#ifdef NEEDS_PORTING
|
|
||||||
auto source = material.mMaterial->Source();
|
auto source = material.mMaterial->Source();
|
||||||
surfaceUniforms.uSpecularMaterial = { source->GetGlossiness(), source->GetSpecularLevel() };
|
surfaceUniforms.uSpecularMaterial = { source->GetGlossiness(), source->GetSpecularLevel() };
|
||||||
surfaceUniforms.uTextureIndex = Mesh->fb->GetBindlessTextureIndex(material.mMaterial, material.mClampMode, material.mTranslation);
|
surfaceUniforms.uTextureIndex = Mesh->fb->GetBindlessTextureIndex(material.mMaterial, material.mClampMode, material.mTranslation);
|
||||||
#else
|
|
||||||
surfaceUniforms.uTextureIndex = 0;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else*/
|
||||||
{
|
{
|
||||||
surfaceUniforms.uTextureIndex = 0;
|
surfaceUniforms.uTextureIndex = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SurfaceUniforms* uniforms = (SurfaceUniforms*)(data + datapos);
|
SurfaceUniforms* uniforms = (SurfaceUniforms*)(data + datapos);
|
||||||
size_t copysize = submesh->Mesh.Uniforms.Size() * sizeof(SurfaceUniforms);
|
size_t copysize = range.Size * sizeof(SurfaceUniforms);
|
||||||
memcpy(uniforms, submesh->Mesh.Uniforms.Data(), copysize);
|
memcpy(uniforms, Mesh->Mesh->Mesh.Uniforms.Data(), copysize);
|
||||||
if (copysize > 0)
|
if (copysize > 0)
|
||||||
cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->UniformsBuffer.get(), datapos, cur.Uniforms.Offset * sizeof(SurfaceUniforms), copysize);
|
cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->UniformsBuffer.get(), datapos, range.Offset * sizeof(SurfaceUniforms), copysize);
|
||||||
datapos += copysize;
|
datapos += copysize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkLevelMeshUploader::UploadPortals()
|
void VkLevelMeshUploader::UploadPortals()
|
||||||
{
|
{
|
||||||
if (start == 0)
|
for (const MeshBufferRange& range : Mesh->Locations.Portals)
|
||||||
{
|
{
|
||||||
PortalInfo* portals = (PortalInfo*)(data + datapos);
|
PortalInfo* portals = (PortalInfo*)(data + datapos);
|
||||||
for (auto& portal : Mesh->Mesh->Portals)
|
for (int i = 0, count = range.Size; i < count; i++)
|
||||||
{
|
{
|
||||||
|
const auto& portal = Mesh->Mesh->Portals[range.Offset + i];
|
||||||
PortalInfo info;
|
PortalInfo info;
|
||||||
info.transformation = portal.transformation;
|
info.transformation = portal.transformation;
|
||||||
*(portals++) = info;
|
*(portals++) = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t copysize = Mesh->Mesh->Portals.Size() * sizeof(PortalInfo);
|
size_t copysize = range.Size * sizeof(PortalInfo);
|
||||||
if (copysize > 0)
|
if (copysize > 0)
|
||||||
cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->PortalBuffer.get(), datapos, 0, copysize);
|
cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->PortalBuffer.get(), datapos, range.Offset * sizeof(PortalInfo), copysize);
|
||||||
datapos += copysize;
|
datapos += copysize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkLevelMeshUploader::UpdateSizes()
|
void VkLevelMeshUploader::UploadLights()
|
||||||
{
|
{
|
||||||
for (LevelSubmesh* submesh : { Mesh->GetMesh()->StaticMesh.get(), Mesh->GetMesh()->DynamicMesh.get() })
|
for (const MeshBufferRange& range : Mesh->Locations.Light)
|
||||||
{
|
{
|
||||||
SubmeshBufferLocation location;
|
LightInfo* lights = (LightInfo*)(data + datapos);
|
||||||
location.Submesh = submesh;
|
for (int i = 0, count = range.Size; i < count; i++)
|
||||||
location.Vertex.Size = submesh->Mesh.Vertices.Size();
|
|
||||||
location.Index.Size = submesh->Mesh.Indexes.Size();
|
|
||||||
location.Node.Size = (int)submesh->Collision->get_nodes().size();
|
|
||||||
location.SurfaceIndex.Size = submesh->Mesh.SurfaceIndexes.Size();
|
|
||||||
location.Surface.Size = submesh->GetSurfaceCount();
|
|
||||||
location.UniformIndexes.Size = submesh->Mesh.UniformIndexes.Size();
|
|
||||||
location.Uniforms.Size = submesh->Mesh.Uniforms.Size();
|
|
||||||
locations.Push(location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VkLevelMeshUploader::UpdateLocations()
|
|
||||||
{
|
|
||||||
for (unsigned int i = 1, count = locations.Size(); i < count; i++)
|
|
||||||
{
|
|
||||||
const SubmeshBufferLocation& prev = locations[i - 1];
|
|
||||||
SubmeshBufferLocation& cur = locations[i];
|
|
||||||
cur.Vertex.Offset = prev.Vertex.Offset + prev.Vertex.Size;
|
|
||||||
cur.Index.Offset = prev.Index.Offset + prev.Index.Size;
|
|
||||||
cur.Node.Offset = prev.Node.Offset + prev.Node.Size;
|
|
||||||
cur.SurfaceIndex.Offset = prev.SurfaceIndex.Offset + prev.SurfaceIndex.Size;
|
|
||||||
cur.Surface.Offset = prev.Surface.Offset + prev.Surface.Size;
|
|
||||||
cur.UniformIndexes.Offset = prev.UniformIndexes.Offset + prev.UniformIndexes.Size;
|
|
||||||
cur.Uniforms.Offset = prev.Uniforms.Offset + prev.Uniforms.Size;
|
|
||||||
|
|
||||||
if (
|
|
||||||
cur.Vertex.Offset + cur.Vertex.Size > Mesh->GetMaxVertexBufferSize() ||
|
|
||||||
cur.Index.Offset + cur.Index.Size > Mesh->GetMaxIndexBufferSize() ||
|
|
||||||
cur.Node.Offset + cur.Node.Size > Mesh->GetMaxNodeBufferSize() ||
|
|
||||||
cur.SurfaceIndex.Offset + cur.SurfaceIndex.Size > Mesh->GetMaxSurfaceIndexBufferSize() ||
|
|
||||||
cur.Surface.Offset + cur.Surface.Size > Mesh->GetMaxSurfaceBufferSize() ||
|
|
||||||
cur.UniformIndexes.Offset + cur.UniformIndexes.Size > Mesh->GetMaxVertexBufferSize() ||
|
|
||||||
cur.Uniforms.Offset + cur.Uniforms.Size > Mesh->GetMaxUniformsBufferSize())
|
|
||||||
{
|
{
|
||||||
I_FatalError("Dynamic accel struct buffers are too small!");
|
const auto& light = Mesh->Mesh->Mesh.Lights[range.Offset + i];
|
||||||
|
LightInfo info;
|
||||||
|
info.Origin = SwapYZ(light.Origin);
|
||||||
|
info.RelativeOrigin = SwapYZ(light.RelativeOrigin);
|
||||||
|
info.Radius = light.Radius;
|
||||||
|
info.Intensity = light.Intensity;
|
||||||
|
info.InnerAngleCos = light.InnerAngleCos;
|
||||||
|
info.OuterAngleCos = light.OuterAngleCos;
|
||||||
|
info.SpotDir = SwapYZ(light.SpotDir);
|
||||||
|
info.Color = light.Color;
|
||||||
|
*(lights++) = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t copysize = range.Size * sizeof(LightInfo);
|
||||||
|
if (copysize > 0)
|
||||||
|
cmdbuffer->copyBuffer(transferBuffer.get(), Mesh->LightBuffer.get(), datapos, range.Offset * sizeof(LightInfo), copysize);
|
||||||
|
datapos += copysize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t VkLevelMeshUploader::GetTransferSize()
|
size_t VkLevelMeshUploader::GetTransferSize()
|
||||||
{
|
{
|
||||||
// Figure out how much memory we need to transfer it to the GPU
|
// Figure out how much memory we need to transfer it to the GPU
|
||||||
size_t transferBufferSize = sizeof(CollisionNodeBufferHeader) + sizeof(CollisionNode);
|
size_t transferBufferSize = 0;
|
||||||
for (unsigned int i = start; i < end; i++)
|
if (Mesh->Locations.Node.Size() > 0) transferBufferSize += sizeof(CollisionNodeBufferHeader) + sizeof(CollisionNode);
|
||||||
{
|
for (const MeshBufferRange& range : Mesh->Locations.Node) transferBufferSize += range.Size * sizeof(CollisionNode);
|
||||||
const SubmeshBufferLocation& cur = locations[i];
|
for (const MeshBufferRange& range : Mesh->Locations.Vertex) transferBufferSize += range.Size * sizeof(FFlatVertex);
|
||||||
transferBufferSize += cur.Submesh->Mesh.Vertices.Size() * sizeof(FFlatVertex);
|
for (const MeshBufferRange& range : Mesh->Locations.UniformIndexes) transferBufferSize += range.Size * sizeof(int);
|
||||||
transferBufferSize += cur.Submesh->Mesh.UniformIndexes.Size() * sizeof(int);
|
for (const MeshBufferRange& range : Mesh->Locations.Index) transferBufferSize += range.Size * sizeof(uint32_t);
|
||||||
transferBufferSize += cur.Submesh->Mesh.Indexes.Size() * sizeof(uint32_t);
|
for (const MeshBufferRange& range : Mesh->Locations.SurfaceIndex) transferBufferSize += range.Size * sizeof(int);
|
||||||
transferBufferSize += cur.Submesh->Collision->get_nodes().size() * sizeof(CollisionNode);
|
for (const MeshBufferRange& range : Mesh->Locations.Surface) transferBufferSize += range.Size * sizeof(SurfaceInfo);
|
||||||
transferBufferSize += cur.Submesh->Mesh.SurfaceIndexes.Size() * sizeof(int);
|
for (const MeshBufferRange& range : Mesh->Locations.Uniforms) transferBufferSize += range.Size * sizeof(SurfaceUniforms);
|
||||||
transferBufferSize += cur.Submesh->GetSurfaceCount() * sizeof(SurfaceInfo);
|
for (const MeshBufferRange& range : Mesh->Locations.Portals) transferBufferSize += range.Size * sizeof(PortalInfo);
|
||||||
transferBufferSize += cur.Submesh->Mesh.Uniforms.Size() * sizeof(SurfaceUniforms);
|
for (const MeshBufferRange& range : Mesh->Locations.LightIndex) transferBufferSize += range.Size * sizeof(int32_t);
|
||||||
}
|
for (const MeshBufferRange& range : Mesh->Locations.Light) transferBufferSize += range.Size * sizeof(LightInfo);
|
||||||
if (start == 0)
|
|
||||||
transferBufferSize += Mesh->GetMesh()->Portals.Size() * sizeof(PortalInfo);
|
|
||||||
return transferBufferSize;
|
return transferBufferSize;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,11 @@ struct SurfaceInfo
|
||||||
uint32_t PortalIndex;
|
uint32_t PortalIndex;
|
||||||
int32_t TextureIndex;
|
int32_t TextureIndex;
|
||||||
float Alpha;
|
float Alpha;
|
||||||
float Padding;
|
float Padding0;
|
||||||
|
uint32_t LightStart;
|
||||||
|
uint32_t LightEnd;
|
||||||
|
uint32_t Padding1;
|
||||||
|
uint32_t Padding2;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PortalInfo
|
struct PortalInfo
|
||||||
|
@ -42,24 +46,30 @@ struct PortalInfo
|
||||||
VSMatrix transformation;
|
VSMatrix transformation;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SubmeshBufferRange
|
struct LightInfo
|
||||||
|
{
|
||||||
|
FVector3 Origin;
|
||||||
|
float Padding0;
|
||||||
|
FVector3 RelativeOrigin;
|
||||||
|
float Padding1;
|
||||||
|
float Radius;
|
||||||
|
float Intensity;
|
||||||
|
float InnerAngleCos;
|
||||||
|
float OuterAngleCos;
|
||||||
|
FVector3 SpotDir;
|
||||||
|
float Padding2;
|
||||||
|
FVector3 Color;
|
||||||
|
float Padding3;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(LightInfo) == sizeof(float) * 20);
|
||||||
|
|
||||||
|
struct MeshBufferRange
|
||||||
{
|
{
|
||||||
int Offset = 0;
|
int Offset = 0;
|
||||||
int Size = 0;
|
int Size = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SubmeshBufferLocation
|
|
||||||
{
|
|
||||||
LevelSubmesh* Submesh = nullptr;
|
|
||||||
SubmeshBufferRange Vertex;
|
|
||||||
SubmeshBufferRange Index;
|
|
||||||
SubmeshBufferRange Node;
|
|
||||||
SubmeshBufferRange SurfaceIndex;
|
|
||||||
SubmeshBufferRange Surface;
|
|
||||||
SubmeshBufferRange UniformIndexes;
|
|
||||||
SubmeshBufferRange Uniforms;
|
|
||||||
};
|
|
||||||
|
|
||||||
class VkLevelMesh
|
class VkLevelMesh
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -77,6 +87,8 @@ public:
|
||||||
VulkanBuffer* GetSurfaceBuffer() { return SurfaceBuffer.get(); }
|
VulkanBuffer* GetSurfaceBuffer() { return SurfaceBuffer.get(); }
|
||||||
VulkanBuffer* GetUniformsBuffer() { return UniformsBuffer.get(); }
|
VulkanBuffer* GetUniformsBuffer() { return UniformsBuffer.get(); }
|
||||||
VulkanBuffer* GetPortalBuffer() { return PortalBuffer.get(); }
|
VulkanBuffer* GetPortalBuffer() { return PortalBuffer.get(); }
|
||||||
|
VulkanBuffer* GetLightBuffer() { return LightBuffer.get(); }
|
||||||
|
VulkanBuffer* GetLightIndexBuffer() { return LightIndexBuffer.get(); }
|
||||||
|
|
||||||
LevelMesh* GetMesh() { return Mesh; }
|
LevelMesh* GetMesh() { return Mesh; }
|
||||||
|
|
||||||
|
@ -94,20 +106,13 @@ private:
|
||||||
void CreateStaticBLAS();
|
void CreateStaticBLAS();
|
||||||
void CreateDynamicBLAS();
|
void CreateDynamicBLAS();
|
||||||
void CreateTLASInstanceBuffer();
|
void CreateTLASInstanceBuffer();
|
||||||
void CreateTopLevelAS();
|
void CreateTopLevelAS(int instanceCount);
|
||||||
|
|
||||||
void UploadMeshes(bool dynamicOnly);
|
void UploadMeshes(bool dynamicOnly);
|
||||||
void UploadTLASInstanceBuffer();
|
void UploadTLASInstanceBuffer();
|
||||||
void UpdateTopLevelAS();
|
void UpdateTopLevelAS(int instanceCount);
|
||||||
|
|
||||||
BLAS CreateBLAS(LevelSubmesh *submesh, bool preferFastBuild, int vertexOffset, int indexOffset);
|
BLAS CreateBLAS(bool preferFastBuild, int indexOffset, int indexCount);
|
||||||
|
|
||||||
int GetMaxVertexBufferSize();
|
|
||||||
int GetMaxIndexBufferSize();
|
|
||||||
int GetMaxNodeBufferSize();
|
|
||||||
int GetMaxSurfaceBufferSize();
|
|
||||||
int GetMaxUniformsBufferSize();
|
|
||||||
int GetMaxSurfaceIndexBufferSize();
|
|
||||||
|
|
||||||
VulkanRenderDevice* fb = nullptr;
|
VulkanRenderDevice* fb = nullptr;
|
||||||
|
|
||||||
|
@ -116,6 +121,20 @@ private:
|
||||||
LevelMesh NullMesh;
|
LevelMesh NullMesh;
|
||||||
LevelMesh* Mesh = nullptr;
|
LevelMesh* Mesh = nullptr;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
TArray<MeshBufferRange> Vertex;
|
||||||
|
TArray<MeshBufferRange> Index;
|
||||||
|
TArray<MeshBufferRange> Node;
|
||||||
|
TArray<MeshBufferRange> SurfaceIndex;
|
||||||
|
TArray<MeshBufferRange> Surface;
|
||||||
|
TArray<MeshBufferRange> UniformIndexes;
|
||||||
|
TArray<MeshBufferRange> Uniforms;
|
||||||
|
TArray<MeshBufferRange> Portals;
|
||||||
|
TArray<MeshBufferRange> Light;
|
||||||
|
TArray<MeshBufferRange> LightIndex;
|
||||||
|
} Locations;
|
||||||
|
|
||||||
std::unique_ptr<VulkanBuffer> VertexBuffer;
|
std::unique_ptr<VulkanBuffer> VertexBuffer;
|
||||||
std::unique_ptr<VulkanBuffer> UniformIndexBuffer;
|
std::unique_ptr<VulkanBuffer> UniformIndexBuffer;
|
||||||
std::unique_ptr<VulkanBuffer> IndexBuffer;
|
std::unique_ptr<VulkanBuffer> IndexBuffer;
|
||||||
|
@ -123,17 +142,11 @@ private:
|
||||||
std::unique_ptr<VulkanBuffer> SurfaceBuffer;
|
std::unique_ptr<VulkanBuffer> SurfaceBuffer;
|
||||||
std::unique_ptr<VulkanBuffer> UniformsBuffer;
|
std::unique_ptr<VulkanBuffer> UniformsBuffer;
|
||||||
std::unique_ptr<VulkanBuffer> PortalBuffer;
|
std::unique_ptr<VulkanBuffer> PortalBuffer;
|
||||||
|
std::unique_ptr<VulkanBuffer> LightBuffer;
|
||||||
|
std::unique_ptr<VulkanBuffer> LightIndexBuffer;
|
||||||
|
|
||||||
std::unique_ptr<VulkanBuffer> NodeBuffer;
|
std::unique_ptr<VulkanBuffer> NodeBuffer;
|
||||||
|
|
||||||
TArray<FFlatVertex> Vertices;
|
|
||||||
static const int MaxDynamicVertices = 100'000;
|
|
||||||
static const int MaxDynamicIndexes = 100'000;
|
|
||||||
static const int MaxDynamicSurfaces = 100'000;
|
|
||||||
static const int MaxDynamicUniforms = 100'000;
|
|
||||||
static const int MaxDynamicSurfaceIndexes = 25'000;
|
|
||||||
static const int MaxDynamicNodes = 10'000;
|
|
||||||
|
|
||||||
BLAS StaticBLAS;
|
BLAS StaticBLAS;
|
||||||
BLAS DynamicBLAS;
|
BLAS DynamicBLAS;
|
||||||
|
|
||||||
|
@ -154,27 +167,24 @@ class VkLevelMeshUploader
|
||||||
public:
|
public:
|
||||||
VkLevelMeshUploader(VkLevelMesh* mesh);
|
VkLevelMeshUploader(VkLevelMesh* mesh);
|
||||||
|
|
||||||
void Upload(bool dynamicOnly);
|
void Upload();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void BeginTransfer(size_t transferBufferSize);
|
void BeginTransfer(size_t transferBufferSize);
|
||||||
void EndTransfer(size_t transferBufferSize);
|
void EndTransfer(size_t transferBufferSize);
|
||||||
|
size_t GetTransferSize();
|
||||||
|
void ClearRanges();
|
||||||
|
|
||||||
void UploadNodes();
|
void UploadNodes();
|
||||||
void UploadVertices();
|
|
||||||
void UploadUniformIndexes();
|
|
||||||
void UploadIndexes();
|
|
||||||
void UploadSurfaceIndexes();
|
|
||||||
void UploadSurfaces();
|
void UploadSurfaces();
|
||||||
void UploadUniforms();
|
void UploadUniforms();
|
||||||
void UploadPortals();
|
void UploadPortals();
|
||||||
void UpdateSizes();
|
void UploadLights();
|
||||||
void UpdateLocations();
|
|
||||||
size_t GetTransferSize();
|
|
||||||
|
|
||||||
VkLevelMesh* Mesh;
|
template<typename T>
|
||||||
TArray<SubmeshBufferLocation> locations;
|
void UploadRanges(const TArray<MeshBufferRange>& ranges, const T* srcbuffer, VulkanBuffer* destbuffer);
|
||||||
unsigned int start = 0;
|
|
||||||
unsigned int end = 0;
|
VkLevelMesh* Mesh = nullptr;
|
||||||
uint8_t* data = nullptr;
|
uint8_t* data = nullptr;
|
||||||
size_t datapos = 0;
|
size_t datapos = 0;
|
||||||
VulkanCommandBuffer* cmdbuffer = nullptr;
|
VulkanCommandBuffer* cmdbuffer = nullptr;
|
||||||
|
|
|
@ -12,8 +12,10 @@
|
||||||
#include "glsl/frag_copy.glsl.h"
|
#include "glsl/frag_copy.glsl.h"
|
||||||
#include "glsl/frag_raytrace.glsl.h"
|
#include "glsl/frag_raytrace.glsl.h"
|
||||||
#include "glsl/frag_resolve.glsl.h"
|
#include "glsl/frag_resolve.glsl.h"
|
||||||
|
#include "glsl/montecarlo.glsl.h"
|
||||||
#include "glsl/polyfill_rayquery.glsl.h"
|
#include "glsl/polyfill_rayquery.glsl.h"
|
||||||
#include "glsl/trace_ambient_occlusion.glsl.h"
|
#include "glsl/trace_ambient_occlusion.glsl.h"
|
||||||
|
#include "glsl/trace_bounce.glsl.h"
|
||||||
#include "glsl/trace_levelmesh.glsl.h"
|
#include "glsl/trace_levelmesh.glsl.h"
|
||||||
#include "glsl/trace_light.glsl.h"
|
#include "glsl/trace_light.glsl.h"
|
||||||
#include "glsl/trace_sunlight.glsl.h"
|
#include "glsl/trace_sunlight.glsl.h"
|
||||||
|
@ -29,17 +31,17 @@ bool lm_ao = true;
|
||||||
bool lm_softshadows = true;
|
bool lm_softshadows = true;
|
||||||
bool lm_sunlight = true;
|
bool lm_sunlight = true;
|
||||||
bool lm_blur = true;
|
bool lm_blur = true;
|
||||||
|
bool lm_bounce = true;
|
||||||
|
|
||||||
VkLightmapper::VkLightmapper(VulkanRenderDevice* fb) : fb(fb)
|
VkLightmapper::VkLightmapper(VulkanRenderDevice* fb) : fb(fb)
|
||||||
{
|
{
|
||||||
useRayQuery = fb->GetDevice()->SupportsExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME) && fb->GetDevice()->PhysicalDevice.Features.RayQuery.rayQuery;
|
useRayQuery = fb->IsRayQueryEnabled();
|
||||||
|
|
||||||
templightlist.Resize(128);
|
templightlist.Resize(128);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
CreateUniformBuffer();
|
CreateUniformBuffer();
|
||||||
CreateLightBuffer();
|
|
||||||
CreateTileBuffer();
|
CreateTileBuffer();
|
||||||
CreateDrawIndexedBuffer();
|
CreateDrawIndexedBuffer();
|
||||||
|
|
||||||
|
@ -64,8 +66,6 @@ VkLightmapper::~VkLightmapper()
|
||||||
|
|
||||||
void VkLightmapper::ReleaseResources()
|
void VkLightmapper::ReleaseResources()
|
||||||
{
|
{
|
||||||
if (lights.Buffer)
|
|
||||||
lights.Buffer->Unmap();
|
|
||||||
if (copytiles.Buffer)
|
if (copytiles.Buffer)
|
||||||
copytiles.Buffer->Unmap();
|
copytiles.Buffer->Unmap();
|
||||||
if (drawindexed.CommandsBuffer)
|
if (drawindexed.CommandsBuffer)
|
||||||
|
@ -82,8 +82,6 @@ void VkLightmapper::SetLevelMesh(LevelMesh* level)
|
||||||
|
|
||||||
void VkLightmapper::BeginFrame()
|
void VkLightmapper::BeginFrame()
|
||||||
{
|
{
|
||||||
lights.Pos = 0;
|
|
||||||
lights.ResetCounter++;
|
|
||||||
drawindexed.Pos = 0;
|
drawindexed.Pos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,8 +112,8 @@ void VkLightmapper::SelectTiles(const TArray<LightmapTile*>& tiles)
|
||||||
bakeImage.maxY = 0;
|
bakeImage.maxY = 0;
|
||||||
selectedTiles.Clear();
|
selectedTiles.Clear();
|
||||||
|
|
||||||
const int spacing = 5; // Note: the spacing is here to avoid that the resolve sampler finds data from other surface tiles
|
// We use a 3 texel spacing between rectangles so that the blur pass will not pick up anything from a neighbour tile.
|
||||||
RectPacker packer(bakeImageSize - spacing, bakeImageSize - spacing, RectPacker::Spacing(spacing));
|
RectPacker packer(bakeImageSize, bakeImageSize, RectPacker::Spacing(3), RectPacker::Padding(3));
|
||||||
|
|
||||||
for (int i = 0, count = tiles.Size(); i < count; i++)
|
for (int i = 0, count = tiles.Size(); i < count; i++)
|
||||||
{
|
{
|
||||||
|
@ -125,21 +123,25 @@ void VkLightmapper::SelectTiles(const TArray<LightmapTile*>& tiles)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Only grab surfaces until our bake texture is full
|
// Only grab surfaces until our bake texture is full
|
||||||
auto result = packer.insert(tile->AtlasLocation.Width + 2, tile->AtlasLocation.Height + 2);
|
auto result = packer.insert(tile->AtlasLocation.Width, tile->AtlasLocation.Height);
|
||||||
if (result.pageIndex == 0)
|
if (result.pageIndex == 0)
|
||||||
{
|
{
|
||||||
SelectedTile selected;
|
SelectedTile selected;
|
||||||
selected.Tile = tile;
|
selected.Tile = tile;
|
||||||
selected.X = result.pos.x + 1;
|
selected.X = result.pos.x;
|
||||||
selected.Y = result.pos.y + 1;
|
selected.Y = result.pos.y;
|
||||||
selectedTiles.Push(selected);
|
selectedTiles.Push(selected);
|
||||||
|
|
||||||
bakeImage.maxX = std::max<uint16_t>(bakeImage.maxX, uint16_t(selected.X + tile->AtlasLocation.Width + spacing));
|
bakeImage.maxX = std::max<uint16_t>(bakeImage.maxX, uint16_t(result.pos.x + tile->AtlasLocation.Width));
|
||||||
bakeImage.maxY = std::max<uint16_t>(bakeImage.maxY, uint16_t(selected.Y + tile->AtlasLocation.Height + spacing));
|
bakeImage.maxY = std::max<uint16_t>(bakeImage.maxY, uint16_t(result.pos.y + tile->AtlasLocation.Height));
|
||||||
|
|
||||||
tile->NeedsUpdate = false;
|
tile->NeedsUpdate = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Include the padding
|
||||||
|
bakeImage.maxX += 3;
|
||||||
|
bakeImage.maxY += 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkLightmapper::Render()
|
void VkLightmapper::Render()
|
||||||
|
@ -150,7 +152,7 @@ void VkLightmapper::Render()
|
||||||
|
|
||||||
RenderPassBegin()
|
RenderPassBegin()
|
||||||
.RenderPass(raytrace.renderPass.get())
|
.RenderPass(raytrace.renderPass.get())
|
||||||
.RenderArea(0, 0, bakeImageSize, bakeImageSize)
|
.RenderArea(0, 0, bakeImage.maxX, bakeImage.maxY)
|
||||||
.Framebuffer(bakeImage.raytrace.Framebuffer.get())
|
.Framebuffer(bakeImage.raytrace.Framebuffer.get())
|
||||||
.AddClearColor(0.0f, 0.0f, 0.0f, 0.0f)
|
.AddClearColor(0.0f, 0.0f, 0.0f, 0.0f)
|
||||||
.Execute(cmdbuffer);
|
.Execute(cmdbuffer);
|
||||||
|
@ -169,10 +171,6 @@ void VkLightmapper::Render()
|
||||||
viewport.height = (float)bakeImageSize;
|
viewport.height = (float)bakeImageSize;
|
||||||
cmdbuffer->setViewport(0, 1, &viewport);
|
cmdbuffer->setViewport(0, 1, &viewport);
|
||||||
|
|
||||||
int dynamicSurfaceIndexOffset = mesh->StaticMesh->GetSurfaceCount();
|
|
||||||
int dynamicFirstIndexOffset = mesh->StaticMesh->Mesh.Indexes.Size();
|
|
||||||
LevelSubmesh* staticMesh = mesh->StaticMesh.get();
|
|
||||||
|
|
||||||
for (int i = 0, count = selectedTiles.Size(); i < count; i++)
|
for (int i = 0, count = selectedTiles.Size(); i < count; i++)
|
||||||
{
|
{
|
||||||
auto& selectedTile = selectedTiles[i];
|
auto& selectedTile = selectedTiles[i];
|
||||||
|
@ -191,59 +189,15 @@ void VkLightmapper::Render()
|
||||||
bool buffersFull = false;
|
bool buffersFull = false;
|
||||||
|
|
||||||
// Paint all surfaces visible in the tile
|
// Paint all surfaces visible in the tile
|
||||||
for (LevelMeshSurface* surface : targetTile->Surfaces)
|
for (int surfaceIndex : targetTile->Surfaces)
|
||||||
{
|
{
|
||||||
int surfaceIndexOffset = 0;
|
LevelMeshSurface* surface = mesh->GetSurface(surfaceIndex);
|
||||||
int firstIndexOffset = 0;
|
pc.SurfaceIndex = surfaceIndex;
|
||||||
if (surface->Submesh != staticMesh)
|
|
||||||
{
|
|
||||||
surfaceIndexOffset = dynamicSurfaceIndexOffset;
|
|
||||||
firstIndexOffset = dynamicFirstIndexOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
pc.SurfaceIndex = surfaceIndexOffset + surface->Submesh->GetSurfaceIndex(surface);
|
|
||||||
|
|
||||||
if (surface->LightList.ResetCounter != lights.ResetCounter)
|
|
||||||
{
|
|
||||||
int lightCount = mesh->AddSurfaceLights(surface, templightlist.Data(), (int)templightlist.Size());
|
|
||||||
|
|
||||||
if (lights.Pos + lightCount > lights.BufferSize)
|
|
||||||
{
|
|
||||||
// Our light buffer is full. Postpone the rest.
|
|
||||||
buffersFull = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
surface->LightList.Pos = lights.Pos;
|
|
||||||
surface->LightList.Count = lightCount;
|
|
||||||
surface->LightList.ResetCounter = lights.ResetCounter;
|
|
||||||
|
|
||||||
LightInfo* lightinfo = &lights.Lights[lights.Pos];
|
|
||||||
for (int i = 0; i < lightCount; i++)
|
|
||||||
{
|
|
||||||
const LevelMeshLight* light = &templightlist[i];
|
|
||||||
lightinfo->Origin = SwapYZ(light->Origin);
|
|
||||||
lightinfo->RelativeOrigin = SwapYZ(light->RelativeOrigin);
|
|
||||||
lightinfo->Radius = light->Radius;
|
|
||||||
lightinfo->Intensity = light->Intensity;
|
|
||||||
lightinfo->InnerAngleCos = light->InnerAngleCos;
|
|
||||||
lightinfo->OuterAngleCos = light->OuterAngleCos;
|
|
||||||
lightinfo->SpotDir = SwapYZ(light->SpotDir);
|
|
||||||
lightinfo->Color = light->Color;
|
|
||||||
lightinfo++;
|
|
||||||
}
|
|
||||||
|
|
||||||
lights.Pos += lightCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
pc.LightStart = surface->LightList.Pos;
|
|
||||||
pc.LightEnd = pc.LightStart + surface->LightList.Count;
|
|
||||||
|
|
||||||
#ifdef USE_DRAWINDIRECT
|
|
||||||
VkDrawIndexedIndirectCommand cmd;
|
VkDrawIndexedIndirectCommand cmd;
|
||||||
cmd.indexCount = surface->MeshLocation.NumElements;
|
cmd.indexCount = surface->MeshLocation.NumElements;
|
||||||
cmd.instanceCount = 1;
|
cmd.instanceCount = 1;
|
||||||
cmd.firstIndex = firstIndexOffset + surface->MeshLocation.StartElementIndex;
|
cmd.firstIndex = surface->MeshLocation.StartElementIndex;
|
||||||
cmd.vertexOffset = 0;
|
cmd.vertexOffset = 0;
|
||||||
cmd.firstInstance = drawindexed.Pos;
|
cmd.firstInstance = drawindexed.Pos;
|
||||||
drawindexed.Constants[drawindexed.Pos] = pc;
|
drawindexed.Constants[drawindexed.Pos] = pc;
|
||||||
|
@ -256,10 +210,6 @@ void VkLightmapper::Render()
|
||||||
buffersFull = true;
|
buffersFull = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
cmdbuffer->pushConstants(raytrace.pipelineLayout.get(), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(LightmapRaytracePC), &pc);
|
|
||||||
cmdbuffer->drawIndexed(surface->numElements, 1, surface->startElementIndex, 0, 0);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffersFull)
|
if (buffersFull)
|
||||||
|
@ -275,9 +225,7 @@ void VkLightmapper::Render()
|
||||||
selectedTile.Rendered = true;
|
selectedTile.Rendered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_DRAWINDIRECT
|
|
||||||
cmdbuffer->drawIndexedIndirect(drawindexed.CommandsBuffer->buffer, 0, drawindexed.Pos, sizeof(VkDrawIndexedIndirectCommand));
|
cmdbuffer->drawIndexedIndirect(drawindexed.CommandsBuffer->buffer, 0, drawindexed.Pos, sizeof(VkDrawIndexedIndirectCommand));
|
||||||
#endif
|
|
||||||
|
|
||||||
cmdbuffer->endRenderPass();
|
cmdbuffer->endRenderPass();
|
||||||
|
|
||||||
|
@ -539,10 +487,6 @@ void VkLightmapper::CreateShaders()
|
||||||
traceprefix += "#extension GL_EXT_ray_query : require\r\n";
|
traceprefix += "#extension GL_EXT_ray_query : require\r\n";
|
||||||
traceprefix += "#define USE_RAYQUERY\r\n";
|
traceprefix += "#define USE_RAYQUERY\r\n";
|
||||||
}
|
}
|
||||||
#ifdef USE_DRAWINDIRECT
|
|
||||||
prefix += "#define USE_DRAWINDIRECT\r\n";
|
|
||||||
traceprefix += "#define USE_DRAWINDIRECT\r\n";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto onIncludeLocal = [](std::string headerName, std::string includerName, size_t depth) { return OnInclude(headerName.c_str(), includerName.c_str(), depth, false); };
|
auto onIncludeLocal = [](std::string headerName, std::string includerName, size_t depth) { return OnInclude(headerName.c_str(), includerName.c_str(), depth, false); };
|
||||||
auto onIncludeSystem = [](std::string headerName, std::string includerName, size_t depth) { return OnInclude(headerName.c_str(), includerName.c_str(), depth, true); };
|
auto onIncludeSystem = [](std::string headerName, std::string includerName, size_t depth) { return OnInclude(headerName.c_str(), includerName.c_str(), depth, true); };
|
||||||
|
@ -574,7 +518,7 @@ void VkLightmapper::CreateShaders()
|
||||||
.DebugName("VkLightmapper.VertCopy")
|
.DebugName("VkLightmapper.VertCopy")
|
||||||
.Create("VkLightmapper.VertCopy", fb->GetDevice());
|
.Create("VkLightmapper.VertCopy", fb->GetDevice());
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 16; i++)
|
||||||
{
|
{
|
||||||
std::string defines = traceprefix;
|
std::string defines = traceprefix;
|
||||||
if (i & 1)
|
if (i & 1)
|
||||||
|
@ -583,6 +527,8 @@ void VkLightmapper::CreateShaders()
|
||||||
defines += "#define USE_AO\n";
|
defines += "#define USE_AO\n";
|
||||||
if (i & 4)
|
if (i & 4)
|
||||||
defines += "#define USE_SUNLIGHT\n";
|
defines += "#define USE_SUNLIGHT\n";
|
||||||
|
if (i & 8)
|
||||||
|
defines += "#define USE_BOUNCE\n";
|
||||||
|
|
||||||
shaders.fragRaytrace[i] = ShaderBuilder()
|
shaders.fragRaytrace[i] = ShaderBuilder()
|
||||||
.Type(ShaderType::Fragment)
|
.Type(ShaderType::Fragment)
|
||||||
|
@ -640,6 +586,8 @@ int VkLightmapper::GetRaytracePipelineIndex()
|
||||||
index |= 2;
|
index |= 2;
|
||||||
if (lm_sunlight && mesh->SunColor != FVector3(0.0f, 0.0f, 0.0f))
|
if (lm_sunlight && mesh->SunColor != FVector3(0.0f, 0.0f, 0.0f))
|
||||||
index |= 4;
|
index |= 4;
|
||||||
|
if (lm_bounce)
|
||||||
|
index |= 8;
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,8 +602,10 @@ FString VkLightmapper::LoadPrivateShaderLump(const char* lumpname)
|
||||||
{ "shaders/lightmap/frag_copy.glsl", frag_copy_glsl },
|
{ "shaders/lightmap/frag_copy.glsl", frag_copy_glsl },
|
||||||
{ "shaders/lightmap/frag_raytrace.glsl", frag_raytrace_glsl },
|
{ "shaders/lightmap/frag_raytrace.glsl", frag_raytrace_glsl },
|
||||||
{ "shaders/lightmap/frag_resolve.glsl", frag_resolve_glsl },
|
{ "shaders/lightmap/frag_resolve.glsl", frag_resolve_glsl },
|
||||||
|
{ "shaders/lightmap/montecarlo.glsl", montecarlo_glsl },
|
||||||
{ "shaders/lightmap/polyfill_rayquery.glsl", polyfill_rayquery_glsl },
|
{ "shaders/lightmap/polyfill_rayquery.glsl", polyfill_rayquery_glsl },
|
||||||
{ "shaders/lightmap/trace_ambient_occlusion.glsl", trace_ambient_occlusion_glsl },
|
{ "shaders/lightmap/trace_ambient_occlusion.glsl", trace_ambient_occlusion_glsl },
|
||||||
|
{ "shaders/lightmap/trace_bounce.glsl", trace_bounce_glsl },
|
||||||
{ "shaders/lightmap/trace_levelmesh.glsl", trace_levelmesh_glsl },
|
{ "shaders/lightmap/trace_levelmesh.glsl", trace_levelmesh_glsl },
|
||||||
{ "shaders/lightmap/trace_light.glsl", trace_light_glsl },
|
{ "shaders/lightmap/trace_light.glsl", trace_light_glsl },
|
||||||
{ "shaders/lightmap/trace_sunlight.glsl", trace_sunlight_glsl },
|
{ "shaders/lightmap/trace_sunlight.glsl", trace_sunlight_glsl },
|
||||||
|
@ -710,9 +660,8 @@ void VkLightmapper::CreateRaytracePipeline()
|
||||||
.AddBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT)
|
.AddBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT)
|
||||||
.AddBinding(3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT)
|
.AddBinding(3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT)
|
||||||
.AddBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT)
|
.AddBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT)
|
||||||
#ifdef USE_DRAWINDIRECT
|
.AddBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT)
|
||||||
.AddBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT)
|
.AddBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT)
|
||||||
#endif
|
|
||||||
.DebugName("raytrace.descriptorSetLayout0")
|
.DebugName("raytrace.descriptorSetLayout0")
|
||||||
.Create(fb->GetDevice());
|
.Create(fb->GetDevice());
|
||||||
|
|
||||||
|
@ -739,9 +688,6 @@ void VkLightmapper::CreateRaytracePipeline()
|
||||||
.AddSetLayout(raytrace.descriptorSetLayout0.get())
|
.AddSetLayout(raytrace.descriptorSetLayout0.get())
|
||||||
.AddSetLayout(raytrace.descriptorSetLayout1.get())
|
.AddSetLayout(raytrace.descriptorSetLayout1.get())
|
||||||
.AddSetLayout(fb->GetDescriptorSetManager()->GetBindlessLayout())
|
.AddSetLayout(fb->GetDescriptorSetManager()->GetBindlessLayout())
|
||||||
#ifndef USE_DRAWINDIRECT
|
|
||||||
.AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(LightmapRaytracePC))
|
|
||||||
#endif
|
|
||||||
.DebugName("raytrace.pipelineLayout")
|
.DebugName("raytrace.pipelineLayout")
|
||||||
.Create(fb->GetDevice());
|
.Create(fb->GetDevice());
|
||||||
|
|
||||||
|
@ -763,7 +709,7 @@ void VkLightmapper::CreateRaytracePipeline()
|
||||||
.DebugName("raytrace.renderPass")
|
.DebugName("raytrace.renderPass")
|
||||||
.Create(fb->GetDevice());
|
.Create(fb->GetDevice());
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 16; i++)
|
||||||
{
|
{
|
||||||
raytrace.pipeline[i] = GraphicsPipelineBuilder()
|
raytrace.pipeline[i] = GraphicsPipelineBuilder()
|
||||||
.Layout(raytrace.pipelineLayout.get())
|
.Layout(raytrace.pipelineLayout.get())
|
||||||
|
@ -783,7 +729,7 @@ void VkLightmapper::CreateRaytracePipeline()
|
||||||
|
|
||||||
raytrace.descriptorPool0 = DescriptorPoolBuilder()
|
raytrace.descriptorPool0 = DescriptorPoolBuilder()
|
||||||
.AddPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1)
|
.AddPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1)
|
||||||
.AddPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 5)
|
.AddPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 6)
|
||||||
.MaxSets(1)
|
.MaxSets(1)
|
||||||
.DebugName("raytrace.descriptorPool0")
|
.DebugName("raytrace.descriptorPool0")
|
||||||
.Create(fb->GetDevice());
|
.Create(fb->GetDevice());
|
||||||
|
@ -836,11 +782,10 @@ void VkLightmapper::UpdateAccelStructDescriptors()
|
||||||
.AddBuffer(raytrace.descriptorSet0.get(), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uniforms.Buffer.get(), 0, sizeof(Uniforms))
|
.AddBuffer(raytrace.descriptorSet0.get(), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uniforms.Buffer.get(), 0, sizeof(Uniforms))
|
||||||
.AddBuffer(raytrace.descriptorSet0.get(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetSurfaceIndexBuffer())
|
.AddBuffer(raytrace.descriptorSet0.get(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetSurfaceIndexBuffer())
|
||||||
.AddBuffer(raytrace.descriptorSet0.get(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetSurfaceBuffer())
|
.AddBuffer(raytrace.descriptorSet0.get(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetSurfaceBuffer())
|
||||||
.AddBuffer(raytrace.descriptorSet0.get(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, lights.Buffer.get())
|
.AddBuffer(raytrace.descriptorSet0.get(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetLightBuffer())
|
||||||
.AddBuffer(raytrace.descriptorSet0.get(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetPortalBuffer())
|
.AddBuffer(raytrace.descriptorSet0.get(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetLightIndexBuffer())
|
||||||
#ifdef USE_DRAWINDIRECT
|
.AddBuffer(raytrace.descriptorSet0.get(), 5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetPortalBuffer())
|
||||||
.AddBuffer(raytrace.descriptorSet0.get(), 5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, drawindexed.ConstantsBuffer.get(), 0, drawindexed.BufferSize * sizeof(LightmapRaytracePC))
|
.AddBuffer(raytrace.descriptorSet0.get(), 6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, drawindexed.ConstantsBuffer.get(), 0, drawindexed.BufferSize * sizeof(LightmapRaytracePC))
|
||||||
#endif
|
|
||||||
.Execute(fb->GetDevice());
|
.Execute(fb->GetDevice());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -949,6 +894,9 @@ void VkLightmapper::CreateBlurPipeline()
|
||||||
.Create(fb->GetDevice());
|
.Create(fb->GetDevice());
|
||||||
|
|
||||||
blur.sampler = SamplerBuilder()
|
blur.sampler = SamplerBuilder()
|
||||||
|
.MinFilter(VK_FILTER_NEAREST)
|
||||||
|
.MagFilter(VK_FILTER_NEAREST)
|
||||||
|
.MipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST)
|
||||||
.DebugName("blur.Sampler")
|
.DebugName("blur.Sampler")
|
||||||
.Create(fb->GetDevice());
|
.Create(fb->GetDevice());
|
||||||
}
|
}
|
||||||
|
@ -1112,25 +1060,6 @@ void VkLightmapper::CreateUniformBuffer()
|
||||||
.Create(fb->GetDevice());
|
.Create(fb->GetDevice());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkLightmapper::CreateLightBuffer()
|
|
||||||
{
|
|
||||||
size_t size = sizeof(LightInfo) * lights.BufferSize;
|
|
||||||
|
|
||||||
lights.Buffer = BufferBuilder()
|
|
||||||
.Usage(
|
|
||||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
|
|
||||||
VMA_MEMORY_USAGE_UNKNOWN, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT)
|
|
||||||
.MemoryType(
|
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
|
|
||||||
.Size(size)
|
|
||||||
.DebugName("LightmapLightBuffer")
|
|
||||||
.Create(fb->GetDevice());
|
|
||||||
|
|
||||||
lights.Lights = (LightInfo*)lights.Buffer->Map(0, size);
|
|
||||||
lights.Pos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VkLightmapper::CreateTileBuffer()
|
void VkLightmapper::CreateTileBuffer()
|
||||||
{
|
{
|
||||||
size_t size = sizeof(CopyTileInfo) * copytiles.BufferSize;
|
size_t size = sizeof(CopyTileInfo) * copytiles.BufferSize;
|
||||||
|
|
|
@ -20,16 +20,16 @@ struct Uniforms
|
||||||
|
|
||||||
struct LightmapRaytracePC
|
struct LightmapRaytracePC
|
||||||
{
|
{
|
||||||
uint32_t LightStart;
|
|
||||||
uint32_t LightEnd;
|
|
||||||
int32_t SurfaceIndex;
|
int32_t SurfaceIndex;
|
||||||
int32_t PushPadding1;
|
int32_t Padding0;
|
||||||
|
int32_t Padding1;
|
||||||
|
int32_t Padding2;
|
||||||
FVector3 WorldToLocal;
|
FVector3 WorldToLocal;
|
||||||
float TextureSize;
|
float TextureSize;
|
||||||
FVector3 ProjLocalToU;
|
FVector3 ProjLocalToU;
|
||||||
float PushPadding2;
|
float Padding3;
|
||||||
FVector3 ProjLocalToV;
|
FVector3 ProjLocalToV;
|
||||||
float PushPadding3;
|
float Padding4;
|
||||||
float TileX;
|
float TileX;
|
||||||
float TileY;
|
float TileY;
|
||||||
float TileWidth;
|
float TileWidth;
|
||||||
|
@ -79,22 +79,6 @@ struct LightmapBakeImage
|
||||||
uint16_t maxY = 0;
|
uint16_t maxY = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LightInfo
|
|
||||||
{
|
|
||||||
FVector3 Origin;
|
|
||||||
float Padding0;
|
|
||||||
FVector3 RelativeOrigin;
|
|
||||||
float Padding1;
|
|
||||||
float Radius;
|
|
||||||
float Intensity;
|
|
||||||
float InnerAngleCos;
|
|
||||||
float OuterAngleCos;
|
|
||||||
FVector3 SpotDir;
|
|
||||||
float Padding2;
|
|
||||||
FVector3 Color;
|
|
||||||
float Padding3;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SelectedTile
|
struct SelectedTile
|
||||||
{
|
{
|
||||||
LightmapTile* Tile = nullptr;
|
LightmapTile* Tile = nullptr;
|
||||||
|
@ -103,8 +87,6 @@ struct SelectedTile
|
||||||
bool Rendered = false;
|
bool Rendered = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(LightInfo) == sizeof(float) * 20);
|
|
||||||
|
|
||||||
struct CopyTileInfo
|
struct CopyTileInfo
|
||||||
{
|
{
|
||||||
int SrcPosX;
|
int SrcPosX;
|
||||||
|
@ -147,7 +129,6 @@ private:
|
||||||
void CreateBlurPipeline();
|
void CreateBlurPipeline();
|
||||||
void CreateCopyPipeline();
|
void CreateCopyPipeline();
|
||||||
void CreateUniformBuffer();
|
void CreateUniformBuffer();
|
||||||
void CreateLightBuffer();
|
|
||||||
void CreateTileBuffer();
|
void CreateTileBuffer();
|
||||||
void CreateDrawIndexedBuffer();
|
void CreateDrawIndexedBuffer();
|
||||||
void CreateBakeImage();
|
void CreateBakeImage();
|
||||||
|
@ -180,15 +161,6 @@ private:
|
||||||
VkDeviceSize StructStride = sizeof(Uniforms);
|
VkDeviceSize StructStride = sizeof(Uniforms);
|
||||||
} uniforms;
|
} uniforms;
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
const int BufferSize = 2 * 1024 * 1024;
|
|
||||||
std::unique_ptr<VulkanBuffer> Buffer;
|
|
||||||
LightInfo* Lights = nullptr;
|
|
||||||
int Pos = 0;
|
|
||||||
int ResetCounter = 0;
|
|
||||||
} lights;
|
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
const int BufferSize = 100'000;
|
const int BufferSize = 100'000;
|
||||||
|
@ -211,7 +183,7 @@ private:
|
||||||
std::unique_ptr<VulkanShader> vertRaytrace;
|
std::unique_ptr<VulkanShader> vertRaytrace;
|
||||||
std::unique_ptr<VulkanShader> vertScreenquad;
|
std::unique_ptr<VulkanShader> vertScreenquad;
|
||||||
std::unique_ptr<VulkanShader> vertCopy;
|
std::unique_ptr<VulkanShader> vertCopy;
|
||||||
std::unique_ptr<VulkanShader> fragRaytrace[8];
|
std::unique_ptr<VulkanShader> fragRaytrace[16];
|
||||||
std::unique_ptr<VulkanShader> fragResolve;
|
std::unique_ptr<VulkanShader> fragResolve;
|
||||||
std::unique_ptr<VulkanShader> fragBlur[2];
|
std::unique_ptr<VulkanShader> fragBlur[2];
|
||||||
std::unique_ptr<VulkanShader> fragCopy;
|
std::unique_ptr<VulkanShader> fragCopy;
|
||||||
|
@ -222,7 +194,7 @@ private:
|
||||||
std::unique_ptr<VulkanDescriptorSetLayout> descriptorSetLayout0;
|
std::unique_ptr<VulkanDescriptorSetLayout> descriptorSetLayout0;
|
||||||
std::unique_ptr<VulkanDescriptorSetLayout> descriptorSetLayout1;
|
std::unique_ptr<VulkanDescriptorSetLayout> descriptorSetLayout1;
|
||||||
std::unique_ptr<VulkanPipelineLayout> pipelineLayout;
|
std::unique_ptr<VulkanPipelineLayout> pipelineLayout;
|
||||||
std::unique_ptr<VulkanPipeline> pipeline[8];
|
std::unique_ptr<VulkanPipeline> pipeline[16];
|
||||||
std::unique_ptr<VulkanRenderPass> renderPass;
|
std::unique_ptr<VulkanRenderPass> renderPass;
|
||||||
std::unique_ptr<VulkanDescriptorPool> descriptorPool0;
|
std::unique_ptr<VulkanDescriptorPool> descriptorPool0;
|
||||||
std::unique_ptr<VulkanDescriptorPool> descriptorPool1;
|
std::unique_ptr<VulkanDescriptorPool> descriptorPool1;
|
||||||
|
|
|
@ -25,7 +25,9 @@ public:
|
||||||
VkLevelMesh* GetLevelMesh() { return levelmesh.get(); }
|
VkLevelMesh* GetLevelMesh() { return levelmesh.get(); }
|
||||||
VkLightmapper* GetLightmapper() { return lightmapper.get(); }
|
VkLightmapper* GetLightmapper() { return lightmapper.get(); }
|
||||||
|
|
||||||
int GetBindlessTextureIndex(FTextureID texture) { return -1; }
|
int GetBindlessTextureIndex(FTextureID texture) { return 0; }
|
||||||
|
|
||||||
|
bool IsRayQueryEnabled() const { return useRayQuery; }
|
||||||
|
|
||||||
bool useRayQuery = false;
|
bool useRayQuery = false;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue