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

This reverts commit 2e0e23622b.

Disable rescale by default on sky faces.
Light is now in control of rescales' default value.
Multiply omni light faces by 0.5 to better match qrad3
Remove some asserts to increase perf
This commit is contained in:
Jonathan 2023-09-04 02:51:20 -04:00
parent 1262ce3f78
commit 7d881768fa
10 changed files with 257 additions and 203 deletions

View File

@ -152,7 +152,7 @@ struct surfflags_t
// if true, rescales any surface light emitted by these brushes to emit 50% light at 90 degrees from the surface
// normal if false, use a more natural angle falloff of 0% at 90 degrees
bool surflight_rescale = true;
std::optional<bool> surflight_rescale;
// override surface lighting style
std::optional<int32_t> surflight_style;

View File

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

View File

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

View File

@ -39,33 +39,40 @@ struct surfacelight_t
{
qvec3d pos;
qvec3f surfnormal;
/**
* 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;
std::vector<qvec3f> points;
std::vector<const mleaf_t *> leaves;
// Surface light settings...
float intensity; // Surface light strength for each point
float totalintensity; // Total surface light strength
qvec3d color; // Surface color
size_t points_before_culling;
// Estimated visible AABB culling
aabb3d bounds;
int32_t style;
// rescale faces to account for perpendicular lights
bool rescale;
std::optional<vec_t> minlight_scale;
std::vector<qvec3f> points;
std::vector<const mleaf_t *> leaves;
// Surface light settings...
struct per_style_t
{
bool bounce = false; // whether this is a direct or indirect emission
/**
* 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
std::vector<per_style_t> styles;
};
class light_t;
void ResetSurflight();
std::vector<surfacelight_t> &GetSurfaceLights();
size_t GetSurflightPoints();
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);

View File

@ -39,13 +39,10 @@
#include <common/qvec.hh>
#include <common/parallel.hh>
std::mutex bouncelights_lock;
static std::vector<surfacelight_t> bouncelights;
static std::atomic_size_t bouncelightpoints;
void ResetBounce()
{
bouncelights.clear();
bouncelightpoints = 0;
}
@ -88,16 +85,14 @@ static bool Face_ShouldBounce(const mbsp_t *bsp, const mface_t *face)
return true;
}
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,
static void MakeBounceLight(const mbsp_t *bsp, const settings::worldspawn_keys &cfg, lightsurf_t &surf,
qvec3d texture_color, int32_t style, std::vector<qvec3f> &points,
const vec_t &area, const qvec3d &facenormal, const qvec3d &facemidpoint)
{
if (!Face_IsEmissive(bsp, face)) {
if (!Face_IsEmissive(bsp, surf.face)) {
return;
}
bouncelightpoints += points.size();
// Calculate emit color and intensity...
// Calculate intensity...
@ -107,50 +102,48 @@ static void MakeBounceLight(const mbsp_t *bsp, const settings::worldspawn_keys &
return;
}
// Normalize color...
if (intensity > 1.0) {
texture_color *= 1.0 / intensity;
}
// Normalize color...
if (intensity > 1.0) {
texture_color *= 1.0 / intensity;
}
if (!surf.vpl) {
auto &l = surf.vpl = std::make_unique<surfacelight_t>();
// Sanity checks...
Q_assert(!points.empty());
// Add surfacelight...
surfacelight_t l;
l.surfnormal = facenormal;
l.omnidirectional = false;
l.points = points;
l.style = style;
l->surfnormal = facenormal;
l->points = std::move(points);
// Init bbox...
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) {
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) {
l.bounds += EstimateVisibleBoundsAtPoint(pt);
l->bounds += EstimateVisibleBoundsAtPoint(pt);
}
}
l.pos = facemidpoint;
l->pos = facemidpoint;
}
// Store surfacelight settings...
l.totalintensity = intensity * area;
l.intensity = l.totalintensity / l.points.size();
l.color = texture_color;
// Store light...
std::unique_lock<std::mutex> lck{bouncelights_lock};
bouncelights.push_back(l);
}
const std::vector<surfacelight_t> &BounceLights()
{
return bouncelights;
auto &l = surf.vpl;
auto &setting = l->styles.emplace_back();
setting.bounce = true;
setting.style = style;
setting.totalintensity = intensity * area;
setting.intensity = setting.totalintensity / l->points.size();
setting.color = texture_color;
}
}
static void MakeBounceLightsThread(const settings::worldspawn_keys &cfg, const mbsp_t *bsp, const mface_t &face)
{
@ -245,8 +238,7 @@ static void MakeBounceLightsThread(const settings::worldspawn_keys &cfg, const m
}
for (auto &style : emitcolors) {
MakeBounceLight(
bsp, cfg, &face, style.second, style.first, points, winding, area, facenormal, facemidpoint);
MakeBounceLight(bsp, cfg, surf, style.second, style.first, points, area, facenormal, facemidpoint);
}
}
@ -256,5 +248,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::print("{} bounce lights created, with {} points\n", bouncelights.size(), bouncelightpoints);
// logging::print("{} bounce lights created, with {} points\n", bouncelights.size(), bouncelightpoints);
}

View File

@ -745,11 +745,15 @@ static void SaveLightmapSurfaces(mbsp_t *bsp)
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);
}
light_surfaces[i].reset();
});
}
void ClearLightmapSurfaces(mbsp_t *bsp)
{
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)
{
Q_assert(modelinfo.size() == 0);
@ -1595,6 +1599,8 @@ int light_main(int argc, const char **argv)
LightGrid(&bspdata);
ClearLightmapSurfaces(&std::get<mbsp_t>(bspdata.bsp));
// invalidate normals
bspdata.bspx.entries.erase("FACENORMALS");

View File

@ -26,7 +26,6 @@
#include <light/entities.hh>
#include <light/lightgrid.hh>
#include <light/trace.hh>
#include <light/bounce.hh>
#include <light/litfile.hh> // for facesup_t
#include <common/imglib.hh>
@ -1018,13 +1017,22 @@ constexpr vec_t SQR(vec_t x)
}
// CHECK: naming? why clamp*min*?
constexpr void Light_ClampMin(lightsample_t &sample, const vec_t light, const qvec3d &color)
constexpr bool Light_ClampMin(lightsample_t &sample, const vec_t light, const qvec3d &color)
{
bool changed = false;
for (int i = 0; i < 3; i++) {
sample.color[i] = std::max(sample.color[i], (float)(color[i] * (light / 255.0f)));
float c = (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)
{
if (val >= max)
@ -1668,14 +1676,13 @@ static void LightFace_Min(const mbsp_t *bsp, const mface_t *face, const qvec3d &
}
if (cfg.addminlight.value()) {
sample.color += color * (value / 255.0);
hit = true;
} else {
if (lightsurf->minlightMottle) {
value += Mottle(surf_sample.point);
}
Light_ClampMin(sample, value, color);
hit = Light_ClampMin(sample, value, color) || hit;
}
hit = true;
}
if (hit) {
@ -1751,11 +1758,11 @@ static void LightFace_LocalMin(
cfg, lightsurf->samples[i].occlusion, entity.get(), 0.0 /* TODO: pass distance */, lightsurf);
if (cfg.addminlight.value()) {
sample.color += entity->color.value() * (value / 255.0);
hit = true;
} else {
Light_ClampMin(sample, value, entity->color.value());
hit = Light_ClampMin(sample, value, entity->color.value()) || hit;
}
hit = true;
total_light_ray_hits++;
}
@ -1898,7 +1905,7 @@ static void LightFace_DebugMottle(const mbsp_t *bsp, const lightsurf_t *lightsur
}
// mxd. Surface light falloff. Returns color in [0,255]
inline qvec3f SurfaceLight_ColorAtDist(const settings::worldspawn_keys &cfg, const float &surf_scale,
constexpr 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)
{
// Exponential falloff
@ -1911,25 +1918,25 @@ inline qvec3f SurfaceLight_ColorAtDist(const settings::worldspawn_keys &cfg, con
// dir: vpl -> sample point direction
// mxd. returns color in [0,255]
inline qvec3f GetSurfaceLighting(const settings::worldspawn_keys &cfg, const surfacelight_t *vpl, const qvec3f &dir,
const float dist, const qvec3f &normal, bool use_normal, const vec_t &standard_scale, const vec_t &sky_scale,
const float &hotspot_clamp)
inline qvec3f GetSurfaceLighting(const settings::worldspawn_keys &cfg, const surfacelight_t &vpl,
const surfacelight_t::per_style_t &vpl_settings, const qvec3f &dir, const float dist, const qvec3f &normal,
bool use_normal, const vec_t &standard_scale, const vec_t &sky_scale, const float &hotspot_clamp)
{
qvec3f result;
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;
float dp2 = use_normal ? qv::dot(sp_vpl, normal) : 1.0f;
if (!vpl->omnidirectional) {
if (!vpl_settings.omnidirectional) {
if (dp1 < -LIGHT_ANGLE_EPSILON)
return {0}; // sample point behind vpl
if (dp2 < -LIGHT_ANGLE_EPSILON)
return {0}; // vpl behind sample face
// Rescale a bit to brighten the faces nearly-perpendicular to the surface light plane...
if (vpl->rescale) {
if (vpl_settings.rescale) {
dp1 = 0.5f + dp1 * 0.5f;
dp2 = 0.5f + dp2 * 0.5f;
}
@ -1937,25 +1944,25 @@ inline qvec3f GetSurfaceLighting(const settings::worldspawn_keys &cfg, const sur
dotProductFactor = dp1 * dp2;
} else {
// used for sky face surface lights
dotProductFactor = dp2;
dotProductFactor = dp2 * 0.5f;
}
dotProductFactor = std::max(0.0f, dotProductFactor);
// Get light contribution
result = SurfaceLight_ColorAtDist(
cfg, vpl->omnidirectional ? sky_scale : standard_scale, vpl->intensity, vpl->color, dist, hotspot_clamp);
result = SurfaceLight_ColorAtDist(cfg, vpl_settings.omnidirectional ? sky_scale : standard_scale,
vpl_settings.intensity, vpl_settings.color, dist, hotspot_clamp);
// Apply angle scale
const qvec3f resultscaled = result * dotProductFactor;
Q_assert(!std::isnan(resultscaled[0]) && !std::isnan(resultscaled[1]) && !std::isnan(resultscaled[2]));
//Q_assert(!std::isnan(resultscaled[0]) && !std::isnan(resultscaled[1]) && !std::isnan(resultscaled[2]));
return resultscaled;
}
static bool // mxd
SurfaceLight_SphereCull(
const surfacelight_t *vpl, const lightsurf_t *lightsurf, const vec_t &bouncelight_gate, const float &hotspot_clamp)
SurfaceLight_SphereCull(const surfacelight_t *vpl, const lightsurf_t *lightsurf,
const surfacelight_t::per_style_t &vpl_settings, const vec_t &bouncelight_gate, const float &hotspot_clamp)
{
if (light_options.visapprox.value() == visapprox_t::RAYS &&
vpl->bounds.disjoint(lightsurf->extents.bounds, 0.001)) {
@ -1967,17 +1974,16 @@ SurfaceLight_SphereCull(
const float dist = qv::length(dir) + lightsurf->extents.radius;
// Get light contribution
const qvec3f color =
SurfaceLight_ColorAtDist(cfg, vpl->omnidirectional ? cfg.surflightskyscale.value() : cfg.surflightscale.value(),
vpl->totalintensity, vpl->color, dist, hotspot_clamp);
const qvec3f color = SurfaceLight_ColorAtDist(cfg,
vpl_settings.omnidirectional ? cfg.surflightskyscale.value() : cfg.surflightscale.value(),
vpl_settings.totalintensity, vpl_settings.color, dist, hotspot_clamp);
return qv::gate(color, (float)bouncelight_gate);
}
static void // mxd
LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t *lightmaps,
const std::vector<surfacelight_t> &surface_lights, const vec_t &standard_scale, const vec_t &sky_scale,
const float &hotspot_clamp)
LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t *lightmaps, bool bounce,
const vec_t &standard_scale, const vec_t &sky_scale, const float &hotspot_clamp)
{
const settings::worldspawn_keys &cfg = *lightsurf->cfg;
const float surflight_gate = 0.01f;
@ -1987,9 +1993,21 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t
return;
}
for (const surfacelight_t &vpl : surface_lights) {
if (SurfaceLight_SphereCull(&vpl, lightsurf, surflight_gate, hotspot_clamp))
for (const auto &surf_ptr : LightSurfaces()) {
if (!surf_ptr || !surf_ptr->vpl) {
// didn't emit anthing
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;
@ -2025,8 +2043,8 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t
dir /= dist;
}
const qvec3f indirect = GetSurfaceLighting(
cfg, &vpl, dir, dist, lightsurf_normal, use_normal, standard_scale, sky_scale, hotspot_clamp);
const qvec3f indirect = GetSurfaceLighting(cfg, vpl, vpl_setting, 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
rs.pushRay(i, pos, dir, dist, &indirect);
}
@ -2038,7 +2056,7 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t
total_surflight_rays += rs.numPushedRays();
rs.tracePushedRaysOcclusion(lightsurf->modelinfo, CHANNEL_MASK_DEFAULT);
const int lightmapstyle = vpl.style;
const int lightmapstyle = vpl_setting.style;
lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, lightmapstyle, lightsurf);
bool hit = false;
@ -2050,7 +2068,7 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t
const int i = rs.getPushedRayPointIndex(j);
qvec3f indirect = rs.getPushedRayColor(j);
Q_assert(!std::isnan(indirect[0]));
//Q_assert(!std::isnan(indirect[0]));
// Use dirt scaling on the surface lighting.
const vec_t dirtscale =
@ -2070,25 +2088,33 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t
}
}
}
}
static void // mxd
LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector<uint8_t> *pvs, raystream_occlusion_t &rs,
const std::vector<surfacelight_t> &surface_lights, const vec_t &standard_scale, const vec_t &sky_scale,
const float &hotspot_clamp, const qvec3d &surfpoint, lightgrid_samples_t &result)
LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector<uint8_t> *pvs, raystream_occlusion_t &rs, bool bounce,
const vec_t &standard_scale, const vec_t &sky_scale, const float &hotspot_clamp, const qvec3d &surfpoint,
lightgrid_samples_t &result)
{
const settings::worldspawn_keys &cfg = light_options;
const float surflight_gate = 0.01f;
for (const surfacelight_t &vpl : surface_lights) {
for (const auto &surf : LightSurfaces()) {
if (!surf || !surf->vpl) {
continue;
}
const surfacelight_t &vpl = *surf->vpl;
for (int c = 0; c < vpl.points.size(); c++) {
if (light_options.visapprox.value() == visapprox_t::VIS && pvs && VisCullEntity(bsp, *pvs, vpl.leaves[c])) {
continue;
}
rs.clearPushedRays();
// 1 ray
{
for (auto &vpl_settings : vpl.styles) {
if (vpl_settings.bounce != bounce)
continue;
qvec3f pos = vpl.points[c];
qvec3f dir = surfpoint - pos;
float dist = qv::length(dir);
@ -2100,6 +2126,8 @@ LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector<uint8_t> *pvs, rays
qvec3f indirect{};
rs.clearPushedRays();
for (int axis = 0; axis < 3; ++axis) {
for (int sign = -1; sign <= +1; sign += 2) {
@ -2108,8 +2136,8 @@ LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector<uint8_t> *pvs, rays
qvec3f cube_normal{};
cube_normal[axis] = sign;
cube_color = GetSurfaceLighting(
cfg, &vpl, dir, dist, cube_normal, true, standard_scale, sky_scale, hotspot_clamp);
cube_color = GetSurfaceLighting(cfg, vpl, vpl_settings, dir, dist, cube_normal, true,
standard_scale, sky_scale, hotspot_clamp);
#ifdef LIGHTPOINT_TAKE_MAX
if (qv::length2(cube_color) > qv::length2(indirect)) {
@ -2124,7 +2152,6 @@ 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
rs.pushRay(0, pos, dir, dist, &indirect);
}
}
if (!rs.numPushedRays())
continue;
@ -2138,13 +2165,14 @@ LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector<uint8_t> *pvs, rays
qvec3f indirect = rs.getPushedRayColor(j);
Q_assert(!std::isnan(indirect[0]));
//Q_assert(!std::isnan(indirect[0]));
result.add(indirect, vpl.style);
result.add(indirect, vpl_settings.style);
}
}
}
}
}
static void LightFace_OccludedDebug(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t *lightmaps)
{
@ -3333,8 +3361,8 @@ void DirectLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings::
// mxd. Add surface lights...
// FIXME: negative surface lights
LightFace_SurfaceLight(bsp, &lightsurf, lightmaps, GetSurfaceLights(), cfg.surflightscale.value(),
cfg.surflightskyscale.value(), 16.0f);
LightFace_SurfaceLight(
bsp, &lightsurf, lightmaps, false, cfg.surflightscale.value(), cfg.surflightskyscale.value(), 16.0f);
}
LightFace_LocalMin(bsp, face, &lightsurf, lightmaps);
@ -3373,8 +3401,8 @@ void IndirectLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const settings
/* add bounce lighting */
// note: scale here is just to keep it close-ish to the old code
LightFace_SurfaceLight(bsp, &lightsurf, lightmaps, BounceLights(), cfg.bouncescale.value() * 0.5,
cfg.bouncescale.value(), 128.0f);
LightFace_SurfaceLight(
bsp, &lightsurf, lightmaps, true, cfg.bouncescale.value() * 0.5, cfg.bouncescale.value(), 128.0f);
}
}
}
@ -3413,9 +3441,10 @@ void PostProcessLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const setti
LightFace_Min(bsp, face, minlight_color, minlight, &lightsurf, lightmaps, 0);
}
if (lightsurf.vpl) {
if (auto value = IsSurfaceLitFace(bsp, face)) {
auto *entity = std::get<3>(value.value());
float surface_minlight_scale = entity ? entity->surflight_minlight_scale.value() : 64.f;
float surface_minlight_scale = entity ? entity->surflight_minlight_scale.value() : 1.f;
surface_minlight_scale *= lightsurf.surflight_minlight_scale;
if (surface_minlight_scale > 0) {
@ -3425,6 +3454,7 @@ void PostProcessLightFace(const mbsp_t *bsp, lightsurf_t &lightsurf, const setti
bsp, face, minlight_color, minlight, &lightsurf, lightmaps, std::get<1>(value.value()));
}
}
}
if (!modelinfo->isWorld()) {
LightFace_AutoMin(bsp, face, &lightsurf, lightmaps);
@ -3581,8 +3611,8 @@ lightgrid_samples_t CalcLightgridAtPoint(const mbsp_t *bsp, const qvec3d &world_
// mxd. Add surface lights...
// FIXME: negative surface lights
LightPoint_SurfaceLight(bsp, pvs, rs, GetSurfaceLights(), cfg.surflightscale.value(), cfg.surflightskyscale.value(),
16.0f, world_point, result);
LightPoint_SurfaceLight(
bsp, pvs, rs, false, cfg.surflightscale.value(), cfg.surflightskyscale.value(), 16.0f, world_point, result);
#if 0
// FIXME: port to lightgrid
@ -3613,8 +3643,8 @@ lightgrid_samples_t CalcLightgridAtPoint(const mbsp_t *bsp, const qvec3d &world_
/* add bounce lighting */
// note: scale here is just to keep it close-ish to the old code
LightPoint_SurfaceLight(bsp, pvs, rs, BounceLights(), cfg.bouncescale.value() * 0.5, cfg.bouncescale.value(),
128.0f, world_point, result);
LightPoint_SurfaceLight(
bsp, pvs, rs, true, cfg.bouncescale.value() * 0.5, cfg.bouncescale.value(), 128.0f, world_point, result);
LightPoint_ScaleAndClamp(result);

View File

@ -37,23 +37,13 @@ See file, 'COPYING', for details.
#include <common/qvec.hh>
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;
static std::atomic_size_t total_surflight_points;
void ResetSurflight()
{
surfacelights = {};
surfacelightsByFacenum = {};
total_surflight_points = {};
}
std::vector<surfacelight_t> &GetSurfaceLights()
{
return surfacelights;
}
size_t GetSurflightPoints()
{
return total_surflight_points;
@ -64,6 +54,14 @@ 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,
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...
auto poly = Face_Points(bsp, face);
const float facearea = qv::PolyArea(poly.begin(), poly.end());
@ -74,38 +72,6 @@ static void MakeSurfaceLight(const mbsp_t *bsp, const settings::worldspawn_keys
if (facearea < 1)
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...
if (extended_flags.surflight_color.has_value()) {
@ -137,52 +103,113 @@ static void MakeSurfaceLight(const mbsp_t *bsp, const settings::worldspawn_keys
if (intensity > 1.0f)
texture_color.value() *= 1.0f / intensity;
// Sanity checks...
if (points.empty())
return;
if (!surf.vpl) {
auto &l = surf.vpl = std::make_unique<surfacelight_t>();
// Add surfacelight...
surfacelight_t l;
l.surfnormal = facenormal;
l.omnidirectional = !is_directional;
l.points = std::move(points);
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;
// Create winding...
auto 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;
}
l.rescale = extended_flags.surflight_rescale;
l.minlight_scale = extended_flags.surflight_minlight_scale;
winding.remove_colinear();
// 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...
if (light_options.visapprox.value() == visapprox_t::RAYS) {
l.bounds = EstimateVisibleBoundsAtPoint(facemidpoint);
l->bounds = EstimateVisibleBoundsAtPoint(l->pos);
}
for (auto &pt : l.points) {
for (auto &pt : l->points) {
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) {
l.bounds += EstimateVisibleBoundsAtPoint(pt);
l->bounds += EstimateVisibleBoundsAtPoint(pt);
}
}
}
l.pos = facemidpoint;
auto &l = surf.vpl;
// 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;
}
if (extended_flags.surflight_rescale) {
setting.rescale = extended_flags.surflight_rescale.value();
} else {
setting.rescale = is_sky ? false : true;
}
// Store surfacelight settings...
l.totalintensity = intensity * facearea;
l.intensity = l.totalintensity / points_before_culling;
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);
setting.totalintensity = intensity * facearea;
setting.intensity = setting.totalintensity / l->points_before_culling;
setting.color = texture_color.value();
}
std::optional<std::tuple<int32_t, int32_t, qvec3d, light_t *>> IsSurfaceLitFace(const mbsp_t *bsp, const mface_t *face)
@ -251,17 +278,6 @@ 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
MakeRadiositySurfaceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp)
{
@ -270,7 +286,7 @@ MakeRadiositySurfaceLights(const settings::worldspawn_keys &cfg, const mbsp_t *b
logging::parallel_for(
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);
}
}*/
}

View File

@ -678,8 +678,9 @@ static surfflags_t SurfFlagsForEntity(
flags.no_minlight = true;
if (entity.epairs.get_int("_lightignore") == 1)
flags.light_ignore = true;
if (entity.epairs.has("_surflight_rescale") && entity.epairs.get_int("_surflight_rescale") == 0)
flags.surflight_rescale = false;
if (entity.epairs.has("_surflight_rescale")) {
flags.surflight_rescale = entity.epairs.get_int("_surflight_rescale") == 1;
}
{
qvec3d color;
// FIXME: get_color, to match settings

View File

@ -381,8 +381,8 @@ static void WriteExtendedTexinfoFlags(void)
if (tx.flags.light_ignore) {
t["light_ignore"] = tx.flags.light_ignore;
}
if (tx.flags.surflight_rescale == false) {
t["surflight_rescale"] = tx.flags.surflight_rescale;
if (tx.flags.surflight_rescale) {
t["surflight_rescale"] = tx.flags.surflight_rescale.value();
}
if (tx.flags.surflight_style.has_value()) {
t["surflight_style"] = tx.flags.surflight_style.value();