Skip to content

Commit

Permalink
pielighting.cpp: Merge nearby point lights
Browse files Browse the repository at this point in the history
  • Loading branch information
past-due committed May 2, 2024
1 parent dee3610 commit 1124727
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 5 deletions.
118 changes: 114 additions & 4 deletions lib/ivis_opengl/pielighting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <glm/glm.hpp>
#include <algorithm>
#include <functional>
#include <unordered_map>
#include "culling.h"
#include "src/profiling.h"

Expand Down Expand Up @@ -113,6 +114,29 @@ namespace {

}

/* The shift on a world coordinate to get the tile coordinate */
#define TILE_SHIFT 7

static inline int32_t pielight_maptile_coord(int32_t worldCoord)
{
return worldCoord >> TILE_SHIFT;
}

struct TileCoordsHasher
{
std::size_t operator()(const std::pair<int32_t, int32_t>& p) const
{
return std::hash<long long>()(static_cast<long long>(p.first) * (static_cast<long long>(INT_MAX) + 1) + p.second);
}
};

static float pointLightDistanceCalc(const renderingNew::LightingManager::CalculatedPointLight& a, const LIGHT& b)
{
glm::vec3 pointLightVector = a.position - glm::vec3(b.position);
auto length = glm::length(pointLightVector);
return length;
}

void renderingNew::LightingManager::ComputeFrameData(const LightingData& data, LightMap&, const glm::mat4& worldViewProjectionMatrix)
{
PointLightBuckets result;
Expand Down Expand Up @@ -140,6 +164,14 @@ void renderingNew::LightingManager::ComputeFrameData(const LightingData& data, L
[](const glm::vec3& in) { return in.z <= 1; }
};

std::unordered_map<std::pair<int32_t, int32_t>, std::vector<size_t>, TileCoordsHasher> tileRangeLights; // map tile coordinates to vector of culledLight indexes
constexpr size_t maxRangedLightsPerTile = 16;
constexpr size_t minLightRange = 5;
constexpr float distanceCalcCombineThreshold = 32.f;
size_t lightsCombined = 0;
size_t lightsSkipped = 0;
size_t tinyLightsSkipped = 0;

culledLights.clear();
for (const auto& light : data.lights)
{
Expand All @@ -152,19 +184,97 @@ void renderingNew::LightingManager::ComputeFrameData(const LightingData& data, L
{
continue;
}
culledLights.push_back({light, clipSpaceBoundingBox});

if (light.range >= minLightRange)
{
std::pair<int32_t, int32_t> lightTileCoords(pielight_maptile_coord(light.position.x), pielight_maptile_coord(light.position.y));
auto it = tileRangeLights.find(lightTileCoords);
if (it != tileRangeLights.end())
{
// merge point lights (if possible)
bool combinedLight = false;
for (auto& o : it->second)
{
auto& existingLight = culledLights[o];
auto newLightRange = static_cast<float>(light.range);
auto distanceCalc = pointLightDistanceCalc(existingLight.light, light);
if ((distanceCalc < distanceCalcCombineThreshold)
&& (distanceCalc < (existingLight.light.range + newLightRange)))
{
// Found two lights close to each other - combine them
if (newLightRange > existingLight.light.range)
{
// If the new light has a greater range, use that as the "base"
CalculatedPointLight calcLight;
calcLight.position = glm::vec3(light.position.x, light.position.y, light.position.z);
calcLight.colour = glm::vec3(light.colour.byte.r / 255.f, light.colour.byte.g / 255.f, light.colour.byte.b / 255.f);
calcLight.range = light.range;

float weight = existingLight.light.range / calcLight.range;
calcLight.colour.x += (existingLight.light.colour.x) * weight;
calcLight.colour.y += (existingLight.light.colour.y) * weight;
calcLight.colour.z += (existingLight.light.colour.z) * weight;

existingLight.light = calcLight;
existingLight.clipSpaceBoundingBox = clipSpaceBoundingBox;
}
else
{
float weight = light.range / existingLight.light.range;
existingLight.light.colour.x += (light.colour.byte.r / 255.f) * weight;
existingLight.light.colour.y += (light.colour.byte.g / 255.f) * weight;
existingLight.light.colour.z += (light.colour.byte.b / 255.f) * weight;
}
combinedLight = true;
break;
}
}
if (combinedLight)
{
++lightsCombined;
continue;
}
if (it->second.size() >= maxRangedLightsPerTile)
{
++lightsSkipped;
continue;
}

it->second.push_back(culledLights.size());
}
else
{
tileRangeLights[lightTileCoords].push_back(culledLights.size());
}
}
else
{
++tinyLightsSkipped;
continue;
}

CalculatedPointLight calcLight;
calcLight.position = glm::vec3(light.position.x, light.position.y, light.position.z);
calcLight.colour = glm::vec3(light.colour.byte.r / 255.f, light.colour.byte.g / 255.f, light.colour.byte.b / 255.f);
calcLight.range = light.range;

culledLights.push_back({std::move(calcLight), std::move(clipSpaceBoundingBox)});
}

if (lightsSkipped > 0 || lightsCombined > 0 || tinyLightsSkipped > 0)
{
// debug(LOG_INFO, "Point lights - merged: %zu, skipped (tile limit): %zu, skipped (tiny): %zu", lightsCombined, lightsSkipped, tinyLightsSkipped);
}

for (size_t lightIndex = 0, end = culledLights.size(); lightIndex < end; lightIndex++)
{
const auto& light = culledLights[lightIndex].light;
result.positions[lightIndex].x = light.position.x;
result.positions[lightIndex].y = light.position.y;
result.positions[lightIndex].z = light.position.z;
result.colorAndEnergy[lightIndex].x = light.colour.byte.r / 255.f;
result.colorAndEnergy[lightIndex].y = light.colour.byte.g / 255.f;
result.colorAndEnergy[lightIndex].z = light.colour.byte.b / 255.f;
result.colorAndEnergy[lightIndex].x = light.colour.x;
result.colorAndEnergy[lightIndex].y = light.colour.y;
result.colorAndEnergy[lightIndex].z = light.colour.z;
result.colorAndEnergy[lightIndex].w = light.range;
}

Expand Down
9 changes: 8 additions & 1 deletion lib/ivis_opengl/pielighting.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,18 @@ namespace renderingNew
struct LightingManager final : ILightingManager
{
void ComputeFrameData(const LightingData& data, LightMap& lightmap, const glm::mat4& worldViewProjectionMatrix) override;

struct CalculatedPointLight
{
glm::vec3 position = glm::vec3(0, 0, 0);
glm::vec3 colour;
float range;
};
private:
// cached containers to avoid frequent reallocations
struct CulledLightInfo
{
const LIGHT& light;
CalculatedPointLight light;
BoundingBox clipSpaceBoundingBox;
};
std::vector<CulledLightInfo> culledLights;
Expand Down

0 comments on commit 1124727

Please sign in to comment.