Revert "reduce memory usage by only storing VPLs when we need to, and only once"

This reverts commit fcf39b2ef8.

# Conflicts:
#	include/light/light.hh
#	include/light/surflight.hh
#	light/bounce.cc
#	light/light.cc
#	light/ltface.cc
#	light/surflight.cc
This commit is contained in:
Jonathan 2023-08-26 23:03:25 -04:00
parent d296b883bf
commit 2e0e23622b
7 changed files with 189 additions and 244 deletions

View File

@ -29,4 +29,5 @@ struct mbsp_t;
// public functions // public functions
void ResetBounce(); void ResetBounce();
const std::vector<struct surfacelight_t> &BounceLights();
void MakeBounceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp); void MakeBounceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp);

View File

@ -143,9 +143,6 @@ struct lightsurf_t
std::unique_ptr<raystream_intersection_t> intersection_stream; std::unique_ptr<raystream_intersection_t> intersection_stream;
lightmapdict_t lightmapsByStyle; lightmapdict_t lightmapsByStyle;
// surface light stuff
std::unique_ptr<surfacelight_t> vpl;
}; };
/* debug */ /* debug */

View File

@ -39,40 +39,33 @@ struct surfacelight_t
{ {
qvec3d pos; qvec3d pos;
qvec3f surfnormal; qvec3f surfnormal;
size_t points_before_culling; /**
* disables use of the surfnormal. We set this to true on sky surface lights,
// Estimated visible AABB culling * to avoid black seams on geometry meeting the sky
aabb3d bounds; */
bool omnidirectional;
std::optional<vec_t> minlight_scale;
std::vector<qvec3f> points; std::vector<qvec3f> points;
std::vector<const mleaf_t *> leaves; std::vector<const mleaf_t *> leaves;
// Surface light settings... // Surface light settings...
struct per_style_t float intensity; // Surface light strength for each point
{ float totalintensity; // Total surface light strength
bool bounce = false; // whether this is a direct or indirect emission qvec3d color; // Surface color
/**
* disables use of the surfnormal. We set this to true on sky surface lights,
* to avoid black seams on geometry meeting the sky
*/
bool omnidirectional = false;
// rescale faces to account for perpendicular lights
bool rescale = false;
int32_t style = 0; // style ID
float intensity = 0; // Surface light strength for each point
float totalintensity = 0; // Total surface light strength
qvec3d color; // Surface color
};
// Light data per style // Estimated visible AABB culling
std::vector<per_style_t> styles; aabb3d bounds;
};
int32_t style;
// rescale faces to account for perpendicular lights
bool rescale;
std::optional<vec_t> minlight_scale;
};
class light_t; class light_t;
void ResetSurflight(); void ResetSurflight();
std::vector<surfacelight_t> &GetSurfaceLights();
size_t GetSurflightPoints(); size_t GetSurflightPoints();
std::optional<std::tuple<int32_t, int32_t, qvec3d, light_t *>> IsSurfaceLitFace(const mbsp_t *bsp, const mface_t *face); std::optional<std::tuple<int32_t, int32_t, qvec3d, light_t *>> IsSurfaceLitFace(const mbsp_t *bsp, const mface_t *face);
const std::vector<int> &SurfaceLightsForFaceNum(int facenum); const std::vector<int> &SurfaceLightsForFaceNum(int facenum);

View File

