Merge pull request #51 from MrRaveYard/pr_portal_pointlights

Full Portal Light Support
This commit is contained in:
Magnus Norddahl 2022-10-31 14:52:25 +01:00 committed by GitHub
commit 001a936994
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 393 additions and 81 deletions

View file

@ -8,7 +8,7 @@ include( CheckCXXCompilerFlag )
project( ZDRay ) project( ZDRay )
SET( CMAKE_CXX_STANDARD 14 ) SET( CMAKE_CXX_STANDARD 17 )
IF( NOT CMAKE_BUILD_TYPE ) IF( NOT CMAKE_BUILD_TYPE )
SET( CMAKE_BUILD_TYPE Debug CACHE STRING SET( CMAKE_BUILD_TYPE Debug CACHE STRING
@ -196,6 +196,7 @@ set( SOURCES
src/lightmap/glsl_vert.h src/lightmap/glsl_vert.h
src/lightmap/glsl_frag_resolve.h src/lightmap/glsl_frag_resolve.h
src/lightmap/renderdoc_app.h src/lightmap/renderdoc_app.h
src/lightmap/portal.h
src/math/mat.cpp src/math/mat.cpp
src/math/plane.cpp src/math/plane.cpp
src/math/angle.cpp src/math/angle.cpp

View file

@ -7,6 +7,7 @@
#include "math/mathlib.h" #include "math/mathlib.h"
#include <memory> #include <memory>
#include <cmath> #include <cmath>
#include <optional>
#undef MIN #undef MIN
#undef MAX #undef MAX
#undef min #undef min
@ -70,6 +71,8 @@ struct IntSideDef
inline int GetSampleDistanceBottom() const { return sampleDistanceBottom ? sampleDistanceBottom : sampleDistance; } inline int GetSampleDistanceBottom() const { return sampleDistanceBottom ? sampleDistanceBottom : sampleDistance; }
TArray<UDMFKey> props; TArray<UDMFKey> props;
inline int GetSectorGroup() const;
}; };
struct MapLineDef struct MapLineDef
@ -107,6 +110,8 @@ struct IntLineDef
TArray<int> ids; TArray<int> ids;
IntSector *frontsector = nullptr, *backsector = nullptr; IntSector *frontsector = nullptr, *backsector = nullptr;
inline int GetSectorGroup() const;
}; };
struct MapSector struct MapSector
@ -158,6 +163,8 @@ struct IntSector
TArray<IntLineDef*> lines; TArray<IntLineDef*> lines;
TArray<IntLineDef*> portals; TArray<IntLineDef*> portals;
int group = 0;
// Utility functions // Utility functions
inline const char* GetTextureName(int plane) const { return plane != PLANE_FLOOR ? data.ceilingpic : data.floorpic; } inline const char* GetTextureName(int plane) const { return plane != PLANE_FLOOR ? data.ceilingpic : data.floorpic; }
@ -173,6 +180,16 @@ struct IntSector
} }
}; };
inline int IntLineDef::GetSectorGroup() const
{
return frontsector ? frontsector->group : (backsector ? backsector->group : 0);
}
inline int IntSideDef::GetSectorGroup() const
{
return line ? line->GetSectorGroup() : 0;
}
struct MapSubsector struct MapSubsector
{ {
uint16_t numlines; uint16_t numlines;
@ -329,6 +346,21 @@ struct ThingLight
IntSector *sector; IntSector *sector;
MapSubsectorEx *ssect; MapSubsectorEx *ssect;
// Portal related functionality
std::optional<vec3> relativePosition;
int sectorGroup = 0;
// Portal aware position
vec3 LightRelativeOrigin() const
{
if (relativePosition)
{
return *relativePosition;
}
return LightOrigin();
}
// Absolute X, Y, Z position of the light
vec3 LightOrigin() const vec3 LightOrigin() const
{ {
float originZ; float originZ;

View file

@ -691,6 +691,49 @@ void FLevel::PostLoadInitialization()
} }
} }
} }
// Discover sector groups (graph islands)
{
int groupId = 0;
std::vector<IntSector*> candidates;
auto canPass = [&](IntLineDef* line) {
// Further conditions can be added to further split the map into groups
return line->special == 0 || (line->special != Line_SetPortal && line->special != Line_Horizon);
};
for (auto& sector : Sectors)
{
if (!sector.group)
{
sector.group = ++groupId;
candidates.push_back(&sector);
while (!candidates.empty())
{
auto* sector = candidates[candidates.size() - 1];
candidates.pop_back();
for (const auto& line : sector->lines)
{
if (canPass(line))
{
if (line->frontsector && !line->frontsector->group)
{
line->frontsector->group = groupId;
candidates.push_back(line->frontsector);
}
if (line->backsector && !line->backsector->group)
{
line->backsector->group = groupId;
candidates.push_back(line->backsector);
}
}
}
}
}
}
}
} }
void FProcessor::BuildNodes() void FProcessor::BuildNodes()

View file

@ -290,6 +290,7 @@ void FLevel::CreateLights()
thingLight.sector = GetSectorFromSubSector(thingLight.ssect); thingLight.sector = GetSectorFromSubSector(thingLight.ssect);
thingLight.origin.x = x; thingLight.origin.x = x;
thingLight.origin.y = y; thingLight.origin.y = y;
thingLight.sectorGroup = thingLight.sector->group;
ThingLights.Push(thingLight); ThingLights.Push(thingLight);
} }

View file

@ -52,14 +52,16 @@ struct LightInfo
{ {
vec3 Origin; vec3 Origin;
float Padding0; float Padding0;
vec3 RelativeOrigin;
float Padding1;
float Radius; float Radius;
float Intensity; float Intensity;
float InnerAngleCos; float InnerAngleCos;
float OuterAngleCos; float OuterAngleCos;
vec3 SpotDir; vec3 SpotDir;
float Padding1;
vec3 Color;
float Padding2; float Padding2;
vec3 Color;
float Padding3;
}; };
layout(set = 0, binding = 1) buffer SurfaceIndexBuffer { uint surfaceIndices[]; }; layout(set = 0, binding = 1) buffer SurfaceIndexBuffer { uint surfaceIndices[]; };
@ -91,6 +93,7 @@ vec2 Hammersley(uint i, uint N);
float RadicalInverse_VdC(uint bits); float RadicalInverse_VdC(uint bits);
bool TraceAnyHit(vec3 origin, float tmin, vec3 dir, float tmax); bool TraceAnyHit(vec3 origin, float tmin, vec3 dir, float tmax);
bool TracePoint(vec3 origin, vec3 target, float tmin, vec3 dir, float tmax);
int TraceFirstHitTriangle(vec3 origin, float tmin, vec3 dir, float tmax); int TraceFirstHitTriangle(vec3 origin, float tmin, vec3 dir, float tmax);
int TraceFirstHitTriangleT(vec3 origin, float tmin, vec3 dir, float tmax, out float t); int TraceFirstHitTriangleT(vec3 origin, float tmin, vec3 dir, float tmax, out float t);
@ -117,10 +120,10 @@ vec3 TraceLight(vec3 origin, vec3 normal, LightInfo light)
{ {
const float minDistance = 0.01; const float minDistance = 0.01;
vec3 incoming = vec3(0.0); vec3 incoming = vec3(0.0);
float dist = distance(light.Origin, origin); float dist = distance(light.RelativeOrigin, origin);
if (dist > minDistance && dist < light.Radius) if (dist > minDistance && dist < light.Radius)
{ {
vec3 dir = normalize(light.Origin - 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 = 1.0f;
@ -139,12 +142,13 @@ vec3 TraceLight(vec3 origin, vec3 normal, LightInfo light)
float attenuation = distAttenuation * angleAttenuation * spotAttenuation; float attenuation = distAttenuation * angleAttenuation * spotAttenuation;
if (attenuation > 0.0) if (attenuation > 0.0)
{ {
if (!TraceAnyHit(origin, minDistance, dir, dist)) if(TracePoint(origin, light.Origin, minDistance, dir, dist))
{ {
incoming.rgb += light.Color * (attenuation * light.Intensity); incoming.rgb += light.Color * (attenuation * light.Intensity);
} }
} }
} }
return incoming; return incoming;
} }
@ -236,6 +240,7 @@ int TraceFirstHitTriangleNoPortal(vec3 origin, float tmin, vec3 dir, float tmax,
} }
else else
{ {
t = tmax;
return -1; return -1;
} }
} }
@ -466,6 +471,8 @@ int TraceFirstHitTriangleNoPortal(vec3 origin, float tmin, vec3 dir, float tmax,
return hit.triangle; return hit.triangle;
} }
} }
tparam = tracedist;
return -1; return -1;
} }
@ -512,4 +519,48 @@ bool TraceAnyHit(vec3 origin, float tmin, vec3 dir, float tmax)
return TraceFirstHitTriangle(origin, tmin, dir, tmax) >= 0; return TraceFirstHitTriangle(origin, tmin, dir, tmax) >= 0;
} }
bool TracePoint(vec3 origin, vec3 target, float tmin, vec3 dir, float tmax)
{
int primitiveID;
float t;
while(true)
{
t = tmax;
primitiveID = TraceFirstHitTriangleNoPortal(origin, tmin, dir, tmax, t);
origin += dir * t;
tmax -= t;
if(primitiveID < 0)
{
// We didn't hit anything
break;
}
SurfaceInfo surface = surfaces[surfaceIndices[primitiveID]];
if(surface.PortalIndex == 0)
{
break;
}
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;
#if defined(USE_RAYQUERY)
#else
origin += dir * tmin;
tmax -= tmin;
#endif
}
return distance(origin, target) <= 1.0;
}
)glsl"; )glsl";

View file

@ -216,6 +216,7 @@ void GPURaytracer::RenderAtlasImage(size_t pageIndex)
for (ThingLight* light : surface->LightList) for (ThingLight* light : surface->LightList)
{ {
lightinfo->Origin = light->LightOrigin(); lightinfo->Origin = light->LightOrigin();
lightinfo->RelativeOrigin = light->LightRelativeOrigin();
lightinfo->Radius = light->LightRadius(); lightinfo->Radius = light->LightRadius();
lightinfo->Intensity = light->intensity; lightinfo->Intensity = light->intensity;
lightinfo->InnerAngleCos = light->innerAngleCos; lightinfo->InnerAngleCos = light->innerAngleCos;
@ -1015,14 +1016,11 @@ std::vector<PortalInfo> GPURaytracer::CreatePortalInfo()
portals.push_back(noPortal); portals.push_back(noPortal);
} }
for (const auto& surface : mesh->surfaces) for (const auto& portal : mesh->portals)
{ {
if (surface->portalIndex >= 0) PortalInfo info;
{ info.Transformation = portal->transformation;
PortalInfo info; portals.push_back(info);
info.Transformation = mesh->portals[surface->portalIndex]->transformation;
portals.push_back(info);
}
} }
return portals; return portals;

View file

@ -50,16 +50,20 @@ struct LightInfo
{ {
vec3 Origin; vec3 Origin;
float Padding0; float Padding0;
vec3 RelativeOrigin;
float Padding1;
float Radius; float Radius;
float Intensity; float Intensity;
float InnerAngleCos; float InnerAngleCos;
float OuterAngleCos; float OuterAngleCos;
vec3 SpotDir; vec3 SpotDir;
float Padding1;
vec3 Color;
float Padding2; float Padding2;
vec3 Color;
float Padding3;
}; };
static_assert(sizeof(LightInfo) == sizeof(float) * 20);
struct CollisionNodeBufferHeader struct CollisionNodeBufferHeader
{ {
int root; int root;

View file

@ -60,6 +60,13 @@ LevelMesh::LevelMesh(FLevel &doomMap, int sampleDistance, int textureSize)
printf("Surfaces total: %i\n\n", (int)surfaces.size()); printf("Surfaces total: %i\n\n", (int)surfaces.size());
// Update sector group of the surfacesaa
for (auto& surface : surfaces)
{
surface->sectorGroup = surface->type == ST_CEILING || surface->type == ST_FLOOR ?
doomMap.GetSectorFromSubSector(&doomMap.GLSubsectors[surface->typeIndex])->group : (doomMap.Sides[surface->typeIndex].GetSectorGroup());
}
printf("Building level mesh...\n\n"); printf("Building level mesh...\n\n");
for (size_t i = 0; i < surfaces.size(); i++) for (size_t i = 0; i < surfaces.size(); i++)
@ -112,66 +119,12 @@ LevelMesh::LevelMesh(FLevel &doomMap, int sampleDistance, int textureSize)
} }
printf("Finding smoothing groups...\n\n"); printf("Finding smoothing groups...\n\n");
BuildSmoothingGroups(doomMap);
for (size_t i = 0; i < surfaces.size(); i++)
{
// Is this surface in the same plane as an existing smoothing group?
int smoothingGroupIndex = -1;
for (size_t j = 0; j < smoothingGroups.size(); j++)
{
float direction = std::abs(dot(smoothingGroups[j].Normal(), surfaces[i]->plane.Normal()));
if (direction >= 0.9999f && direction <= 1.001f)
{
float dist = std::abs(smoothingGroups[j].Distance(surfaces[i]->plane.Normal() * surfaces[i]->plane.d));
if (dist <= 0.01f)
{
smoothingGroupIndex = (int)j;
break;
}
}
}
// Surface is in a new plane. Create a smoothing group for it
if (smoothingGroupIndex == -1)
{
smoothingGroupIndex = smoothingGroups.size();
smoothingGroups.push_back(surfaces[i]->plane);
}
surfaces[i]->smoothingGroupIndex = smoothingGroupIndex;
}
printf("Created %d smoothing groups for %d surfaces\n\n", (int)smoothingGroups.size(), (int)surfaces.size());
printf("Building collision data...\n\n"); printf("Building collision data...\n\n");
Collision = std::make_unique<TriangleMeshShape>(MeshVertices.Data(), MeshVertices.Size(), MeshElements.Data(), MeshElements.Size()); Collision = std::make_unique<TriangleMeshShape>(MeshVertices.Data(), MeshVertices.Size(), MeshElements.Data(), MeshElements.Size());
printf("Building light list...\n\n"); BuildLightLists(doomMap);
for (ThingLight& light : map->ThingLights)
{
SphereShape sphere;
sphere.center = light.LightOrigin();
sphere.radius = light.LightRadius();
for (int triangleIndex : TriangleMeshShape::find_all_hits(Collision.get(), &sphere))
{
Surface* surface = surfaces[MeshSurfaces[triangleIndex]].get();
bool found = false;
for (ThingLight* light2 : surface->LightList)
{
if (light2 == &light)
{
found = true;
break;
}
}
if (!found)
surface->LightList.push_back(&light);
}
}
/* /*
std::map<int, int> lightStats; std::map<int, int> lightStats;
for (auto& surface : surfaces) for (auto& surface : surfaces)
@ -182,6 +135,119 @@ LevelMesh::LevelMesh(FLevel &doomMap, int sampleDistance, int textureSize)
*/ */
} }
void LevelMesh::BuildSmoothingGroups(FLevel& doomMap)
{
for (size_t i = 0; i < surfaces.size(); i++)
{
// Is this surface in the same plane as an existing smoothing group?
int smoothingGroupIndex = -1;
auto surface = surfaces[i].get();
for (size_t j = 0; j < smoothingGroups.size(); j++)
{
if (surface->sectorGroup == smoothingGroups[j].sectorGroup)
{
float direction = std::abs(dot(smoothingGroups[j].plane.Normal(), surface->plane.Normal()));
if (direction >= 0.9999f && direction <= 1.001f)
{
float dist = std::abs(smoothingGroups[j].plane.Distance(surface->plane.Normal() * surface->plane.d));
if (dist <= 0.01f)
{
smoothingGroupIndex = (int)j;
break;
}
}
}
}
// Surface is in a new plane. Create a smoothing group for it
if (smoothingGroupIndex == -1)
{
smoothingGroupIndex = smoothingGroups.size();
SmoothingGroup group;
group.plane = surface->plane;
group.sectorGroup = surface->sectorGroup;
smoothingGroups.push_back(group);
}
surface->smoothingGroupIndex = smoothingGroupIndex;
}
printf("Created %d smoothing groups for %d surfaces\n\n", (int)smoothingGroups.size(), (int)surfaces.size());
}
void LevelMesh::PropagateLight(FLevel& doomMap, ThingLight *light)
{
if (lightPropagationRecursiveDepth > 32)
{
return;
}
SphereShape sphere;
sphere.center = light->LightRelativeOrigin();
sphere.radius = light->LightRadius();
lightPropagationRecursiveDepth++;
std::set<Portal, RecursivePortalComparator> portalsToErase;
for (int triangleIndex : TriangleMeshShape::find_all_hits(Collision.get(), &sphere))
{
Surface* surface = surfaces[MeshSurfaces[triangleIndex]].get();
// skip any surface which isn't physically connected to the sector group in which the light resides
if (light->sectorGroup == surface->sectorGroup)
{
if (surface->portalIndex >= 0)
{
auto portal = portals[surface->portalIndex].get();
if (touchedPortals.insert(*portal).second)
{
auto fakeLight = std::make_unique<ThingLight>(*light);
fakeLight->relativePosition.emplace(portal->TransformPosition(light->LightRelativeOrigin()));
fakeLight->sectorGroup = portal->targetSectorGroup;
PropagateLight(doomMap, fakeLight.get());
portalsToErase.insert(*portal);
portalLights.push_back(std::move(fakeLight));
}
}
// Add light to the list if it isn't already there
bool found = false;
for (ThingLight* light2 : surface->LightList)
{
if (light2 == light)
{
found = true;
break;
}
}
if (!found)
surface->LightList.push_back(light);
}
}
for (auto& portal : portalsToErase)
{
touchedPortals.erase(portal);
}
lightPropagationRecursiveDepth--;
}
void LevelMesh::BuildLightLists(FLevel& doomMap)
{
for (unsigned i = 0; i < map->ThingLights.Size(); ++i)
{
printf("Building light lists: %u / %u\r", i, map->ThingLights.Size());
PropagateLight(doomMap, &map->ThingLights[i]);
}
printf("Building light lists: %u / %u\n", map->ThingLights.Size(), map->ThingLights.Size());
}
// Determines a lightmap block in which to map to the lightmap texture. // Determines a lightmap block in which to map to the lightmap texture.
// Width and height of the block is calcuated and steps are computed to determine where each texel will be positioned on the surface // Width and height of the block is calcuated and steps are computed to determine where each texel will be positioned on the surface
void LevelMesh::BuildSurfaceParams(Surface* surface) void LevelMesh::BuildSurfaceParams(Surface* surface)
@ -504,10 +570,21 @@ int LevelMesh::CreateLinePortal(FLevel& doomMap, const IntLineDef& srcLine, cons
// printf("Portal translation: %.3f %.3f %.3f\n", translation.x, translation.y, translation.z); // printf("Portal translation: %.3f %.3f %.3f\n", translation.x, translation.y, translation.z);
portal->transformation = mat4::translate(translation); portal->transformation = mat4::translate(translation);
portal->sourceSectorGroup = srcLine.GetSectorGroup();
portal->targetSectorGroup = dstLine.GetSectorGroup();
} }
portals.push_back(std::move(portal)); // Deduplicate portals
return int(portals.size() - 1); auto it = portalCache.find(*portal);
if (it == portalCache.end())
{
int id = int(portals.size());
portalCache.emplace(*portal, id);
portals.push_back(std::move(portal));
return id;
}
return it->second;
} }
int LevelMesh::CheckAndMakePortal(FLevel& doomMap, MapSubsectorEx* sub, IntSector* sector, int typeIndex, int plane) int LevelMesh::CheckAndMakePortal(FLevel& doomMap, MapSubsectorEx* sub, IntSector* sector, int typeIndex, int plane)
@ -588,10 +665,21 @@ int LevelMesh::CreatePlanePortal(FLevel& doomMap, const IntLineDef& srcLine, con
// printf("Portal translation: %.3f %.3f %.3f\n", translation.x, translation.y, translation.z); // printf("Portal translation: %.3f %.3f %.3f\n", translation.x, translation.y, translation.z);
portal->transformation = mat4::translate(translation); portal->transformation = mat4::translate(translation);
portal->sourceSectorGroup = srcLine.GetSectorGroup();
portal->targetSectorGroup = dstLine.GetSectorGroup();
} }
portals.push_back(std::move(portal)); // Deduplicate portals
return int(portals.size() - 1); auto it = portalCache.find(*portal);
if (it == portalCache.end())
{
int id = int(portals.size());
portalCache.emplace(*portal, id);
portals.push_back(std::move(portal));
return id;
}
return it->second;
} }
void LevelMesh::CreateSideSurfaces(FLevel &doomMap, IntSideDef *side) void LevelMesh::CreateSideSurfaces(FLevel &doomMap, IntSideDef *side)

