some optimizations in indirect lighting code

multiple bounce support
This commit is contained in:
Jonathan 2023-09-16 00:41:05 -04:00
parent 04044dd76d
commit 147be8f87a
6 changed files with 100 additions and 59 deletions

View File

@ -282,7 +282,7 @@ Debug modes
.. option:: -debugmottle
Save mottle pattern (used by Q2 minlight, unless opted out with :bmodel-key:`_minlight_mottle`)
Save mottle pattern (used by Q2 minlight, when opted in with :bmodel-key:`_minlight_mottle`)
to lightmap.
.. option:: -debugface x y z
@ -531,7 +531,8 @@ The following keys can be added to the *worldspawn* entity:
.. worldspawn-key:: "_bounce" "n"
1 enables bounce lighting, disabled by default.
Non-zero enables bounce lighting, disabled by default. The value is
the maximum number of bounces to perform.
.. worldspawn-key:: "_bouncescale" "n"
@ -596,7 +597,7 @@ func_detail/func_group as well, if qbsp from these tools is used.
"_minlightMottle" "n"
Whether minlight should have a mottled pattern. Defaults
to 1 in Q2 mode and 0 otherwise.
to 0.
.. bmodel-key:: "_minlight_exclude" "texname"

View File

@ -28,5 +28,5 @@ struct mbsp_t;
// public functions
void ResetBounce();
void MakeBounceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp);
bool MakeBounceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp);
void ClearBounceLights(const mbsp_t *bsp);

View File

@ -78,6 +78,7 @@ class lightmap_t
public:
int style;
std::vector<lightsample_t> samples;
qvec3d bounce_color;
};
using lightmapdict_t = std::vector<lightmap_t>;
@ -300,7 +301,7 @@ public:
setting_scalar phongangle;
/* bounce */
setting_bool bounce;
setting_int32 bounce;
setting_bool bouncestyled;
setting_scalar bouncescale;
setting_scalar bouncecolorscale;

View File