@ -39,10 +39,13 @@
#include <common/qvec.hh> #include <common/qvec.hh>
#include <common/parallel.hh> #include <common/parallel.hh>
std::mutex bouncelights_lock;
static std::vector<surfacelight_t> bouncelights;
static std::atomic_size_t bouncelightpoints; static std::atomic_size_t bouncelightpoints;
void ResetBounce() void ResetBounce()
{ {
bouncelights.clear();
bouncelightpoints = 0; bouncelightpoints = 0;
} }
@ -85,11 +88,11 @@ static bool Face_ShouldBounce(const mbsp_t *bsp, const mface_t *face)
return true; return true;
} }
static void MakeBounceLight(const mbsp_t *bsp, const settings::worldspawn_keys &cfg, lightsurf_t &surf, static void MakeBounceLight(const mbsp_t *bsp, const settings::worldspawn_keys &cfg, const mface_t *face,
qvec3d texture_color, int32_t style, const std::vector<qvec3f> &points, const polylib::winding_t &winding, qvec3d texture_color, int32_t style, const std::vector<qvec3f> &points, const polylib::winding_t &winding,
const vec_t &area, const qvec3d &facenormal, const qvec3d &facemidpoint) const vec_t &area, const qvec3d &facenormal, const qvec3d &facemidpoint)
{ {
if (!Face_IsEmissive(bsp, surf.face)) { if (!Face_IsEmissive(bsp, face)) {
return; return;
} }
@ -104,9 +107,6 @@ static void MakeBounceLight(const mbsp_t *bsp, const settings::worldspawn_keys &
return; return;
} }
if (!surf.vpl) {
auto &l = surf.vpl = std::make_unique<surfacelight_t>();
// Normalize color... // Normalize color...
if (intensity > 1.0) { if (intensity > 1.0) {
texture_color *= 1.0 / intensity; texture_color *= 1.0 / intensity;
@ -116,36 +116,41 @@ static void MakeBounceLight(const mbsp_t *bsp, const settings::worldspawn_keys &
Q_assert(!points.empty()); Q_assert(!points.empty());
// Add surfacelight... // Add surfacelight...
l->surfnormal = facenormal; surfacelight_t l;
l->points = points; l.surfnormal = facenormal;
l.omnidirectional = false;
l.points = points;
l.style = style;
// Init bbox... // Init bbox...
if (light_options.visapprox.value() == visapprox_t::RAYS) { if (light_options.visapprox.value() == visapprox_t::RAYS) {
l->bounds = EstimateVisibleBoundsAtPoint(facemidpoint); l.bounds = EstimateVisibleBoundsAtPoint(facemidpoint);
} }
for (auto &pt : l->points) { for (auto &pt : l.points) {
if (light_options.visapprox.value() == visapprox_t::VIS) { if (light_options.visapprox.value() == visapprox_t::VIS) {
l->leaves.push_back(Light_PointInLeaf(bsp, pt)); l.leaves.push_back(Light_PointInLeaf(bsp, pt));
} else if (light_options.visapprox.value() == visapprox_t::RAYS) { } else if (light_options.visapprox.value() == visapprox_t::RAYS) {
l->bounds += EstimateVisibleBoundsAtPoint(pt); l.bounds += EstimateVisibleBoundsAtPoint(pt);
} }
} }
l->pos = facemidpoint; l.pos = facemidpoint;
}
// Store surfacelight settings... // Store surfacelight settings...
{ l.totalintensity = intensity * area;
auto &l = surf.vpl; l.intensity = l.totalintensity / l.points.size();
auto &setting = l->styles.emplace_back(); l.color = texture_color;
setting.bounce = true;
setting.style = style; // Store light...
setting.totalintensity = intensity * area; std::unique_lock<std::mutex> lck{bouncelights_lock};
setting.intensity = setting.totalintensity / l->points.size(); bouncelights.push_back(l);
setting.color = texture_color; }
const std::vector<surfacelight_t> &BounceLights()
{
return bouncelights;
} }
}
static void MakeBounceLightsThread(const settings::worldspawn_keys &cfg, const mbsp_t *bsp, const mface_t &face) static void MakeBounceLightsThread(const settings::worldspawn_keys &cfg, const mbsp_t *bsp, const mface_t &face)
{ {
@ -240,7 +245,8 @@ static void MakeBounceLightsThread(const settings::worldspawn_keys &cfg, const m
} }
for (auto &style : emitcolors) { for (auto &style : emitcolors) {
MakeBounceLight(bsp, cfg, surf, style.second, style.first, points, winding, area, facenormal, facemidpoint); MakeBounceLight(
bsp, cfg, &face, style.second, style.first, points, winding, area, facenormal, facemidpoint);
} }
} }
@ -250,5 +256,5 @@ void MakeBounceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp)
logging::parallel_for_each(bsp->dfaces, [&](const mface_t &face) { MakeBounceLightsThread(cfg, bsp, face); }); logging::parallel_for_each(bsp->dfaces, [&](const mface_t &face) { MakeBounceLightsThread(cfg, bsp, face); });
// logging::print("{} bounce lights created, with {} points\n", bouncelights.size(), bouncelightpoints); logging::print("{} bounce lights created, with {} points\n", bouncelights.size(), bouncelightpoints);
} }

View File

@ -745,13 +745,9 @@ static void SaveLightmapSurfaces(mbsp_t *bsp)
SaveLightmapSurface(bsp, f, nullptr, nullptr, surf.get(), surf->extents, surf->vanilla_extents); SaveLightmapSurface(bsp, f, nullptr, nullptr, surf.get(), surf->extents, surf->vanilla_extents);
SaveLightmapSurface(bsp, f, &faces_sup[i], nullptr, surf.get(), surf->extents, surf->extents); SaveLightmapSurface(bsp, f, &faces_sup[i], nullptr, surf.get(), surf->extents, surf->extents);
} }
});
}
void ClearLightmapSurfaces(mbsp_t *bsp) light_surfaces[i].reset();
{ });
logging::funcheader();
logging::parallel_for(static_cast<size_t>(0), bsp->dfaces.size(), [&bsp](size_t i) { light_surfaces[i].reset(); });
} }
static void FindModelInfo(const mbsp_t *bsp) static void FindModelInfo(const mbsp_t *bsp)
@ -1548,12 +1544,8 @@ int light_main(int argc, const char **argv)
// check vis approx type // check vis approx type
if (light_options.visapprox.value() == visapprox_t::AUTO) { if (light_options.visapprox.value() == visapprox_t::AUTO) {
if (!bsp.dvis.bits.empty()) {
light_options.visapprox.set_value(visapprox_t::VIS, settings::source::DEFAULT);
} else {
light_options.visapprox.set_value(visapprox_t::RAYS, settings::source::DEFAULT); light_options.visapprox.set_value(visapprox_t::RAYS, settings::source::DEFAULT);
} }
}
img::load_textures(&bsp, light_options); img::load_textures(&bsp, light_options);
@ -1596,8 +1588,6 @@ int light_main(int argc, const char **argv)
LightGrid(&bspdata); LightGrid(&bspdata);
ClearLightmapSurfaces(&std::get<mbsp_t>(bspdata.bsp));
// invalidate normals // invalidate normals
bspdata.bspx.entries.erase("FACENORMALS"); bspdata.bspx.entries.erase("FACENORMALS");

View File

@ -26,6 +26,7 @@
#include <light/entities.hh> #include <light/entities.hh>
#include <light/lightgrid.hh> #include <light/lightgrid.hh>
#include <light/trace.hh> #include <light/trace.hh>
#include <light/bounce.hh>
#include <light/litfile.hh> // for facesup_t #include <light/litfile.hh> // for facesup_t
#include <common/imglib.hh> #include <common/imglib.hh>
@ -1012,22 +1013,13 @@ constexpr vec_t SQR(vec_t x)
} }
// CHECK: naming? why clamp*min*? // CHECK: naming? why clamp*min*?
constexpr bool Light_ClampMin(lightsample_t &sample, const vec_t light, const qvec3d &color) constexpr void Light_ClampMin(lightsample_t &sample, const vec_t light, const qvec3d &color)
{ {
bool changed = false;
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
float c = (float)(color[i] * (light / 255.0f)); sample.color[i] = std::max(sample.color[i], (float)(color[i] * (light / 255.0f)));
if (c > sample.color[i]) {
sample.color[i] = c;
changed = true;
} }
} }
return changed;
}
constexpr vec_t fraction(const vec_t &min, const vec_t &val, const vec_t &max) constexpr vec_t fraction(const vec_t &min, const vec_t &val, const vec_t &max)
{ {
if (val >= max) if (val >= max)
@ -1671,13 +1663,14 @@ static void LightFace_Min(const mbsp_t *bsp, const mface_t *face, const qvec3d &
} }
if (cfg.addminlight.value()) { if (cfg.addminlight.value()) {
sample.color += color * (value / 255.0); sample.color += color * (value / 255.0);
hit = true;
} else { } else {
if (lightsurf->minlightMottle) { if (lightsurf->minlightMottle) {
value += Mottle(surf_sample.point); value += Mottle(surf_sample.point);
} }
hit = Light_ClampMin(sample, value, color) || hit; Light_ClampMin(sample, value, color);
} }
hit = true;
} }
if (hit) { if (hit) {
@ -1753,11 +1746,11 @@ static void LightFace_LocalMin(
cfg, lightsurf->samples[i].occlusion, entity.get(), 0.0 /* TODO: pass distance */, lightsurf); cfg, lightsurf->samples[i].occlusion, entity.get(), 0.0 /* TODO: pass distance */, lightsurf);
if (cfg.addminlight.value()) { if (cfg.addminlight.value()) {
sample.color += entity->color.value() * (value / 255.0); sample.color += entity->color.value() * (value / 255.0);
hit = true;
} else { } else {
hit = Light_ClampMin(sample, value, entity->color.value()) || hit; Light_ClampMin(sample, value, entity->color.value());
} }
hit = true;
total_light_ray_hits++; total_light_ray_hits++;
} }
@ -1900,7 +1893,7 @@ static void LightFace_DebugMottle(const mbsp_t *bsp, const lightsurf_t *lightsur
} }
// mxd. Surface light falloff. Returns color in [0,255] // mxd. Surface light falloff. Returns color in [0,255]
constexpr qvec3f SurfaceLight_ColorAtDist(const settings::worldspawn_keys &cfg, const float &surf_scale, inline qvec3f SurfaceLight_ColorAtDist(const settings::worldspawn_keys &cfg, const float &surf_scale,
const float &intensity, const qvec3d &color, const float &dist, const float &hotspot_clamp) const float &intensity, const qvec3d &color, const float &dist, const float &hotspot_clamp)
{ {
// Exponential falloff // Exponential falloff
@ -1913,25 +1906,25 @@ constexpr qvec3f SurfaceLight_ColorAtDist(const settings::worldspawn_keys &cfg,
// dir: vpl -> sample point direction // dir: vpl -> sample point direction
// mxd. returns color in [0,255] // mxd. returns color in [0,255]
inline qvec3f GetSurfaceLighting(const settings::worldspawn_keys &cfg, const surfacelight_t &vpl, inline qvec3f GetSurfaceLighting(const settings::worldspawn_keys &cfg, const surfacelight_t *vpl, const qvec3f &dir,
const surfacelight_t::per_style_t &vpl_settings, const qvec3f &dir, const float dist, const qvec3f &normal, const float dist, const qvec3f &normal, bool use_normal, const vec_t &standard_scale, const vec_t &sky_scale,
bool use_normal, const vec_t &standard_scale, const vec_t &sky_scale, const float &hotspot_clamp) const float &hotspot_clamp)
{ {
qvec3f result; qvec3f result;
float dotProductFactor = 1.0f; float dotProductFactor = 1.0f;
float dp1 = qv::dot(vpl.surfnormal, dir); float dp1 = qv::dot(vpl->surfnormal, dir);
const qvec3f sp_vpl = dir * -1.0f; const qvec3f sp_vpl = dir * -1.0f;
float dp2 = use_normal ? qv::dot(sp_vpl, normal) : 1.0f; float dp2 = use_normal ? qv::dot(sp_vpl, normal) : 1.0f;
if (!vpl_settings.omnidirectional) { if (!vpl->omnidirectional) {
if (dp1 < -LIGHT_ANGLE_EPSILON) if (dp1 < -LIGHT_ANGLE_EPSILON)
return {0}; // sample point behind vpl return {0}; // sample point behind vpl
if (dp2 < -LIGHT_ANGLE_EPSILON) if (dp2 < -LIGHT_ANGLE_EPSILON)
return {0}; // vpl behind sample face return {0}; // vpl behind sample face
// Rescale a bit to brighten the faces nearly-perpendicular to the surface light plane... // Rescale a bit to brighten the faces nearly-perpendicular to the surface light plane...
if (vpl_settings.rescale) { if (vpl->rescale) {
dp1 = 0.5f + dp1 * 0.5f; dp1 = 0.5f + dp1 * 0.5f;
dp2 = 0.5f + dp2 * 0.5f; dp2 = 0.5f + dp2 * 0.5f;
} }
@ -1945,8 +1938,8 @@ inline qvec3f GetSurfaceLighting(const settings::worldspawn_keys &cfg, const sur
dotProductFactor = std::max(0.0f, dotProductFactor); dotProductFactor = std::max(0.0f, dotProductFactor);
// Get light contribution // Get light contribution
result = SurfaceLight_ColorAtDist(cfg, vpl_settings.omnidirectional ? sky_scale : standard_scale, result = SurfaceLight_ColorAtDist(
vpl_settings.intensity, vpl_settings.color, dist, hotspot_clamp); cfg, vpl->omnidirectional ? sky_scale : standard_scale, vpl->intensity, vpl->color, dist, hotspot_clamp);
// Apply angle scale // Apply angle scale
const qvec3f resultscaled = result * dotProductFactor; const qvec3f resultscaled = result * dotProductFactor;
@ -1956,8 +1949,8 @@ inline qvec3f GetSurfaceLighting(const settings::worldspawn_keys &cfg, const sur
} }
static bool // mxd static bool // mxd
SurfaceLight_SphereCull(const surfacelight_t *vpl, const lightsurf_t *lightsurf, SurfaceLight_SphereCull(
const surfacelight_t::per_style_t &vpl_settings, const vec_t &bouncelight_gate, const float &hotspot_clamp) const surfacelight_t *vpl, const lightsurf_t *lightsurf, const vec_t &bouncelight_gate, const float &hotspot_clamp)
{ {
if (light_options.visapprox.value() == visapprox_t::RAYS && if (light_options.visapprox.value() == visapprox_t::RAYS &&
vpl->bounds.disjoint(lightsurf->extents.bounds, 0.001)) { vpl->bounds.disjoint(lightsurf->extents.bounds, 0.001)) {
@ -1969,16 +1962,17 @@ SurfaceLight_SphereCull(const surfacelight_t *vpl, const lightsurf_t *lightsurf,
const float dist = qv::length(dir) + lightsurf->extents.radius; const float dist = qv::length(dir) + lightsurf->extents.radius;
// Get light contribution // Get light contribution
const qvec3f color = SurfaceLight_ColorAtDist(cfg, const qvec3f color =
vpl_settings.omnidirectional ? cfg.surflightskyscale.value() : cfg.surflightscale.value(), SurfaceLight_ColorAtDist(cfg, vpl->omnidirectional ? cfg.surflightskyscale.value() : cfg.surflightscale.value(),
vpl_settings.totalintensity, vpl_settings.color, dist, hotspot_clamp); vpl->totalintensity, vpl->color, dist, hotspot_clamp);
return qv::gate(color, (float)bouncelight_gate); return qv::gate(color, (float)bouncelight_gate);
} }
static void // mxd static void // mxd
LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t *lightmaps, bool bounce, LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t *lightmaps,
const vec_t &standard_scale, const vec_t &sky_scale, const float &hotspot_clamp) const std::vector<surfacelight_t> &surface_lights, const vec_t &standard_scale, const vec_t &sky_scale,
const float &hotspot_clamp)
{ {
const settings::worldspawn_keys &cfg = *lightsurf->cfg; const settings::worldspawn_keys &cfg = *lightsurf->cfg;
const float surflight_gate = 0.01f; const float surflight_gate = 0.01f;
@ -1988,21 +1982,9 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t
return; return;
} }
for (const auto &surf_ptr : LightSurfaces()) { for (const surfacelight_t &vpl : surface_lights) {
if (SurfaceLight_SphereCull(&vpl, lightsurf, surflight_gate, hotspot_clamp))
if (!surf_ptr || !surf_ptr->vpl) {
// didn't emit anthing
continue; continue;
}
auto &vpl = *surf_ptr->vpl.get();
for (const auto &vpl_setting : surf_ptr->vpl->styles) {
if (vpl_setting.bounce != bounce)
continue;
else if (SurfaceLight_SphereCull(&vpl, lightsurf, vpl_setting, surflight_gate, hotspot_clamp))
continue;
raystream_occlusion_t &rs = *lightsurf->occlusion_stream; raystream_occlusion_t &rs = *lightsurf->occlusion_stream;
@ -2035,8 +2017,8 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t
dir /= dist; dir /= dist;
} }
const qvec3f indirect = GetSurfaceLighting(cfg, vpl, vpl_setting, dir, dist, lightsurf_normal, const qvec3f indirect = GetSurfaceLighting(
use_normal, standard_scale, sky_scale, hotspot_clamp); cfg, &vpl, dir, dist, lightsurf_normal, use_normal, standard_scale, sky_scale, hotspot_clamp);
if (!qv::gate(indirect, surflight_gate)) { // Each point contributes very little to the final result if (!qv::gate(indirect, surflight_gate)) { // Each point contributes very little to the final result
rs.pushRay(i, pos, dir, dist, &indirect); rs.pushRay(i, pos, dir, dist, &indirect);
} }
@ -2048,7 +2030,7 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t
total_surflight_rays += rs.numPushedRays(); total_surflight_rays += rs.numPushedRays();
rs.tracePushedRaysOcclusion(lightsurf->modelinfo, CHANNEL_MASK_DEFAULT); rs.tracePushedRaysOcclusion(lightsurf->modelinfo, CHANNEL_MASK_DEFAULT);
const int lightmapstyle = vpl_setting.style; const int lightmapstyle = vpl.style;
lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, lightmapstyle, lightsurf); lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, lightmapstyle, lightsurf);
bool hit = false; bool hit = false;
@ -2080,33 +2062,25 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t
} }
} }
} }
}
static void // mxd static void // mxd
LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector<uint8_t> *pvs, raystream_occlusion_t &rs, bool bounce, LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector<uint8_t> *pvs, raystream_occlusion_t &rs,
const vec_t &standard_scale, const vec_t &sky_scale, const float &hotspot_clamp, const qvec3d &surfpoint, const std::vector<surfacelight_t> &surface_lights, const vec_t &standard_scale, const vec_t &sky_scale,
lightgrid_samples_t &result) const float &hotspot_clamp, const qvec3d &surfpoint, lightgrid_samples_t &result)
{ {
const settings::worldspawn_keys &cfg = light_options; const settings::worldspawn_keys &cfg = light_options;
const float surflight_gate = 0.01f; const float surflight_gate = 0.01f;
for (const auto &surf : LightSurfaces()) { for (const surfacelight_t &vpl : surface_lights) {
if (!surf || !surf->vpl) {
continue;
}
const surfacelight_t &vpl = *surf->vpl;
for (int c = 0; c < vpl.points.size(); c++) { for (int c = 0; c < vpl.points.size(); c++) {
if (light_options.visapprox.value() == visapprox_t::VIS && pvs && VisCullEntity(bsp, *pvs, vpl.leaves[c])) { if (light_options.visapprox.value() == visapprox_t::VIS && pvs && VisCullEntity(bsp, *pvs, vpl.leaves[c])) {
continue; continue;
} }
// 1 ray rs.clearPushedRays();
for (auto &vpl_settings : vpl.styles) {
if (vpl_settings.bounce != bounce)
continue;
// 1 ray
{
qvec3f pos = vpl.points[c]; qvec3f pos = vpl.points[c];
qvec3f dir = surfpoint - pos; qvec3f dir = surfpoint - pos;
float dist = qv::length(dir); float dist = qv::length(dir);
@ -2118,8 +2092,6 @@ LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector<uint8_t> *pvs, rays
qvec3f indirect{}; qvec3f indirect{};
rs.clearPushedRays();
for (int axis = 0; axis < 3; ++axis) { for (int axis = 0; axis < 3; ++axis) {
for (int sign = -1; sign <= +1; sign += 2) { for (int sign = -1; sign <= +1; sign += 2) {
@ -2128,8 +2100,8 @@ LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector<uint8_t> *pvs, rays
qvec3f cube_normal{}; qvec3f cube_normal{};
cube_normal[axis] = sign; cube_normal[axis] = sign;
cube_color = GetSurfaceLighting(cfg, vpl, vpl_settings, dir, dist, cube_normal, true, cube_color = GetSurfaceLighting(
standard_scale, sky_scale, hotspot_clamp); cfg, &vpl, dir, dist, cube_normal, true, standard_scale, sky_scale, hotspot_clamp);
#ifdef LIGHTPOINT_TAKE_MAX #ifdef LIGHTPOINT_TAKE_MAX
if (qv::length2(cube_color) > qv::length2(indirect)) { if (qv::length2(cube_color) > qv::length2(indirect)) {
@ -2144,6 +2116,7 @@ LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector<uint8_t> *pvs, rays
if (!qv::gate(indirect, surflight_gate)) { // Each point contributes very little to the final result if (!qv::gate(indirect, surflight_gate)) { // Each point contributes very little to the final result
rs.pushRay(0, pos, dir, dist, &indirect); rs.pushRay(0, pos, dir, dist, &indirect);
} }
}
if (!rs.numPushedRays()) if (!rs.numPushedRays())
continue; continue;
@ -2159,12 +2132,11 @@ LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector<uint8_t> *pvs, rays
Q_assert(!std::isnan(indirect[0])); Q_assert(!std::isnan(indirect[0]));
result.add(indirect, vpl_settings.style); result.add(indirect, vpl.style);
} }
} }
} }
} }
}
static void LightFace_OccludedDebug(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t *lightmaps) static void LightFace_OccludedDebug(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t *lightmaps)
{ {
@ -3353,8 +3325,8 @@ void DirectLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings::
// mxd. Add surface lights... // mxd. Add surface lights...
// FIXME: negative surface lights // FIXME: negative surface lights
LightFace_SurfaceLight( LightFace_SurfaceLight(bsp, &lightsurf, lightmaps, GetSurfaceLights(), cfg.surflightscale.value(),
bsp, &lightsurf, lightmaps, false, cfg.surflightscale.value(), cfg.surflightskyscale.value(), 16.0f); cfg.surflightskyscale.value(), 16.0f);
} }
LightFace_LocalMin(bsp, face, &lightsurf, lightmaps); LightFace_LocalMin(bsp, face, &lightsurf, lightmaps);
@ -3393,8 +3365,8 @@ void IndirectLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings
/* add bounce lighting */ /* add bounce lighting */
// note: scale here is just to keep it close-ish to the old code // note: scale here is just to keep it close-ish to the old code
LightFace_SurfaceLight( LightFace_SurfaceLight(bsp, &lightsurf, lightmaps, BounceLights(), cfg.bouncescale.value() * 0.5,
bsp, &lightsurf, lightmaps, true, cfg.bouncescale.value() * 0.5, cfg.bouncescale.value(), 128.0f); cfg.bouncescale.value(), 128.0f);
} }
} }
} }
@ -3433,10 +3405,9 @@ void PostProcessLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const setti
LightFace_Min(bsp, face, minlight_color, minlight, &lightsurf, lightmaps, 0); LightFace_Min(bsp, face, minlight_color, minlight, &lightsurf, lightmaps, 0);
} }
if (lightsurf.vpl) {
if (auto value = IsSurfaceLitFace(bsp, face)) { if (auto value = IsSurfaceLitFace(bsp, face)) {
auto *entity = std::get<3>(value.value()); auto *entity = std::get<3>(value.value());
float surface_minlight_scale = entity ? entity->surflight_minlight_scale.value() : 1.f; float surface_minlight_scale = entity ? entity->surflight_minlight_scale.value() : 64.f;
surface_minlight_scale *= lightsurf.surflight_minlight_scale; surface_minlight_scale *= lightsurf.surflight_minlight_scale;
if (surface_minlight_scale > 0) { if (surface_minlight_scale > 0) {
@ -3446,7 +3417,6 @@ void PostProcessLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const setti
bsp, face, minlight_color, minlight, &lightsurf, lightmaps, std::get<1>(value.value())); bsp, face, minlight_color, minlight, &lightsurf, lightmaps, std::get<1>(value.value()));
} }
} }
}
if (!modelinfo->isWorld()) { if (!modelinfo->isWorld()) {
LightFace_AutoMin(bsp, face, &lightsurf, lightmaps); LightFace_AutoMin(bsp, face, &lightsurf, lightmaps);
@ -3603,8 +3573,8 @@ lightgrid_samples_t CalcLightgridAtPoint(const mbsp_t *bsp, const qvec3d &world_
// mxd. Add surface lights... // mxd. Add surface lights...
// FIXME: negative surface lights // FIXME: negative surface lights
LightPoint_SurfaceLight( LightPoint_SurfaceLight(bsp, pvs, rs, GetSurfaceLights(), cfg.surflightscale.value(), cfg.surflightskyscale.value(),
bsp, pvs, rs, false, cfg.surflightscale.value(), cfg.surflightskyscale.value(), 16.0f, world_point, result); 16.0f, world_point, result);
#if 0 #if 0
// FIXME: port to lightgrid // FIXME: port to lightgrid
@ -3635,8 +3605,8 @@ lightgrid_samples_t CalcLightgridAtPoint(const mbsp_t *bsp, const qvec3d &world_
/* add bounce lighting */ /* add bounce lighting */
// note: scale here is just to keep it close-ish to the old code // note: scale here is just to keep it close-ish to the old code
LightPoint_SurfaceLight( LightPoint_SurfaceLight(bsp, pvs, rs, BounceLights(), cfg.bouncescale.value() * 0.5, cfg.bouncescale.value(),
bsp, pvs, rs, true, cfg.bouncescale.value() * 0.5, cfg.bouncescale.value(), 128.0f, world_point, result); 128.0f, world_point, result);
LightPoint_ScaleAndClamp(result); LightPoint_ScaleAndClamp(result);

View File

@ -37,13 +37,23 @@ See file, 'COPYING', for details.
#include <common/qvec.hh> #include <common/qvec.hh>
static std::atomic_size_t total_surflight_points; static std::mutex surfacelights_lock;
static std::vector<surfacelight_t> surfacelights;
static std::map<int, std::vector<int>> surfacelightsByFacenum;
static size_t total_surflight_points = 0;
void ResetSurflight() void ResetSurflight()
{ {
surfacelights = {};
surfacelightsByFacenum = {};
total_surflight_points = {}; total_surflight_points = {};
} }
std::vector<surfacelight_t> &GetSurfaceLights()
{
return surfacelights;
}
size_t GetSurflightPoints() size_t GetSurflightPoints()
{ {
return total_surflight_points; return total_surflight_points;
@ -54,14 +64,6 @@ int LightStyleForTargetname(const settings::worldspawn_keys &cfg, const std::str
static void MakeSurfaceLight(const mbsp_t *bsp, const settings::worldspawn_keys &cfg, const mface_t *face, static void MakeSurfaceLight(const mbsp_t *bsp, const settings::worldspawn_keys &cfg, const mface_t *face,
std::optional<qvec3f> texture_color, bool is_directional, bool is_sky, int32_t style, int32_t light_value) std::optional<qvec3f> texture_color, bool is_directional, bool is_sky, int32_t style, int32_t light_value)
{ {
auto &surf_ptr = LightSurfaces()[face - bsp->dfaces.data()];
if (!surf_ptr || !Face_IsEmissive(bsp, face)) {
return;
}
auto &surf = *surf_ptr.get();
// Create face points... // Create face points...
auto poly = Face_Points(bsp, face); auto poly = Face_Points(bsp, face);
const float facearea = qv::PolyArea(poly.begin(), poly.end()); const float facearea = qv::PolyArea(poly.begin(), poly.end());
@ -72,6 +74,38 @@ static void MakeSurfaceLight(const mbsp_t *bsp, const settings::worldspawn_keys
if (facearea < 1) if (facearea < 1)
return; return;
// Create winding...
polylib::winding_t winding = polylib::winding_t::from_winding_points(poly);
auto face_modelinfo = ModelInfoForFace(bsp, face - bsp->dfaces.data());
for (auto &pt : winding) {
pt += face_modelinfo->offset;
}
winding.remove_colinear();
// Get face normal and midpoint...
qvec3d facenormal = Face_Normal(bsp, face);
qvec3d facemidpoint = winding.center() + facenormal; // Lift 1 unit
// Dice winding...
std::vector<qvec3f> points;
size_t points_before_culling = 0;
winding.dice(cfg.surflightsubdivision.value(), [&](polylib::winding_t &w) {
++points_before_culling;
qvec3f point = w.center() + facenormal;
// optimization - cull surface lights in the void
// also try to move them if they're slightly inside a wall
auto [fixed_point, success] = FixLightOnFace(bsp, point, false, 0.5f);
if (!success) {
return;
}
points.push_back(fixed_point);
});
// Calculate emit color and intensity... // Calculate emit color and intensity...
if (extended_flags.surflight_color.has_value()) { if (extended_flags.surflight_color.has_value()) {
@ -103,109 +137,52 @@ static void MakeSurfaceLight(const mbsp_t *bsp, const settings::worldspawn_keys
if (intensity > 1.0f) if (intensity > 1.0f)
texture_color.value() *= 1.0f / intensity; texture_color.value() *= 1.0f / intensity;
if (!surf.vpl) { // Sanity checks...
auto &l = surf.vpl = std::make_unique<surfacelight_t>(); if (points.empty())
return;
// Create winding... // Add surfacelight...
auto winding = polylib::winding_t::from_winding_points(poly); surfacelight_t l;
auto face_modelinfo = ModelInfoForFace(bsp, face - bsp->dfaces.data()); l.surfnormal = facenormal;
l.omnidirectional = !is_directional;
for (auto &pt : winding) { l.points = std::move(points);
pt += face_modelinfo->offset; if (extended_flags.surflight_targetname) {
l.style = LightStyleForTargetname(cfg, extended_flags.surflight_targetname.value());
} else if (extended_flags.surflight_style) {
l.style = extended_flags.surflight_style.value();
} else {
l.style = style;
} }
l.rescale = extended_flags.surflight_rescale;
winding.remove_colinear(); l.minlight_scale = extended_flags.surflight_minlight_scale;
// Get face normal and midpoint...
l->surfnormal = Face_Normal(bsp, face);
l->pos = winding.center() + l->surfnormal; // Lift 1 unit
// Dice winding...
l->points_before_culling = 0;
if (light_options.emissivequality.value() == emissivequality_t::LOW ||
light_options.emissivequality.value() == emissivequality_t::MEDIUM) {
l->points = {l->pos};
l->points_before_culling++;
total_surflight_points++;
if (light_options.emissivequality.value() == emissivequality_t::MEDIUM) {
for (auto &pt : winding) {
l->points_before_culling++;
auto point = pt + l->surfnormal;
auto diff = qv::normalize(l->pos - pt);
point += diff;
// optimization - cull surface lights in the void
// also try to move them if they're slightly inside a wall
auto [fixed_point, success] = FixLightOnFace(bsp, point, false, 0.5f);
if (!success) {
continue;
}
l->points.push_back(fixed_point);
total_surflight_points++;
}
}
} else {
winding.dice(cfg.surflightsubdivision.value(), [&](polylib::winding_t &w) {
++l->points_before_culling;
qvec3f point = w.center() + l->surfnormal;
// optimization - cull surface lights in the void
// also try to move them if they're slightly inside a wall
auto [fixed_point, success] = FixLightOnFace(bsp, point, false, 0.5f);
if (!success) {
return;
}
l->points.push_back(fixed_point);
++total_surflight_points;
});
}
l->minlight_scale = extended_flags.surflight_minlight_scale;
// Init bbox... // Init bbox...
if (light_options.visapprox.value() == visapprox_t::RAYS) { if (light_options.visapprox.value() == visapprox_t::RAYS) {
l->bounds = EstimateVisibleBoundsAtPoint(l->pos); l.bounds = EstimateVisibleBoundsAtPoint(facemidpoint);
} }
for (auto &pt : l->points) { for (auto &pt : l.points) {
if (light_options.visapprox.value() == visapprox_t::VIS) { if (light_options.visapprox.value() == visapprox_t::VIS) {
l->leaves.push_back(Light_PointInLeaf(bsp, pt)); l.leaves.push_back(Light_PointInLeaf(bsp, pt));
} else if (light_options.visapprox.value() == visapprox_t::RAYS) { } else if (light_options.visapprox.value() == visapprox_t::RAYS) {
l->bounds += EstimateVisibleBoundsAtPoint(pt); l.bounds += EstimateVisibleBoundsAtPoint(pt);
} }
} }
}
auto &l = surf.vpl; l.pos = facemidpoint;
// Sanity checks...
if (l->points.empty()) {
return;
}
// Add surfacelight...
auto &setting = l->styles.emplace_back();
setting.omnidirectional = !is_directional;
if (extended_flags.surflight_targetname) {
setting.style = LightStyleForTargetname(cfg, extended_flags.surflight_targetname.value());
} else if (extended_flags.surflight_style) {
setting.style = extended_flags.surflight_style.value();
} else {
setting.style = style;
}
setting.rescale = extended_flags.surflight_rescale;
// Store surfacelight settings... // Store surfacelight settings...
setting.totalintensity = intensity * facearea; l.totalintensity = intensity * facearea;
setting.intensity = setting.totalintensity / l->points_before_culling; l.intensity = l.totalintensity / points_before_culling;
setting.color = texture_color.value(); l.color = texture_color.value();
// Store light...
std::unique_lock<std::mutex> lck{surfacelights_lock};
total_surflight_points += l.points.size();
surfacelights.push_back(l);
const int index = static_cast<int>(surfacelights.size()) - 1;
surfacelightsByFacenum[Face_GetNum(bsp, face)].push_back(index);
} }
std::optional<std::tuple<int32_t, int32_t, qvec3d, light_t *>> IsSurfaceLitFace(const mbsp_t *bsp, const mface_t *face) std::optional<std::tuple<int32_t, int32_t, qvec3d, light_t *>> IsSurfaceLitFace(const mbsp_t *bsp, const mface_t *face)
@ -274,6 +251,17 @@ static void MakeSurfaceLightsThread(const mbsp_t *bsp, const settings::worldspaw
} }
} }
// No surflight_debug (yet?), so unused...
const std::vector<int> &SurfaceLightsForFaceNum(int facenum)
{
const auto &vec = surfacelightsByFacenum.find(facenum);
if (vec != surfacelightsByFacenum.end())
return vec->second;
static std::vector<int> empty;
return empty;
}
void // Quake 2 surface lights void // Quake 2 surface lights
MakeRadiositySurfaceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp) MakeRadiositySurfaceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp)
{ {
@ -282,7 +270,7 @@ MakeRadiositySurfaceLights(const settings::worldspawn_keys &cfg, const mbsp_t *b
logging::parallel_for( logging::parallel_for(
static_cast<size_t>(0), bsp->dfaces.size(), [&](size_t i) { MakeSurfaceLightsThread(bsp, cfg, i); }); static_cast<size_t>(0), bsp->dfaces.size(), [&](size_t i) { MakeSurfaceLightsThread(bsp, cfg, i); });
/*if (surfacelights.size()) { if (surfacelights.size()) {
logging::print("{} surface lights ({} light points) in use.\n", surfacelights.size(), total_surflight_points); logging::print("{} surface lights ({} light points) in use.\n", surfacelights.size(), total_surflight_points);
}*/ }
} }