View file

@ -31,12 +31,15 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <cstring> #include <cstring>
#include <map>
#include <set>
#include "framework/tarray.h" #include "framework/tarray.h"
#include "framework/halffloat.h" #include "framework/halffloat.h"
#include "lightmaptexture.h" #include "lightmaptexture.h"
#include "math/mathlib.h" #include "math/mathlib.h"
#include "collision.h" #include "collision.h"
#include "portal.h"
#include "dp_rect_pack/dp_rect_pack.h" #include "dp_rect_pack/dp_rect_pack.h"
@ -60,11 +63,6 @@ enum SurfaceType
ST_FLOOR ST_FLOOR
}; };
struct Portal
{
mat4 transformation = mat4::identity();
};
struct Surface struct Surface
{ {
// Surface geometry // Surface geometry
@ -86,6 +84,9 @@ struct Surface
// Portal // Portal
int portalDestinationIndex = -1; // line or sector index int portalDestinationIndex = -1; // line or sector index
int portalIndex = -1; int portalIndex = -1;
// Sector group
int sectorGroup = 0;
// Touching light sources // Touching light sources
std::vector<ThingLight*> LightList; std::vector<ThingLight*> LightList;
@ -117,6 +118,12 @@ struct Surface
int smoothingGroupIndex = -1; int smoothingGroupIndex = -1;
}; };
struct SmoothingGroup
{
Plane plane = Plane(0, 0, 1, 0);
int sectorGroup = 0;
};
class LevelMesh class LevelMesh
{ {
public: public:
@ -132,7 +139,7 @@ public:
std::vector<std::unique_ptr<LightmapTexture>> textures; std::vector<std::unique_ptr<LightmapTexture>> textures;
std::vector<Plane> smoothingGroups; std::vector<SmoothingGroup> smoothingGroups;
std::vector<std::unique_ptr<Portal>> portals; std::vector<std::unique_ptr<Portal>> portals;
@ -148,6 +155,14 @@ public:
std::unique_ptr<TriangleMeshShape> Collision; std::unique_ptr<TriangleMeshShape> Collision;
private: private:
// Portal to portals[] index
std::map<Portal, int, IdenticalPortalComparator> portalCache;
// Portal lights
std::vector<std::unique_ptr<ThingLight>> portalLights;
std::set<Portal, RecursivePortalComparator> touchedPortals;
int lightPropagationRecursiveDepth = 0;
void CreateSubsectorSurfaces(FLevel &doomMap); void CreateSubsectorSurfaces(FLevel &doomMap);
void CreateCeilingSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector *sector, int typeIndex, bool is3DFloor); void CreateCeilingSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector *sector, int typeIndex, bool is3DFloor);
void CreateFloorSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector *sector, int typeIndex, bool is3DFloor); void CreateFloorSurface(FLevel &doomMap, MapSubsectorEx *sub, IntSector *sector, int typeIndex, bool is3DFloor);
@ -155,6 +170,12 @@ private:
void BuildSurfaceParams(Surface* surface); void BuildSurfaceParams(Surface* surface);
BBox GetBoundsFromSurface(const Surface* surface); BBox GetBoundsFromSurface(const Surface* surface);
void BuildLightLists(FLevel &doomMap);
void PropagateLight(FLevel& doomMap, ThingLight* thing);
void BuildSmoothingGroups(FLevel& doomMap);
void BlurSurfaces(); void BlurSurfaces();
void FinishSurface(RectPacker& packer, Surface* surface); void FinishSurface(RectPacker& packer, Surface* surface);

73
src/lightmap/portal.h Normal file
View file

@ -0,0 +1,73 @@
#pragma once
#include "math/mathlib.h"
struct Portal
{
mat4 transformation = mat4::identity();
int sourceSectorGroup = 0;
int targetSectorGroup = 0;
inline vec3 TransformPosition(const vec3& pos) const
{
auto v = transformation * vec4(pos, 1.0);
return vec3(v.x, v.y, v.z);
}
inline vec3 TransformRotation(const vec3& dir) const
{
auto v = transformation * vec4(dir, 0.0);
return vec3(v.x, v.y, v.z);
}
// Checks only transformation
inline bool IsInverseTransformationPortal(const Portal& portal) const
{
auto diff = portal.TransformPosition(TransformPosition(vec3(0)));
return abs(diff.x) < 0.001 && abs(diff.y) < 0.001 && abs(diff.z) < 0.001;
}
// Checks only transformation
inline bool IsEqualTransformationPortal(const Portal& portal) const
{
auto diff = portal.TransformPosition(vec3(0)) - TransformPosition(vec3(0));
return (abs(diff.x) < 0.001 && abs(diff.y) < 0.001 && abs(diff.z) < 0.001);
}
// Checks transformation, source and destiantion sector groups
inline bool IsEqualPortal(const Portal& portal) const
{
return sourceSectorGroup == portal.sourceSectorGroup && targetSectorGroup == portal.targetSectorGroup && IsEqualTransformationPortal(portal);
}
// Checks transformation, source and destiantion sector groups
inline bool IsInversePortal(const Portal& portal) const
{
return sourceSectorGroup == portal.targetSectorGroup && targetSectorGroup == portal.sourceSectorGroup && IsInverseTransformationPortal(portal);
}
inline void DumpInfo()
{
auto v = TransformPosition(vec3(0));
printf("Portal offset: %.3f %.3f %.3f\n\tsource group:\t%d\n\ttarget group:\t%d", v.x, v.y, v.z, sourceSectorGroup, targetSectorGroup);
}
};
// for use with std::set to recursively go through portals and skip returning portals
struct RecursivePortalComparator
{
bool operator()(const Portal& a, const Portal& b) const
{
return !a.IsInversePortal(b) && std::memcmp(&a.transformation, &b.transformation, sizeof(mat4)) < 0;
}
};
// for use with std::map to reject portals which have the same effect for light rays
struct IdenticalPortalComparator
{
bool operator()(const Portal& a, const Portal& b) const
{
return !a.IsEqualPortal(b) && std::memcmp(&a.transformation, &b.transformation, sizeof(mat4)) < 0;
}
};