@ -39,13 +39,6 @@
#include <common/qvec.hh>
#include <common/parallel.hh>
static std::atomic_size_t bouncelightpoints;
void ResetBounce()
{
bouncelightpoints = 0;
}
static bool Face_ShouldBounce(const mbsp_t *bsp, const mface_t *face)
{
// make bounce light, only if this face is shadow casting
@ -145,30 +138,30 @@ static void MakeBounceLight(const mbsp_t *bsp, const settings::worldspawn_keys &
}
}
static void MakeBounceLightsThread(const settings::worldspawn_keys &cfg, const mbsp_t *bsp, const mface_t &face)
static bool MakeBounceLightsThread(const settings::worldspawn_keys &cfg, const mbsp_t *bsp, const mface_t &face)
{
if (!Face_ShouldBounce(bsp, &face)) {
return;
return false;
}
auto &surf_ptr = LightSurfaces()[&face - bsp->dfaces.data()];
if (!surf_ptr) {
return;
return false;
}
auto &surf = *surf_ptr.get();
// no lights
if (!surf.lightmapsByStyle.size()) {
return;
return false;
}
auto winding = polylib::winding_t::from_face(bsp, &face);
vec_t area = winding.area();
if (area < 1.f) {
return;
return false;
}
// Create winding...
@ -181,27 +174,25 @@ static void MakeBounceLightsThread(const settings::worldspawn_keys &cfg, const m
bool has_any_color = false;
for (const auto &lightmap : surf.lightmapsByStyle) {
for (auto &lightmap : surf.lightmapsByStyle) {
if (lightmap.style && !cfg.bouncestyled.value()) {
continue;
}
for (auto &sample : lightmap.samples) {
sum[lightmap.style] += sample.color;
}
}
for (auto &sample : sum) {
if (!qv::emptyExact(sample.second)) {
sample.second /= sample_divisor;
if (!qv::emptyExact(lightmap.bounce_color)) {
sum[lightmap.style] = lightmap.bounce_color / sample_divisor;
has_any_color = true;
}
// clear bounced color from lightmap since we
// have "counted" it
lightmap.bounce_color = {};
}
// no bounced color, we can leave early
if (!has_any_color) {
return;
return false;
}
// lerp between gray and the texture color according to `bouncecolorscale` (0 = use gray, 1 = use texture color)
@ -240,13 +231,51 @@ static void MakeBounceLightsThread(const settings::worldspawn_keys &cfg, const m
for (auto &style : emitcolors) {
MakeBounceLight(bsp, cfg, surf, style.second, style.first, points, area, facenormal, facemidpoint);
}
return true;
}
void MakeBounceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp)
static void ClearBounceLightsThread(const mbsp_t *bsp, const mface_t &face)
{
if (!Face_ShouldBounce(bsp, &face)) {
return;
}
auto &surf_ptr = LightSurfaces()[&face - bsp->dfaces.data()];
if (!surf_ptr) {
return;
}
auto &surf = *surf_ptr.get();
// no bouncing yet
if (!surf.vpl) {
return;
}
// remove all styles that are bounce
auto &l = *surf.vpl;
auto removed = std::remove_if(l.styles.begin(), l.styles.end(), [](surfacelight_t::per_style_t &p) {
return p.bounce;
});
l.styles.erase(removed, l.styles.end());
}
bool MakeBounceLights(const settings::worldspawn_keys &cfg, const mbsp_t *bsp)
{
logging::funcheader();
logging::parallel_for_each(bsp->dfaces, [&](const mface_t &face) { MakeBounceLightsThread(cfg, bsp, face); });
std::atomic_bool any_to_bounce = false;
// logging::print("{} bounce lights created, with {} points\n", bouncelights.size(), bouncelightpoints);
logging::parallel_for_each(bsp->dfaces, [&](const mface_t &face) { any_to_bounce = MakeBounceLightsThread(cfg, bsp, face) || any_to_bounce; });
return any_to_bounce.load();
}
void ClearBounceLights(const mbsp_t *bsp)
{
logging::funcheader();
logging::parallel_for_each(bsp->dfaces, [&](const mface_t &face) { ClearBounceLightsThread(bsp, face); });
}

View File

@ -186,7 +186,7 @@ worldspawn_keys::worldspawn_keys()
minlight_dirt{this, "minlight_dirt", false, &worldspawn_group},
phongallowed{this, "phong", true, &worldspawn_group},
phongangle{this, "phong_angle", 0, &worldspawn_group},
bounce{this, "bounce", false, &worldspawn_group},
bounce{this, "bounce", 0, &worldspawn_group},
bouncestyled{this, "bouncestyled", false, &worldspawn_group},
bouncescale{this, "bouncescale", 1.0, 0.0, 100.0, &worldspawn_group},
bouncecolorscale{this, "bouncecolorscale", 0.0, 0.0, 1.0, &worldspawn_group},
@ -668,10 +668,12 @@ static void CacheTextures(const mbsp_t &bsp)
face_textures[i] = {nullptr, {127}, {0.5}};
} else {
auto tex = img::find(name);
face_textures[i] = {tex, tex->averageColor,
auto &ext = extended_texinfo_flags[bsp.dfaces[i].texinfo];
auto avg = ext.surflight_color.value_or(tex->averageColor);
face_textures[i] = {tex, avg,
// lerp between gray and the texture color according to `bouncecolorscale` (0 = use gray, 1 = use
// texture color)
mix(qvec3d{127}, qvec3d(tex->averageColor), light_options.bouncecolorscale.value()) / 255.0};
mix(qvec3d{127}, qvec3d(avg), light_options.bouncecolorscale.value()) / 255.0};
}
}
}
@ -936,18 +938,29 @@ static void LightWorld(bspdata_t *bspdata, bool forcedscale)
});
if (bouncerequired && !light_options.nolighting.value()) {
MakeBounceLights(light_options, &bsp);
logging::header("Indirect Lighting"); // mxd
logging::parallel_for(static_cast<size_t>(0), bsp.dfaces.size(), [&bsp](size_t i) {
if (light_surfaces[i] && Face_IsLightmapped(&bsp, &bsp.dfaces[i])) {
#if defined(HAVE_EMBREE) && defined(__SSE2__)
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
#endif
for (size_t i = 0; i < light_options.bounce.value(); i++) {
IndirectLightFace(&bsp, *light_surfaces[i].get(), light_options);
if (i != 0) {
ClearBounceLights(&bsp);
}
});
if (!MakeBounceLights(light_options, &bsp)) {
logging::header("No bounces; indirect lighting halted");
break;
}
logging::header(fmt::format("Indirect Lighting (pass {0})", i).c_str()); // mxd
logging::parallel_for(static_cast<size_t>(0), bsp.dfaces.size(), [&bsp](size_t i) {
if (light_surfaces[i] && Face_IsLightmapped(&bsp, &bsp.dfaces[i])) {
#if defined(HAVE_EMBREE) && defined(__SSE2__)
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
#endif
IndirectLightFace(&bsp, *light_surfaces[i].get(), light_options);
}
});
}
}
if (!light_options.nolighting.value()) {
@ -1470,7 +1483,6 @@ static void ResetLight()
void light_reset()
{
ResetBounce();
ResetLightEntities();
ResetLight();
ResetLtFace();
@ -1561,9 +1573,10 @@ int light_main(int argc, const char **argv)
img::load_textures(&bsp, light_options);
LoadExtendedTexinfoFlags(source, &bsp);
CacheTextures(bsp);
LoadExtendedTexinfoFlags(source, &bsp);
LoadEntities(light_options, &bsp);
light_options.postinitialize(argc, argv);

View File

@ -634,12 +634,7 @@ static std::unique_ptr<lightsurf_t> Lightsurf_Init(const modelinfo_t *modelinfo,
} else if (light_options.minlightMottle.is_changed()) {
lightsurf->minlightMottle = light_options.minlightMottle.value();
} else {
// default value depends on game
if (bsp->loadversion->game->id == GAME_QUAKE_II) {
lightsurf->minlightMottle = true;
} else {
lightsurf->minlightMottle = false;
}
lightsurf->minlightMottle = false;
}
// Q2 uses a 0-1 range for minlight
@ -758,6 +753,7 @@ static void Lightmap_AllocOrClear(lightmap_t *lightmap, const lightsurf_t *light
} else if (lightmap->style != INVALID_LIGHTSTYLE) {
/* clear only the data that is going to be merged to it. there's no point clearing more */
std::fill_n(lightmap->samples.begin(), lightsurf->samples.size(), lightsample_t{});
lightmap->bounce_color = {};
}
}
@ -801,13 +797,6 @@ static lightmap_t *Lightmap_ForStyle(lightmapdict_t *lightmaps, const int style,
return &newLightmap;
}
static void Lightmap_ClearAll(lightmapdict_t *lightmaps)
{
for (auto &lm : *lightmaps) {
lm.style = INVALID_LIGHTSTYLE;
}
}
/*
* Lightmap_Save
*
@ -1306,6 +1295,7 @@ static void LightFace_Entity(
lightsample_t &sample = cached_lightmap->samples[i];
sample.color += rs.getPushedRayColor(j);
cached_lightmap->bounce_color += rs.getPushedRayColor(j);
sample.direction += rs.getPushedRayNormalContrib(j);
Lightmap_Save(bsp, lightmaps, lightsurf, cached_lightmap, cached_style);
@ -1478,6 +1468,7 @@ static void LightFace_Sky(const mbsp_t *bsp, const sun_t *sun, lightsurf_t *ligh
lightsample_t &sample = cached_lightmap->samples[i];
sample.color += rs.getPushedRayColor(j);
cached_lightmap->bounce_color += rs.getPushedRayColor(j);
sample.direction += rs.getPushedRayNormalContrib(j);
total_light_ray_hits++;
@ -1949,6 +1940,11 @@ inline qvec3f GetSurfaceLighting(const settings::worldspawn_keys &cfg, const sur
dotProductFactor = std::max(0.0f, dotProductFactor);
// quick exit
if (!dotProductFactor) {
return {0};
}
if (vpl_settings.omnidirectional) {
dist += cfg.surflightskydist.value();
}
@ -2034,7 +2030,7 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t
const qvec3f &pos = vpl.points[c];
qvec3f dir = lightsurf_pos - pos;
float dist = qv::length(dir);
float dist = std::max(0.01f, qv::length(dir));
bool use_normal = true;
if (lightsurf->twosided) {
@ -2081,6 +2077,7 @@ LightFace_SurfaceLight(const mbsp_t *bsp, lightsurf_t *lightsurf, lightmapdict_t
lightsample_t &sample = lightmap->samples[i];
sample.color += indirect;
lightmap->bounce_color += indirect;
hit = true;
++total_surflight_ray_hits;