light: remove hack which disable vis culling inside liquids
instead, implement the equivalent by bridging the PVS across opaque liquid faces
This commit is contained in:
parent
6b707b6d5a
commit
64d6cbad4f
|
|
@ -655,6 +655,35 @@ void DecompressVis(const uint8_t *in, const uint8_t *inend, uint8_t *out, uint8_
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the visdata so everything that:
|
||||
* everything that can see into cluster a, can also see into cluster b + its pvs
|
||||
*/
|
||||
static void ConnectLeafVisibilityDirectional(const mbsp_t *bsp, std::unordered_map<int, std::vector<uint8_t>> &all_visdata, int a, int b)
|
||||
{
|
||||
Q_assert(bsp->loadversion->game->id == GAME_QUAKE_II);
|
||||
|
||||
if (a < 0)
|
||||
return;
|
||||
if (b < 0)
|
||||
return;
|
||||
|
||||
const std::vector<uint8_t> b_pvs_copy = all_visdata.at(b);
|
||||
|
||||
for (auto &[cluster, pvs] : all_visdata) {
|
||||
// can cluster see into `a`?
|
||||
if (pvs[a >> 3] & (1 << (a & 7))) {
|
||||
// update `pvs` to see into `b`
|
||||
pvs[b >> 3] |= (1 << (b & 7));
|
||||
|
||||
// update `pvs` to see into b's pvs
|
||||
for (int i = 0; i < pvs.size(); ++i) {
|
||||
pvs[i] |= b_pvs_copy[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decompress visdata for the entire map, and returns a map of:
|
||||
*
|
||||
|
|
@ -666,6 +695,8 @@ void DecompressVis(const uint8_t *in, const uint8_t *inend, uint8_t *out, uint8_
|
|||
*/
|
||||
std::unordered_map<int, std::vector<uint8_t>> DecompressAllVis(const mbsp_t *bsp, bool trans_water)
|
||||
{
|
||||
logging::funcheader();
|
||||
|
||||
std::unordered_map<int, std::vector<uint8_t>> result;
|
||||
|
||||
const size_t decompressed_size = DecompressedVisSize(bsp);
|
||||
|
|
@ -710,6 +741,47 @@ std::unordered_map<int, std::vector<uint8_t>> DecompressAllVis(const mbsp_t *bsp
|
|||
}
|
||||
}
|
||||
|
||||
if (trans_water && bsp->loadversion->game->id == GAME_QUAKE_II) {
|
||||
// FIXME: implement non q2 path
|
||||
|
||||
// we want to make all visblocking liquids transparent
|
||||
|
||||
std::set<std::pair<int, int>> cluster_pairs_to_unify;
|
||||
|
||||
const auto &world = bsp->dmodels[0];
|
||||
for (int i = world.firstface; i < (world.firstface + world.numfaces); ++i) {
|
||||
const mface_t &face = bsp->dfaces[i];
|
||||
|
||||
qvec3f centroid = Face_Centroid(bsp, &face);
|
||||
auto plane = Face_Plane(bsp, &face);
|
||||
|
||||
auto *top = BSP_FindLeafAtPoint(bsp, &world, centroid + (plane.normal * 0.5));
|
||||
auto *bottom = BSP_FindLeafAtPoint(bsp, &world, centroid - (plane.normal * 0.5));
|
||||
|
||||
contentflags_t top_contents{top->contents};
|
||||
contentflags_t bottom_contents{bottom->contents};
|
||||
|
||||
// this weakens the pvs culling effectiveness, so only do it if top and bottom can't see each other
|
||||
// FIXME: would be better to do a PVS check (especially for Q1)
|
||||
if (Face_IsTranslucent(bsp, &face)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (top_contents.is_empty(bsp->loadversion->game) && bottom_contents.is_liquid(bsp->loadversion->game)) {
|
||||
cluster_pairs_to_unify.insert(std::make_pair(top->cluster, bottom->cluster));
|
||||
}
|
||||
}
|
||||
|
||||
if (cluster_pairs_to_unify.size()) {
|
||||
logging::print("{:9} cluster pairs PVS connected to make liquid translucent\n", cluster_pairs_to_unify.size());
|
||||
}
|
||||
|
||||
for (auto [top, bottom] : cluster_pairs_to_unify) {
|
||||
ConnectLeafVisibilityDirectional(bsp, result, top, bottom);
|
||||
ConnectLeafVisibilityDirectional(bsp, result, bottom, top);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -513,16 +513,6 @@ static void CalcPvs(const mbsp_t *bsp, lightsurf_t *lightsurf)
|
|||
/* copy the pvs for this leaf into pointpvs */
|
||||
Mod_LeafPvs(bsp, leaf, pointpvs);
|
||||
|
||||
if (bsp->loadversion->game->contents_are_liquid({leaf->contents})) {
|
||||
// hack for when the sample point might be in an opaque liquid, blocking vis,
|
||||
// but we typically want light to pass through these.
|
||||
// see also VisCullEntity() which handles the case when the light emitter is in liquid.
|
||||
for (int j = 0; j < pvssize; j++) {
|
||||
lightsurf->pvs[j] |= 0xff;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* merge the pvs for this sample point into lightsurf->pvs */
|
||||
for (int j = 0; j < pvssize; j++) {
|
||||
lightsurf->pvs[j] |= pointpvs[j];
|
||||
|
|
@ -1090,11 +1080,7 @@ static bool VisCullEntity(const mbsp_t *bsp, const std::vector<uint8_t> &pvs, co
|
|||
}
|
||||
|
||||
if (bsp->loadversion->game->contents_are_solid({entleaf->contents}) ||
|
||||
bsp->loadversion->game->contents_are_sky({entleaf->contents}) ||
|
||||
bsp->loadversion->game->contents_are_liquid({entleaf->contents})) {
|
||||
// the liquid case is because entleaf->contents might be in an opaque liquid,
|
||||
// which we typically want light to pass through, but visdata would report that
|
||||
// there's no visibility across the opaque liquid. so, skip culling and do the raytracing.
|
||||
bsp->loadversion->game->contents_are_sky({entleaf->contents})) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue