reduce memory usage by only storing VPLs when we need to, and only once
fix visapprox auto not actually being auto
This commit is contained in:
parent
da2e6936d1
commit
fcf39b2ef8
|
|
@ -33,5 +33,4 @@
|
||||||
// public functions
|
// public functions
|
||||||
|
|
||||||
void ResetBounce();
|
void ResetBounce();
|
||||||
const std::vector<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);
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,8 @@ public:
|
||||||
|
|
||||||
using lightmapdict_t = std::vector<lightmap_t>;
|
using lightmapdict_t = std::vector<lightmap_t>;
|
||||||
|
|
||||||
|
struct surfacelight_t;
|
||||||
|
|
||||||
struct lightsurf_t
|
struct lightsurf_t
|
||||||
{
|
{
|
||||||
const settings::worldspawn_keys *cfg;
|
const settings::worldspawn_keys *cfg;
|
||||||
|
|
@ -148,6 +150,9 @@ struct lightsurf_t
|
||||||
raystream_intersection_t intersection_stream;
|
raystream_intersection_t intersection_stream;
|
||||||
|
|
||||||
lightmapdict_t lightmapsByStyle;
|
lightmapdict_t lightmapsByStyle;
|
||||||
|
|
||||||
|
// surface light stuff
|
||||||
|
std::unique_ptr<surfacelight_t> vpl;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* debug */
|
/* debug */
|
||||||
|
|
|
||||||
|
|
@ -27,33 +27,40 @@ 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,
|
|
||||||
* 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
|
|
||||||
|
|
||||||
// Estimated visible AABB culling
|
// Estimated visible AABB culling
|
||||||
aabb3d bounds;
|
aabb3d bounds;
|
||||||
|
|
||||||
int32_t style;
|
|
||||||
|
|
||||||
// rescale faces to account for perpendicular lights
|
|
||||||
bool rescale;
|
|
||||||
std::optional<vec_t> minlight_scale;
|
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;
|
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);
|
||||||
|
|
|
||||||
|
|
@ -40,13 +40,10 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace polylib;
|
using namespace polylib;
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,7 +86,7 @@ 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, const mface_t *face,
|
static void MakeBounceLight(const mbsp_t *bsp, const settings::worldspawn_keys &cfg, lightsurf_t &surf,
|
||||||
qvec3d texture_color, int32_t style, const std::vector<qvec3f> &points, const winding_t &winding, const vec_t &area,
|
qvec3d texture_color, int32_t style, const std::vector<qvec3f> &points, const winding_t &winding, const vec_t &area,
|
||||||
const qvec3d &facenormal, const qvec3d &facemidpoint)
|
const qvec3d &facenormal, const qvec3d &facemidpoint)
|
||||||
{
|
{
|
||||||
|
|
@ -104,49 +101,47 @@ static void MakeBounceLight(const mbsp_t *bsp, const settings::worldspawn_keys &
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize color...
|
if (!surf.vpl) {
|
||||||
if (intensity > 1.0) {
|
auto &l = surf.vpl = std::make_unique<surfacelight_t>();
|
||||||
texture_color *= 1.0 / intensity;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sanity checks...
|
// Normalize color...
|
||||||
Q_assert(!points.empty());
|
if (intensity > 1.0) {
|
||||||
|
texture_color *= 1.0 / intensity;
|
||||||
// Add surfacelight...
|
|
||||||
surfacelight_t l;
|
|
||||||
l.surfnormal = facenormal;
|
|
||||||
l.omnidirectional = false;
|
|
||||||
l.points = points;
|
|
||||||
l.style = style;
|
|
||||||
|
|
||||||
// Init bbox...
|
|
||||||
if (light_options.visapprox.value() == visapprox_t::RAYS) {
|
|
||||||
l.bounds = EstimateVisibleBoundsAtPoint(facemidpoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &pt : l.points) {
|
|
||||||
if (light_options.visapprox.value() == visapprox_t::VIS) {
|
|
||||||
l.leaves.push_back(Light_PointInLeaf(bsp, pt));
|
|
||||||
} else if (light_options.visapprox.value() == visapprox_t::RAYS) {
|
|
||||||
l.bounds += EstimateVisibleBoundsAtPoint(pt);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
l.pos = facemidpoint;
|
// Sanity checks...
|
||||||
|
Q_assert(!points.empty());
|
||||||
|
|
||||||
|
// Add surfacelight...
|
||||||
|
l->surfnormal = facenormal;
|
||||||
|
l->points = points;
|
||||||
|
|
||||||
|
// Init bbox...
|
||||||
|
if (light_options.visapprox.value() == visapprox_t::RAYS) {
|
||||||
|
l->bounds = EstimateVisibleBoundsAtPoint(facemidpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &pt : l->points) {
|
||||||
|
if (light_options.visapprox.value() == visapprox_t::VIS) {
|
||||||
|
l->leaves.push_back(Light_PointInLeaf(bsp, pt));
|
||||||
|
} else if (light_options.visapprox.value() == visapprox_t::RAYS) {
|
||||||
|
l->bounds += EstimateVisibleBoundsAtPoint(pt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
l->pos = facemidpoint;
|
||||||
|
}
|
||||||
|
|
||||||
// Store surfacelight settings...
|
// Store surfacelight settings...
|
||||||
l.totalintensity = intensity * area;
|
{
|
||||||
l.intensity = l.totalintensity / l.points.size();
|
auto &l = surf.vpl;
|
||||||
l.color = texture_color;
|
auto &setting = l->styles.emplace_back();
|
||||||
|
setting.bounce = true;
|
||||||
// Store light...
|
setting.style = style;
|
||||||
unique_lock<mutex> lck{bouncelights_lock};
|
setting.totalintensity = intensity * area;
|
||||||
bouncelights.push_back(l);
|
setting.intensity = setting.totalintensity / l->points.size();
|
||||||
}
|
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)
|
||||||
|
|
@ -229,7 +224,7 @@ static void MakeBounceLightsThread(const settings::worldspawn_keys &cfg, const m
|
||||||
|
|
||||||
for (auto &style : emitcolors) {
|
for (auto &style : emitcolors) {
|
||||||
MakeBounceLight(
|
MakeBounceLight(
|
||||||
bsp, cfg, &face, style.second, style.first, points, winding, area, facenormal, facemidpoint);
|
bsp, cfg, surf, style.second, style.first, points, winding, area, facenormal, facemidpoint);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
vector<qvec3f> points;
|
vector<qvec3f> points;
|
||||||
|
|
@ -238,7 +233,7 @@ static void MakeBounceLightsThread(const settings::worldspawn_keys &cfg, const m
|
||||||
|
|
||||||
for (auto &style : emitcolors) {
|
for (auto &style : emitcolors) {
|
||||||
MakeBounceLight(
|
MakeBounceLight(
|
||||||
bsp, cfg, &face, style.second, style.first, points, winding, area, facenormal, facemidpoint);
|
bsp, cfg, surf, style.second, style.first, points, winding, area, facenormal, facemidpoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -249,5 +244,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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -738,7 +738,13 @@ 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)
|
||||||
|
{
|
||||||
|
logging::funcheader();
|
||||||
|
logging::parallel_for(static_cast<size_t>(0), bsp->dfaces.size(), [&bsp](size_t i) {
|
||||||
light_surfaces[i].reset();
|
light_surfaces[i].reset();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -1537,7 +1543,11 @@ 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) {
|
||||||
light_options.visapprox.set_value(visapprox_t::RAYS, settings::source::DEFAULT);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
img::load_textures(&bsp, light_options);
|
img::load_textures(&bsp, light_options);
|
||||||
|
|
@ -1581,6 +1591,8 @@ 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");
|
||||||
|
|
||||||
|
|
|
||||||
249
light/ltface.cc
249
light/ltface.cc
|
|
@ -1009,11 +1009,20 @@ constexpr vec_t SQR(vec_t x)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CHECK: naming? why clamp*min*?
|
// 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++) {
|
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)
|
constexpr vec_t fraction(const vec_t &min, const vec_t &val, const vec_t &max)
|
||||||
|
|
@ -1654,14 +1663,13 @@ 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(lightsurf->points[i]);
|
value += Mottle(lightsurf->points[i]);
|
||||||
}
|
}
|
||||||
Light_ClampMin(sample, value, color);
|
hit = Light_ClampMin(sample, value, color) || hit;
|
||||||
}
|
}
|
||||||
|
|
||||||
hit = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hit) {
|
if (hit) {
|
||||||
|
|
@ -1735,11 +1743,11 @@ static void LightFace_LocalMin(
|
||||||
cfg, lightsurf->occlusion[i], entity.get(), 0.0 /* TODO: pass distance */, lightsurf);
|
cfg, lightsurf->occlusion[i], 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 {
|
||||||
Light_ClampMin(sample, value, entity->color.value());
|
hit = Light_ClampMin(sample, value, entity->color.value()) || hit;
|
||||||
}
|
}
|
||||||
|
|
||||||
hit = true;
|
|
||||||
total_light_ray_hits++;
|
total_light_ray_hits++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1882,7 +1890,7 @@ static void LightFace_DebugMottle(const lightsurf_t *lightsurf, lightmapdict_t *
|
||||||
}
|
}
|
||||||
|
|
||||||
// mxd. Surface light falloff. Returns color in [0,255]
|
// 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)
|
const float &intensity, const qvec3d &color, const float &dist, const float &hotspot_clamp)
|
||||||
{
|
{
|
||||||
// Exponential falloff
|
// Exponential falloff
|
||||||
|
|
@ -1895,25 +1903,25 @@ inline qvec3f SurfaceLight_ColorAtDist(const settings::worldspawn_keys &cfg, con
|
||||||
|
|
||||||
// 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, const qvec3f &dir,
|
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 dist, const qvec3f &normal, 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->omnidirectional) {
|
if (!vpl_settings.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->rescale) {
|
if (vpl_settings.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;
|
||||||
}
|
}
|
||||||
|
|
@ -1928,7 +1936,7 @@ inline qvec3f GetSurfaceLighting(const settings::worldspawn_keys &cfg, const sur
|
||||||
|
|
||||||
// Get light contribution
|
// Get light contribution
|
||||||
result = SurfaceLight_ColorAtDist(
|
result = SurfaceLight_ColorAtDist(
|
||||||
cfg, vpl->omnidirectional ? sky_scale : standard_scale, vpl->intensity, vpl->color, dist, hotspot_clamp);
|
cfg, vpl_settings.omnidirectional ? sky_scale : standard_scale, vpl_settings.intensity, vpl_settings.color, dist, hotspot_clamp);
|
||||||
|
|
||||||
// Apply angle scale
|
// Apply angle scale
|
||||||
const qvec3f resultscaled = result * dotProductFactor;
|
const qvec3f resultscaled = result * dotProductFactor;
|
||||||
|
|
@ -1939,7 +1947,7 @@ inline qvec3f GetSurfaceLighting(const settings::worldspawn_keys &cfg, const sur
|
||||||
|
|
||||||
static bool // mxd
|
static bool // mxd
|
||||||
SurfaceLight_SphereCull(
|
SurfaceLight_SphereCull(
|
||||||
const surfacelight_t *vpl, const lightsurf_t *lightsurf, const vec_t &bouncelight_gate, const float &hotspot_clamp)
|
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 &&
|
if (light_options.visapprox.value() == visapprox_t::RAYS &&
|
||||||
vpl->bounds.disjoint(lightsurf->extents.bounds, 0.001)) {
|
vpl->bounds.disjoint(lightsurf->extents.bounds, 0.001)) {
|
||||||
|
|
@ -1952,15 +1960,15 @@ SurfaceLight_SphereCull(
|
||||||
|
|
||||||
// Get light contribution
|
// Get light contribution
|
||||||
const qvec3f color =
|
const qvec3f color =
|
||||||
SurfaceLight_ColorAtDist(cfg, vpl->omnidirectional ? cfg.surflightskyscale.value() : cfg.surflightscale.value(),
|
SurfaceLight_ColorAtDist(cfg, vpl_settings.omnidirectional ? cfg.surflightskyscale.value() : cfg.surflightscale.value(),
|
||||||
vpl->totalintensity, vpl->color, dist, hotspot_clamp);
|
vpl_settings.totalintensity, vpl_settings.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,
|
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,
|
bool bounce, const vec_t &standard_scale, const vec_t &sky_scale,
|
||||||
const float &hotspot_clamp)
|
const float &hotspot_clamp)
|
||||||
{
|
{
|
||||||
const settings::worldspawn_keys &cfg = *lightsurf->cfg;
|
const settings::worldspawn_keys &cfg = *lightsurf->cfg;
|
||||||
|
|
@ -1971,102 +1979,122 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const surfacelight_t &vpl : surface_lights) {
|
for (const auto & surf_ptr : LightSurfaces()) {
|
||||||
if (SurfaceLight_SphereCull(&vpl, lightsurf, surflight_gate, hotspot_clamp))
|
|
||||||
|
if (!surf_ptr || !surf_ptr->vpl) {
|
||||||
|
// didn't emit anthing
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
raystream_occlusion_t &rs = lightsurf->occlusion_stream;
|
auto &vpl = *surf_ptr->vpl.get();
|
||||||
|
|
||||||
for (int c = 0; c < vpl.points.size(); c++) {
|
for (const auto &vpl_setting : surf_ptr->vpl->styles) {
|
||||||
if (light_options.visapprox.value() == visapprox_t::VIS &&
|
|
||||||
VisCullEntity(bsp, lightsurf->pvs, vpl.leaves[c])) {
|
if (vpl_setting.bounce != bounce)
|
||||||
continue;
|
continue;
|
||||||
}
|
else if (SurfaceLight_SphereCull(&vpl, lightsurf, vpl_setting, surflight_gate, hotspot_clamp))
|
||||||
|
|
||||||
rs.clearPushedRays();
|
|
||||||
|
|
||||||
for (int i = 0; i < lightsurf->points.size(); i++) {
|
|
||||||
if (lightsurf->occluded[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const qvec3d &lightsurf_pos = lightsurf->points[i];
|
|
||||||
const qvec3d &lightsurf_normal = lightsurf->normals[i];
|
|
||||||
|
|
||||||
qvec3f pos = vpl.points[c];
|
|
||||||
qvec3f dir = lightsurf_pos - pos;
|
|
||||||
float dist = qv::length(dir);
|
|
||||||
bool use_normal = true;
|
|
||||||
|
|
||||||
if (dist == 0.0f) {
|
|
||||||
dir = lightsurf_normal;
|
|
||||||
use_normal = false;
|
|
||||||
} else {
|
|
||||||
dir /= dist;
|
|
||||||
}
|
|
||||||
|
|
||||||
const qvec3f indirect = GetSurfaceLighting(
|
|
||||||
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
|
|
||||||
rs.pushRay(i, pos, dir, dist, &indirect);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rs.numPushedRays())
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
total_surflight_rays += rs.numPushedRays();
|
raystream_occlusion_t &rs = lightsurf->occlusion_stream;
|
||||||
rs.tracePushedRaysOcclusion(lightsurf->modelinfo, CHANNEL_MASK_DEFAULT);
|
|
||||||
|
|
||||||
const int lightmapstyle = vpl.style;
|
for (int c = 0; c < vpl.points.size(); c++) {
|
||||||
lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, lightmapstyle, lightsurf);
|
if (light_options.visapprox.value() == visapprox_t::VIS &&
|
||||||
|
VisCullEntity(bsp, lightsurf->pvs, vpl.leaves[c])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
bool hit = false;
|
rs.clearPushedRays();
|
||||||
const int numrays = rs.numPushedRays();
|
|
||||||
for (int j = 0; j < numrays; j++) {
|
for (int i = 0; i < lightsurf->points.size(); i++) {
|
||||||
if (rs.getPushedRayOccluded(j))
|
if (lightsurf->occluded[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const qvec3d &lightsurf_pos = lightsurf->points[i];
|
||||||
|
const qvec3d &lightsurf_normal = lightsurf->normals[i];
|
||||||
|
|
||||||
|
qvec3f pos = vpl.points[c];
|
||||||
|
qvec3f dir = lightsurf_pos - pos;
|
||||||
|
float dist = qv::length(dir);
|
||||||
|
bool use_normal = true;
|
||||||
|
|
||||||
|
if (dist == 0.0f) {
|
||||||
|
dir = lightsurf_normal;
|
||||||
|
use_normal = false;
|
||||||
|
} else {
|
||||||
|
dir /= dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rs.numPushedRays())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const int i = rs.getPushedRayPointIndex(j);
|
total_surflight_rays += rs.numPushedRays();
|
||||||
qvec3f indirect = rs.getPushedRayColor(j);
|
rs.tracePushedRaysOcclusion(lightsurf->modelinfo, CHANNEL_MASK_DEFAULT);
|
||||||
|
|
||||||
Q_assert(!std::isnan(indirect[0]));
|
const int lightmapstyle = vpl_setting.style;
|
||||||
|
lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, lightmapstyle, lightsurf);
|
||||||
|
|
||||||
// Use dirt scaling on the surface lighting.
|
bool hit = false;
|
||||||
const vec_t dirtscale = Dirt_GetScaleFactor(cfg, lightsurf->occlusion[i], nullptr, 0.0, lightsurf);
|
const int numrays = rs.numPushedRays();
|
||||||
indirect *= dirtscale;
|
for (int j = 0; j < numrays; j++) {
|
||||||
|
if (rs.getPushedRayOccluded(j))
|
||||||
|
continue;
|
||||||
|
|
||||||
lightsample_t &sample = lightmap->samples[i];
|
const int i = rs.getPushedRayPointIndex(j);
|
||||||
sample.color += indirect;
|
qvec3f indirect = rs.getPushedRayColor(j);
|
||||||
|
|
||||||
hit = true;
|
Q_assert(!std::isnan(indirect[0]));
|
||||||
++total_surflight_ray_hits;
|
|
||||||
|
// Use dirt scaling on the surface lighting.
|
||||||
|
const vec_t dirtscale = Dirt_GetScaleFactor(cfg, lightsurf->occlusion[i], nullptr, 0.0, lightsurf);
|
||||||
|
indirect *= dirtscale;
|
||||||
|
|
||||||
|
lightsample_t &sample = lightmap->samples[i];
|
||||||
|
sample.color += indirect;
|
||||||
|
|
||||||
|
hit = true;
|
||||||
|
++total_surflight_ray_hits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If surface light contributed anything, save.
|
||||||
|
if (hit)
|
||||||
|
Lightmap_Save(lightmaps, lightsurf, lightmap, lightmapstyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If surface light contributed anything, save.
|
|
||||||
if (hit)
|
|
||||||
Lightmap_Save(lightmaps, lightsurf, lightmap, lightmapstyle);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void // mxd
|
static void // mxd
|
||||||
LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector<uint8_t> *pvs, raystream_occlusion_t &rs,
|
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,
|
bool bounce, const vec_t &standard_scale, const vec_t &sky_scale,
|
||||||
const float &hotspot_clamp, const qvec3d &surfpoint, 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 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++) {
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
rs.clearPushedRays();
|
|
||||||
|
|
||||||
// 1 ray
|
// 1 ray
|
||||||
{
|
for (auto &vpl_settings : vpl.styles) {
|
||||||
|
if (vpl_settings.bounce != bounce)
|
||||||
|
continue;
|
||||||
|
|
||||||
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);
|
||||||
|
|
@ -2078,6 +2106,8 @@ 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) {
|
||||||
|
|
||||||
|
|
@ -2087,7 +2117,7 @@ LightPoint_SurfaceLight(const mbsp_t *bsp, const std::vector<uint8_t> *pvs, rays
|
||||||
cube_normal[axis] = sign;
|
cube_normal[axis] = sign;
|
||||||
|
|
||||||
cube_color = GetSurfaceLighting(
|
cube_color = GetSurfaceLighting(
|
||||||
cfg, &vpl, dir, dist, cube_normal, true, standard_scale, sky_scale, hotspot_clamp);
|
cfg, vpl, vpl_settings, 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)) {
|
||||||
|
|
@ -2102,23 +2132,23 @@ 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;
|
|
||||||
|
|
||||||
rs.tracePushedRaysOcclusion(nullptr, CHANNEL_MASK_DEFAULT);
|
|
||||||
|
|
||||||
const int numrays = rs.numPushedRays();
|
|
||||||
for (int j = 0; j < numrays; j++) {
|
|
||||||
if (rs.getPushedRayOccluded(j))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
qvec3f indirect = rs.getPushedRayColor(j);
|
rs.tracePushedRaysOcclusion(nullptr, CHANNEL_MASK_DEFAULT);
|
||||||
|
|
||||||
Q_assert(!std::isnan(indirect[0]));
|
const int numrays = rs.numPushedRays();
|
||||||
|
for (int j = 0; j < numrays; j++) {
|
||||||
|
if (rs.getPushedRayOccluded(j))
|
||||||
|
continue;
|
||||||
|
|
||||||
result.add(indirect, vpl.style);
|
qvec3f indirect = rs.getPushedRayColor(j);
|
||||||
|
|
||||||
|
Q_assert(!std::isnan(indirect[0]));
|
||||||
|
|
||||||
|
result.add(indirect, vpl_settings.style);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2807,10 +2837,11 @@ bool Face_IsLightmapped(const mbsp_t *bsp, const mface_t *face)
|
||||||
|
|
||||||
// Very specific hack: the only reason to lightmap sky faces in Q2 is to light mdl's floating over sky.
|
// Very specific hack: the only reason to lightmap sky faces in Q2 is to light mdl's floating over sky.
|
||||||
// If lightgrid is in use, this reason is no longer relevant, so skip lightmapping.
|
// If lightgrid is in use, this reason is no longer relevant, so skip lightmapping.
|
||||||
if (light_options.lightgrid.value() && bsp->loadversion->game->id == GAME_QUAKE_II &&
|
// TEMP DISABLED
|
||||||
|
/*if (light_options.lightgrid.value() && bsp->loadversion->game->id == GAME_QUAKE_II &&
|
||||||
(texinfo->flags.native & Q2_SURF_SKY)) {
|
(texinfo->flags.native & Q2_SURF_SKY)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
return bsp->loadversion->game->surf_is_lightmapped(texinfo->flags);
|
return bsp->loadversion->game->surf_is_lightmapped(texinfo->flags);
|
||||||
}
|
}
|
||||||
|
|
@ -3308,7 +3339,7 @@ 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(bsp, &lightsurf, lightmaps, GetSurfaceLights(), cfg.surflightscale.value(),
|
LightFace_SurfaceLight(bsp, &lightsurf, lightmaps, false, cfg.surflightscale.value(),
|
||||||
cfg.surflightskyscale.value(), 16.0f);
|
cfg.surflightskyscale.value(), 16.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3348,7 +3379,7 @@ 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(bsp, &lightsurf, lightmaps, BounceLights(), cfg.bouncescale.value() * 0.5,
|
LightFace_SurfaceLight(bsp, &lightsurf, lightmaps, true, cfg.bouncescale.value() * 0.5,
|
||||||
cfg.bouncescale.value(), 128.0f);
|
cfg.bouncescale.value(), 128.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3388,15 +3419,17 @@ 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 (auto value = IsSurfaceLitFace(bsp, face)) {
|
if (lightsurf.vpl) {
|
||||||
auto *entity = std::get<3>(value.value());
|
if (auto value = IsSurfaceLitFace(bsp, face)) {
|
||||||
float surface_minlight_scale = entity ? entity->surflight_minlight_scale.value() : 64.f;
|
auto *entity = std::get<3>(value.value());
|
||||||
surface_minlight_scale *= lightsurf.surflight_minlight_scale;
|
float surface_minlight_scale = entity ? entity->surflight_minlight_scale.value() : 1.f;
|
||||||
|
surface_minlight_scale *= lightsurf.surflight_minlight_scale;
|
||||||
|
|
||||||
if (surface_minlight_scale > 0) {
|
if (surface_minlight_scale > 0) {
|
||||||
minlight = std::get<0>(value.value()) * surface_minlight_scale;
|
minlight = std::get<0>(value.value()) * surface_minlight_scale;
|
||||||
minlight_color = std::get<2>(value.value());
|
minlight_color = std::get<2>(value.value());
|
||||||
LightFace_Min(bsp, face, minlight_color, minlight, &lightsurf, lightmaps, std::get<1>(value.value()));
|
LightFace_Min(bsp, face, minlight_color, minlight, &lightsurf, lightmaps, std::get<1>(value.value()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3555,7 +3588,7 @@ 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(bsp, pvs, rs, GetSurfaceLights(), cfg.surflightscale.value(), cfg.surflightskyscale.value(),
|
LightPoint_SurfaceLight(bsp, pvs, rs, false, cfg.surflightscale.value(), cfg.surflightskyscale.value(),
|
||||||
16.0f, world_point, result);
|
16.0f, world_point, result);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
@ -3587,7 +3620,7 @@ 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(bsp, pvs, rs, BounceLights(), cfg.bouncescale.value() * 0.5, cfg.bouncescale.value(),
|
LightPoint_SurfaceLight(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);
|
||||||
|
|
|
||||||
|
|
@ -38,22 +38,13 @@ using namespace std;
|
||||||
using namespace polylib;
|
using namespace polylib;
|
||||||
|
|
||||||
static mutex surfacelights_lock;
|
static 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 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;
|
||||||
|
|
@ -64,6 +55,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,
|
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) {
|
||||||
|
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());
|
||||||
|
|
@ -74,38 +73,6 @@ static void MakeSurfaceLight(const mbsp_t *bsp, const settings::worldspawn_keys
|
||||||
if (facearea < 1)
|
if (facearea < 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Create winding...
|
|
||||||
winding_t winding = 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...
|
|
||||||
vector<qvec3f> points;
|
|
||||||
size_t points_before_culling = 0;
|
|
||||||
winding.dice(cfg.surflightsubdivision.value(), [&](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()) {
|
||||||
|
|
@ -137,52 +104,80 @@ 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;
|
||||||
|
|
||||||
// Sanity checks...
|
if (!surf.vpl) {
|
||||||
if (points.empty())
|
auto &l = surf.vpl = std::make_unique<surfacelight_t>();
|
||||||
return;
|
|
||||||
|
|
||||||
// Add surfacelight...
|
// Create winding...
|
||||||
surfacelight_t l;
|
winding_t winding = winding_t::from_winding_points(poly);
|
||||||
l.surfnormal = facenormal;
|
auto face_modelinfo = ModelInfoForFace(bsp, face - bsp->dfaces.data());
|
||||||
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;
|
|
||||||
}
|
|
||||||
l.rescale = extended_flags.surflight_rescale;
|
|
||||||
l.minlight_scale = extended_flags.surflight_minlight_scale;
|
|
||||||
|
|
||||||
// Init bbox...
|
for (auto &pt : winding) {
|
||||||
if (light_options.visapprox.value() == visapprox_t::RAYS) {
|
pt += face_modelinfo->offset;
|
||||||
l.bounds = EstimateVisibleBoundsAtPoint(facemidpoint);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &pt : l.points) {
|
winding.remove_colinear();
|
||||||
if (light_options.visapprox.value() == visapprox_t::VIS) {
|
|
||||||
l.leaves.push_back(Light_PointInLeaf(bsp, pt));
|
// Get face normal and midpoint...
|
||||||
} else if (light_options.visapprox.value() == visapprox_t::RAYS) {
|
l->surfnormal = Face_Normal(bsp, face);
|
||||||
l.bounds += EstimateVisibleBoundsAtPoint(pt);
|
l->pos = winding.center() + l->surfnormal; // Lift 1 unit
|
||||||
|
|
||||||
|
// Dice winding...
|
||||||
|
l->points_before_culling = 0;
|
||||||
|
|
||||||
|
winding.dice(cfg.surflightsubdivision.value(), [&](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);
|
||||||
|
});
|
||||||
|
|
||||||
|
l->minlight_scale = extended_flags.surflight_minlight_scale;
|
||||||
|
|
||||||
|
// Init bbox...
|
||||||
|
if (light_options.visapprox.value() == visapprox_t::RAYS) {
|
||||||
|
l->bounds = EstimateVisibleBoundsAtPoint(l->pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &pt : l->points) {
|
||||||
|
if (light_options.visapprox.value() == visapprox_t::VIS) {
|
||||||
|
l->leaves.push_back(Light_PointInLeaf(bsp, pt));
|
||||||
|
} else if (light_options.visapprox.value() == visapprox_t::RAYS) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
setting.rescale = extended_flags.surflight_rescale;
|
||||||
|
|
||||||
// Store surfacelight settings...
|
// Store surfacelight settings...
|
||||||
l.totalintensity = intensity * facearea;
|
setting.totalintensity = intensity * facearea;
|
||||||
l.intensity = l.totalintensity / points_before_culling;
|
setting.intensity = setting.totalintensity / l->points_before_culling;
|
||||||
l.color = texture_color.value();
|
setting.color = texture_color.value();
|
||||||
|
|
||||||
// Store light...
|
|
||||||
unique_lock<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)
|
||||||
|
|
@ -251,17 +246,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
|
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)
|
||||||
{
|
{
|
||||||
|
|
@ -270,7 +254,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);
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue