light: fix excessive bouncing with lit water, or _shadow -1

Fixes #397
This commit is contained in:
Eric Wasylishen 2023-12-24 00:44:56 -07:00
parent 6351cc50e6
commit 8db1d32e9f
6 changed files with 223 additions and 11 deletions

View File

@ -24,12 +24,15 @@
#include <common/log.hh> // for FError
#include <vector>
#include <set>
struct mbsp_t;
class modelinfo_t;
struct mface_t;
void ResetEmbree();
void Embree_TraceInit(const mbsp_t *bsp);
const std::set<const mface_t *> &ShadowCastingSolidFacesSet();
class raystream_embree_common_t
{

View File

@ -28,6 +28,7 @@
#include <light/ltface.hh>
#include <light/surflight.hh>
#include <light/trace.hh> // for Light_PointInLeaf
#include <light/trace_embree.hh> // for ShadowCastingSolidFacesSet
#include <common/polylib.hh>
#include <common/bsputils.hh>
@ -42,10 +43,13 @@
static bool Face_ShouldBounce(const mbsp_t *bsp, const mface_t *face)
{
// make bounce light, only if this face is shadow casting
const modelinfo_t *mi = ModelInfoForFace(bsp, Face_GetNum(bsp, face));
if (!mi || !mi->shadow.boolValue()) {
// NOTE: this should be the same set of faces that are unconditionally shadow casting
// (so exclude fences, water, etc.) which is why we're currently fetching it from the embree
// code, because the condition is quite complex and we don't want to try to repeat it here.
auto &face_set = ShadowCastingSolidFacesSet();
if (face_set.find(face) == face_set.end())
return false;
}
if (!Face_IsLightmapped(bsp, face)) {
return false;
@ -67,14 +71,6 @@ static bool Face_ShouldBounce(const mbsp_t *bsp, const mface_t *face)
return false;
}
// don't bounce from faces on non-default object channels
if (mi->object_channel_mask.value() != CHANNEL_MASK_DEFAULT) {
return false;
}
if (ext_info.object_channel_mask.value_or(CHANNEL_MASK_DEFAULT) != CHANNEL_MASK_DEFAULT) {
return false;
}
return true;
}

View File

@ -26,11 +26,15 @@
#include <common/polylib.hh>
#include <vector>
#include <climits>
#include <set>
sceneinfo skygeom; // sky. always occludes.
sceneinfo solidgeom; // solids. always occludes.
sceneinfo filtergeom; // conditional occluders.. needs to run ray intersection filter
// set of faces in `solidgeom`,
std::set<const mface_t *> shadow_casting_solid_faces;
static RTCDevice device;
RTCScene scene;
@ -41,6 +45,7 @@ void ResetEmbree()
skygeom = {};
solidgeom = {};
filtergeom = {};
shadow_casting_solid_faces = {};
if (scene) {
rtcReleaseScene(scene);
@ -55,6 +60,12 @@ void ResetEmbree()
bsp_static = nullptr;
}
const std::set<const mface_t *> &ShadowCastingSolidFacesSet()
{
return shadow_casting_solid_faces;
}
/**
* Returns 1.0 unless a custom alpha value is set.
* The priority is: "_light_alpha" (read from extended_texinfo_flags), then "alpha", then Q2 surface flags
@ -675,6 +686,11 @@ void Embree_TraceInit(const mbsp_t *bsp)
rtcCommitScene(scene);
// keep a backup of solidfaces
for (const mface_t *face : solidfaces) {
shadow_casting_solid_faces.insert(face);
}
logging::funcprint("\n");
logging::print("\t{} sky faces\n", skyfaces.size());
logging::print("\t{} solid faces\n", solidfaces.size());

View File

@ -0,0 +1,86 @@
// Game: Quake
// Format: Valve
// entity 0
{
"classname" "worldspawn"
"wad" "deprecated/free_wad.wad"
"_tb_def" "builtin:Quake.fgd"
// brush 0
{
( -416 -128 32 ) ( -416 -127 32 ) ( -416 -128 33 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
( -416 -208 32 ) ( -416 -208 33 ) ( -415 -208 32 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( -416 -128 32 ) ( -415 -128 32 ) ( -416 -127 32 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 128 272 48 ) ( 128 273 48 ) ( 129 272 48 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 128 272 48 ) ( 129 272 48 ) ( 128 272 49 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 128 272 48 ) ( 128 272 49 ) ( 128 273 48 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
}
// brush 1
{
( -416 -128 288 ) ( -416 -127 288 ) ( -416 -128 289 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
( -416 -208 288 ) ( -416 -208 289 ) ( -415 -208 288 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( -416 -128 288 ) ( -415 -128 288 ) ( -416 -127 288 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 128 272 304 ) ( 128 273 304 ) ( 129 272 304 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 128 272 304 ) ( 129 272 304 ) ( 128 272 305 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 128 272 304 ) ( 128 272 305 ) ( 128 273 304 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
}
// brush 2
{
( -432 -128 272 ) ( -432 -127 272 ) ( -432 -128 273 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
( -432 -208 272 ) ( -432 -208 273 ) ( -431 -208 272 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( -432 -128 48 ) ( -431 -128 48 ) ( -432 -127 48 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 112 272 288 ) ( 112 273 288 ) ( 113 272 288 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 112 272 288 ) ( 113 272 288 ) ( 112 272 289 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( -416 272 288 ) ( -416 272 289 ) ( -416 273 288 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
}
// brush 3
{
( 128 -128 272 ) ( 128 -127 272 ) ( 128 -128 273 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
( 128 -208 272 ) ( 128 -208 273 ) ( 129 -208 272 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 128 -128 48 ) ( 129 -128 48 ) ( 128 -127 48 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 672 272 288 ) ( 672 273 288 ) ( 673 272 288 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 672 272 288 ) ( 673 272 288 ) ( 672 272 289 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 144 272 288 ) ( 144 272 289 ) ( 144 273 288 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
}
// brush 4
{
( -416 -144 272 ) ( -416 -143 272 ) ( -416 -144 273 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
( 96 -224 272 ) ( 96 -224 273 ) ( 97 -224 272 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 96 -144 48 ) ( 97 -144 48 ) ( 96 -143 48 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 640 256 288 ) ( 640 257 288 ) ( 641 256 288 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 640 -208 288 ) ( 641 -208 288 ) ( 640 -208 289 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 128 256 288 ) ( 128 256 289 ) ( 128 257 288 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
}
// brush 5
{
( -416 256 48 ) ( -416 257 48 ) ( -416 256 49 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
( -432 256 48 ) ( -432 256 49 ) ( -431 256 48 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( -432 256 48 ) ( -431 256 48 ) ( -432 257 48 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 128 272 288 ) ( 128 273 288 ) ( 129 272 288 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 128 272 64 ) ( 129 272 64 ) ( 128 272 65 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 128 272 64 ) ( 128 272 65 ) ( 128 273 64 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
}
}
// entity 1
{
"classname" "info_player_start"
"origin" "-292 0 72"
}
// entity 2
{
"classname" "light"
"origin" "-136 24 148"
"delay" "2"
}
// entity 3
{
"classname" "func_detail"
// brush 0
{
( 0 112 48 ) ( 0 113 48 ) ( 0 112 49 ) *swater5 [ 0 -1 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 0 -208 48 ) ( 0 -208 49 ) ( 1 -208 48 ) *swater5 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 0 112 48 ) ( 1 112 48 ) ( 0 113 48 ) *swater5 [ -1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1
( 128 256 288 ) ( 128 257 288 ) ( 129 256 288 ) *swater5 [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1
( 128 256 64 ) ( 129 256 64 ) ( 128 256 65 ) *swater5 [ -1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 128 256 64 ) ( 128 256 65 ) ( 128 257 64 ) *swater5 [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1
}
}

View File

@ -0,0 +1,88 @@
// Game: Quake
// Format: Valve
// entity 0
{
"classname" "worldspawn"
"wad" "deprecated/free_wad.wad;deprecated/fence.wad"
"_tb_def" "builtin:Quake.fgd"
// brush 0
{
( -416 -128 32 ) ( -416 -127 32 ) ( -416 -128 33 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
( -416 -208 32 ) ( -416 -208 33 ) ( -415 -208 32 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( -416 -128 32 ) ( -415 -128 32 ) ( -416 -127 32 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 128 272 48 ) ( 128 273 48 ) ( 129 272 48 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 128 272 48 ) ( 129 272 48 ) ( 128 272 49 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 128 272 48 ) ( 128 272 49 ) ( 128 273 48 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
}
// brush 1
{
( -416 -128 288 ) ( -416 -127 288 ) ( -416 -128 289 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
( -416 -208 288 ) ( -416 -208 289 ) ( -415 -208 288 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( -416 -128 288 ) ( -415 -128 288 ) ( -416 -127 288 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 128 272 304 ) ( 128 273 304 ) ( 129 272 304 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 128 272 304 ) ( 129 272 304 ) ( 128 272 305 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 128 272 304 ) ( 128 272 305 ) ( 128 273 304 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
}
// brush 2
{
( -432 -128 272 ) ( -432 -127 272 ) ( -432 -128 273 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
( -432 -208 272 ) ( -432 -208 273 ) ( -431 -208 272 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( -432 -128 48 ) ( -431 -128 48 ) ( -432 -127 48 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 112 272 288 ) ( 112 273 288 ) ( 113 272 288 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 112 272 288 ) ( 113 272 288 ) ( 112 272 289 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( -416 272 288 ) ( -416 272 289 ) ( -416 273 288 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
}
// brush 3
{
( 128 -128 272 ) ( 128 -127 272 ) ( 128 -128 273 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
( 128 -208 272 ) ( 128 -208 273 ) ( 129 -208 272 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 128 -128 48 ) ( 129 -128 48 ) ( 128 -127 48 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 672 272 288 ) ( 672 273 288 ) ( 673 272 288 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 672 272 288 ) ( 673 272 288 ) ( 672 272 289 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 144 272 288 ) ( 144 272 289 ) ( 144 273 288 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
}
// brush 4
{
( -416 -144 272 ) ( -416 -143 272 ) ( -416 -144 273 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
( 96 -224 272 ) ( 96 -224 273 ) ( 97 -224 272 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 96 -144 48 ) ( 97 -144 48 ) ( 96 -143 48 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 640 256 288 ) ( 640 257 288 ) ( 641 256 288 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 640 -208 288 ) ( 641 -208 288 ) ( 640 -208 289 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 128 256 288 ) ( 128 256 289 ) ( 128 257 288 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
}
// brush 5
{
( -416 256 48 ) ( -416 257 48 ) ( -416 256 49 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
( -432 256 48 ) ( -432 256 49 ) ( -431 256 48 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( -432 256 48 ) ( -431 256 48 ) ( -432 257 48 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 128 272 288 ) ( 128 273 288 ) ( 129 272 288 ) bolt3 [ 1 0 0 0 ] [ 0 -1 0 -32 ] 0 1 1
( 128 272 64 ) ( 129 272 64 ) ( 128 272 65 ) bolt3 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 128 272 64 ) ( 128 272 65 ) ( 128 273 64 ) bolt3 [ 0 1 0 32 ] [ 0 0 -1 0 ] 0 1 1
}
}
// entity 1
{
"classname" "info_player_start"
"origin" "-292 0 72"
}
// entity 2
{
"classname" "func_detail_illusionary"
"_mirrorinside" "0"
"_shadow" "-1"
// brush 0
{
( 0 823.1111111111112 48 ) ( 0 826.3333333333334 48 ) ( 0 823.1111111111112 49 ) grate1 [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 0 -192 48 ) ( 0 -192 49 ) ( 1 -192 48 ) grate1 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 0 823.1111111111112 48 ) ( 1 823.1111111111112 48 ) ( 0 826.3333333333334 48 ) grate1 [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1
( 128 1287.1111111111113 272 ) ( 128 1290.3333333333335 272 ) ( 129 1287.1111111111113 272 ) grate1 [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1
( 128 224 64 ) ( 129 224 64 ) ( 128 224 65 ) grate1 [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
( 128 1287.1111111111113 64 ) ( 128 1287.1111111111113 65 ) ( 128 1290.3333333333335 64 ) grate1 [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1
}
}
// entity 3
{
"classname" "light"
"origin" "-136 24 148"
"delay" "2"
}

View File

@ -852,3 +852,26 @@ TEST_CASE("q1_sunlight")
auto [bsp, bspx, lit] = QbspVisLight_Q1("q1_sunlight.map", {"-lit"});
CheckFaceLuxelAtPoint(&bsp, &bsp.dmodels[0], {49, 49, 49}, {0, 0, 0}, {0, 0, 1}, &lit);
}
TEST_CASE("q1_light_bounce_litwater without the water")
{
auto [bsp, bspx] = QbspVisLight_Common("q1_light_bounce_litwater.map", {"-omitdetail"}, {"-lit", "-bounce", "4"}, runvis_t::no);
CheckFaceLuxelAtPoint(&bsp, &bsp.dmodels[0], {118, 118, 118}, {128, 12, 156}, {-1, 0, 0});
}
TEST_CASE("q1_light_bounce_litwater")
{
INFO("adding a water plane should not affect the amount of light bounced on to the walls");
auto [bsp, bspx, lit] = QbspVisLight_Q1("q1_light_bounce_litwater.map", {"-lit", "-bounce", "4"});
CheckFaceLuxelAtPoint(&bsp, &bsp.dmodels[0], {118, 118, 118}, {128, 12, 156}, {-1, 0, 0});
}
TEST_CASE("q1_light_bounce_noshadow")
{
INFO("make sure light doesn't both pass through and bounce off of a face with _shadow -1");
auto [bsp, bspx, lit] = QbspVisLight_Q1("q1_light_bounce_noshadow.map", {"-lit", "-bounce", "4"});
CheckFaceLuxelAtPoint(&bsp, &bsp.dmodels[0], {118, 118, 118}, {128, 12, 156}, {-1, 0, 0});
}