light: delete some dead code

This commit is contained in:
Eric Wasylishen 2017-02-27 15:32:38 -07:00
parent a6f56d9111
commit 69d5669773
7 changed files with 0 additions and 1101 deletions

View File

@ -157,7 +157,6 @@ typedef enum {
debugmode_dirt,
debugmode_bounce,
debugmode_bouncelights,
debugmode_contribfaces,
debugmode_debugoccluded
} debugmode_t;

View File

@ -45,34 +45,6 @@
#include <glm/vec4.hpp>
#include <glm/mat4x4.hpp>
using batch_t = std::vector<int>;
using batches_t = std::vector<batch_t>;
class contributing_face_t {
public:
const bsp2_dface_t *contribFace;
const bsp2_dface_t *refFace;
std::vector<glm::vec4> contribFaceEdgePlanes;
};
using all_contrib_faces_t = std::map<const bsp2_dface_t *, std::vector<contributing_face_t>>;
using blocking_plane_t = glm::vec4;
struct lightbatchthread_info_t {
batches_t all_batches;
all_contrib_faces_t all_contribFaces;
bsp2_t *bsp;
};
void *LightBatchThread(void *arg);
std::vector<blocking_plane_t> BlockingPlanes(const bsp2_t *bsp, const bsp2_dface_t *f, const edgeToFaceMap_t &edgeToFaceMap);
batches_t MakeLightingBatches(const bsp2_t *bsp);
all_contrib_faces_t MakeContributingFaces(const bsp2_t *bsp);
std::vector<contributing_face_t> SetupContributingFaces(const bsp2_t *bsp, const bsp2_dface_t *face, const edgeToFaceMap_t &edgeToFaceMap);
std::pair<bool, glm::mat4x4> RotationAboutLineSegment(glm::vec3 p0, glm::vec3 p1,
glm::vec3 face0Norm, glm::vec3 face1Norm);

View File

@ -31,7 +31,6 @@
#include <light/light2.hh>
glm::vec2 WorldToTexCoord_HighPrecision(const bsp2_t *bsp, const bsp2_dface_t *face, const glm::vec3 &world);
void LightBatch(bsp2_t *bsp, const batch_t &batch, const all_contrib_faces_t &all_contrib_faces);
class faceextents_t {
private:

View File

@ -986,12 +986,6 @@ light_main(int argc, const char **argv)
} else if ( !strcmp( argv[ i ], "-debugvert" ) ) {
ParseVec3(dump_vert_point, &i, argc, argv);
dump_vert = true;
} else if ( !strcmp( argv[ i ], "-debugcontribfaces" ) ) {
CheckNoDebugModeSet();
debugmode = debugmode_contribfaces;
ParseVec3(dump_face_point, &i, argc, argv);
dump_face = true;
} else if ( !strcmp( argv[ i ], "-debugoccluded" ) ) {
CheckNoDebugModeSet();
debugmode = debugmode_debugoccluded;

View File

@ -103,333 +103,3 @@ glm::mat4x4 TexSpaceToWorld(const bsp2_t *bsp, const bsp2_dface_t *f)
return glm::inverse(T);
}
using bbox2 = pair<glm::vec2, glm::vec2>;
using bbox3 = pair<glm::vec3, glm::vec3>;
using contribface_stackframe_t = const bsp2_dface_t *;
// Returns the next stack frames to process
vector<contribface_stackframe_t> SetupContributingFaces_R(const contribface_stackframe_t &frame,
const bsp2_t *bsp,
const edgeToFaceMap_t &edgeToFaceMap,
const bsp2_dface_t *refFace,
const aabb2 &refFaceTexBounds,
const aabb3 &refFaceWorldBounds,
vector<bool> *faceidx_handled,
vector<contributing_face_t> *result)
{
const bsp2_dface_t *f = frame;
const int currFnum = Face_GetNum(bsp, f);
if (faceidx_handled->at(currFnum))
return {};
// mark currentFace as handled
faceidx_handled->at(currFnum) = true;
if (!Face_IsLightmapped(bsp, f))
return {};
// Check angle between reference face and this face
const glm::vec4 refPlane = Face_Plane_E(bsp, refFace);
const glm::vec3 refNormal = glm::vec3(refPlane);
const glm::vec3 fNormal = Face_Normal_E(bsp, f);
if (dot(fNormal, refNormal) <= 0)
return {};
//printf("%s\n", Face_TextureName(bsp, f));
// now check each vertex's position projected onto refFace.
// if no verts are within the range that could contribute to a sample in refFace
// we can stop recursion and skip adding `f` to the result vector.
bool foundNearVert = false;
for (int j = 0; j < f->numedges; j++) {
const int v0 = Face_VertexAtIndex(bsp, f, j);
const glm::vec3 v0_position = Vertex_GetPos_E(bsp, v0);
const glm::vec3 v0InRefWorld = GLM_ProjectPointOntoPlane(refPlane, v0_position);
const glm::vec2 v0InRefTex2f = WorldToTexCoord_HighPrecision(bsp, refFace, v0InRefWorld);
// check distance to box
const bool near = refFaceTexBounds.grow(glm::vec2(16, 16)).contains(v0InRefTex2f);
if (near) {
//const float worldDist = refFaceWorldBounds.exteriorDistance(v0InRefWorld);
//printf ("world distance: %f, tex dist: %f\n", worldDist, dist);
foundNearVert = true;
break;
}
}
if (!foundNearVert) {
return {};
}
// add to result (don't add the starting face though)
if (f != refFace) {
contributing_face_t resAddition;
resAddition.contribFace = f;
resAddition.refFace = refFace;
resAddition.contribFaceEdgePlanes = GLM_MakeInwardFacingEdgePlanes(GLM_FacePoints(bsp, f));
result->push_back(resAddition);
}
// walk edges
vector<contribface_stackframe_t> nextframes;
for (int j = 0; j < f->numedges; j++) {
const int v0 = Face_VertexAtIndex(bsp, f, j);
const int v1 = Face_VertexAtIndex(bsp, f, (j + 1) % f->numedges);
const glm::vec3 v0pos = Vertex_GetPos_E(bsp, v0);
const glm::vec3 v1pos = Vertex_GetPos_E(bsp, v1);
auto it = edgeToFaceMap.find(make_pair(v1, v0));
if (it != edgeToFaceMap.end()) {
for (const bsp2_dface_t *neighbour : it->second) {
const int neighbourFNum = Face_GetNum(bsp, neighbour);
if (neighbour == f) {
// Invalid face, e.g. with vertex numbers: [0, 1, 0, 2]
continue;
}
// Check if these faces are smoothed or on the same plane
if (!(FacesSmoothed(f, neighbour) || neighbour->planenum == f->planenum)) {
// Never visit this face. Since we are exploring breadth-first from the reference face,
// once we have a non-smoothed edge, we don't want to "loop around" and include it later.
faceidx_handled->at(neighbourFNum) = true;
continue;
}
nextframes.push_back(neighbour);
}
}
}
return nextframes;
}
aabb2 FaceTexBounds(const bsp2_t *bsp, const bsp2_dface_t *f)
{
aabb2 result;
const glm::mat4x4 T = WorldToTexSpace(bsp, f);
for (int j = 0; j < f->numedges; j++) {
const int v0 = Face_VertexAtIndex(bsp, f, j);
const glm::vec3 v0_position = Vertex_GetPos_E(bsp, v0);
const glm::vec4 v0Tex = T * glm::vec4(v0_position[0], v0_position[1], v0_position[2], 1.0);
const glm::vec2 v0Tex2f = glm::vec2(v0Tex);
result = result.expand(v0Tex2f);
}
return result;
}
aabb3 FaceWorldBounds(const bsp2_t *bsp, const bsp2_dface_t *f)
{
aabb3 result;
for (int j = 0; j < f->numedges; j++) {
const int v0 = Face_VertexAtIndex(bsp, f, j);
const glm::vec3 v0_position = Vertex_GetPos_E(bsp, v0);
result = result.expand(v0_position);
}
return result;
}
std::vector<blocking_plane_t> BlockingPlanes(const bsp2_t *bsp, const bsp2_dface_t *f, const edgeToFaceMap_t &edgeToFaceMap)
{
vector<blocking_plane_t> blockers;
const glm::vec3 fNormal = Face_Normal_E(bsp, f);
for (int j = 0; j < f->numedges; j++) {
const int v0 = Face_VertexAtIndex(bsp, f, j);
const int v1 = Face_VertexAtIndex(bsp, f, (j + 1) % f->numedges);
const glm::vec3 v0pos = Vertex_GetPos_E(bsp, v0);
const glm::vec3 v1pos = Vertex_GetPos_E(bsp, v1);
auto it = edgeToFaceMap.find(make_pair(v1, v0));
if (it != edgeToFaceMap.end()) {
for (const bsp2_dface_t *neighbour : it->second) {
if (neighbour == f) {
// Invalid face, e.g. with vertex numbers: [0, 1, 0, 2]
continue;
}
// Check if these faces are smoothed or on the same plane
if (!(FacesSmoothed(f, neighbour) || neighbour->planenum == f->planenum)) {
// Not smoothed; add a blocker
pair<bool, glm::vec4> blocker = GLM_MakeInwardFacingEdgePlane(v0pos, v1pos, fNormal);
if (blocker.first) {
blockers.push_back(blocker.second);
}
}
}
}
}
return blockers;
}
/**
* For the given face, find all other faces that can contribute samples.
*
* For each face that can contribute samples, makes a transformation matrix
* from that face's texture space to this face's.
*
*
*
*/
vector<contributing_face_t> SetupContributingFaces(const bsp2_t *bsp, const bsp2_dface_t *face, const edgeToFaceMap_t &edgeToFaceMap)
{
vector<bool> faceidx_handled(static_cast<size_t>(bsp->numfaces), false);
vector<contributing_face_t> result;
const aabb2 refFaceTexBounds = FaceTexBounds(bsp, face);
const aabb3 refFaceWorldBounds = FaceWorldBounds(bsp, face);
// std::cout << "Face " << Face_GetNum(bsp, face)
// << " has tex bounds: "
// << refFaceTexBounds.min() << ", max:"
// << refFaceTexBounds.max() << std::endl
// << " has world bounds: "
// << refFaceWorldBounds.min() << ", max:"
// << refFaceWorldBounds.max() << std::endl;
// Breadth-first search, starting with `face`.
list<contribface_stackframe_t> queue { face };
while (!queue.empty()) {
const contribface_stackframe_t frame = queue.front();
queue.pop_front();
vector<contribface_stackframe_t> next = SetupContributingFaces_R(frame, bsp, edgeToFaceMap, face,
refFaceTexBounds, refFaceWorldBounds, &faceidx_handled, &result);
// Push the next frames on the back of the queue to get a BFS
for (const auto &frame : next) {
queue.push_back(frame);
}
}
return result;
}
all_contrib_faces_t MakeContributingFaces(const bsp2_t *bsp)
{
const edgeToFaceMap_t &edgeToFaceMap = GetEdgeToFaceMap();
logprint("--- MakeContributingFaces ---\n");
all_contrib_faces_t result;
for (int i = 0; i < bsp->numfaces; i++) {
const bsp2_dface_t *f = &bsp->dfaces[i];
auto contrib = SetupContributingFaces(bsp, f, edgeToFaceMap);
result[f] = contrib;
// printf("face %d (%s) has %d contributing faces\n",
// (int)i,
// Face_TextureName(bsp, f),
// (int)contrib.size());
}
return result;
}
static void AddFaceToBatch_R(const bsp2_t *bsp, const bsp2_dface_t *f, std::vector<bool> *faceidx_handled, std::vector<int> *batch)
{
const int fnum = Face_GetNum(bsp, f);
if (faceidx_handled->at(fnum))
return;
// add this face to the batch
faceidx_handled->at(fnum) = true;
batch->push_back(fnum);
// get touching faces either on the same plane, or phong shaded
for (const bsp2_dface_t *f2 : GetSmoothFaces(f)) {
AddFaceToBatch_R(bsp, f2, faceidx_handled, batch);
}
for (const bsp2_dface_t *f2 : GetPlaneFaces(f)) {
AddFaceToBatch_R(bsp, f2, faceidx_handled, batch);
}
}
/**
* Batch of faces that need to be lit together, on the same thread
*
* - If 2 faces are phong shaded across an edge, or line on the same plane and share an edge, they need to be lit together
*
* Light samples taken on one face might also contribute to other faces in a lightingbatch_t, but
* never to faces in another lightingbatch_t.
*/
batches_t MakeLightingBatches(const bsp2_t *bsp)
{
std::vector<bool> faceidx_handled(static_cast<size_t>(bsp->numfaces), false);
batches_t batches;
for (int i = 0; i < bsp->numfaces; i++) {
if (faceidx_handled.at(i))
continue;
std::vector<int> batch;
AddFaceToBatch_R(bsp, &bsp->dfaces[i], &faceidx_handled, &batch);
Q_assert(batch.size() > 0);
batches.push_back(batch);
}
//stats
int sum = 0;
int max = -1;
for (const auto &batch : batches) {
const int bs = static_cast<int>(batch.size());
sum += bs;
if (bs > max) {
max = bs;
}
}
Q_assert(sum == bsp->numfaces);
std::cout << "batches: " << batches.size() << " largest batch: " << max << std::endl;
return batches;
}
void *LightBatchThread(void *arg)
{
lightbatchthread_info_t *info = (lightbatchthread_info_t *)arg;
#ifdef HAVE_EMBREE
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
// _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
#endif
while (1) {
const int batchnum = GetThreadWork();
if (batchnum == -1)
break;
const auto &batch = info->all_batches.at(batchnum);
LightBatch(info->bsp, batch, info->all_contribFaces);
}
return NULL;
}

View File

@ -42,25 +42,6 @@ std::atomic<uint32_t> total_bounce_rays, total_bounce_ray_hits;
/* ======================================================================== */
/*
* ============================================================================
* SAMPLE POINT DETERMINATION
* void SetupBlock (bsp2_dface_t *f) Returns with surfpt[] set
*
* This is a little tricky because the lightmap covers more area than the face.
* If done in the straightforward fashion, some of the sample points will be
* inside walls or on the other side of walls, causing false shadows and light
* bleeds.
*
* To solve this, I only consider a sample point valid if a line can be drawn
* between it and the exact midpoint of the face. If invalid, it is adjusted
* towards the center until it is valid.
*
* FIXME: This doesn't completely work; I think what we really want is to move
* the light point to the nearst sample point that is on the polygon;
* ============================================================================
*/
static void
TexCoordToWorld(vec_t s, vec_t t, const texorg_t *texorg, vec3_t world)
{
@ -200,29 +181,6 @@ CalcFaceExtents(const bsp2_dface_t *face,
}
}
/*
* Print warning for CalcPoint where the midpoint of a polygon, one
* unit above the surface is covered by a solid brush.
*/
static void
WarnBadMidpoint(const vec3_t point)
{
#if 0
static qboolean warned = false;
if (warned)
return;
warned = true;
logprint("WARNING: unable to lightmap surface near (%s)\n"
" This is usually caused by an unintentional tiny gap between\n"
" two solid brushes which doesn't leave enough room for the\n"
" lightmap to fit (one world unit). Further instances of this\n"
" warning during this compile will be supressed.\n",
VecStr(point));
#endif
}
// from: http://stackoverflow.com/a/1501725
// see also: http://mathworld.wolfram.com/Projection.html
static float
@ -360,46 +318,6 @@ position_t CalcPointNormal(const bsp2_t *bsp, const bsp2_dface_t *face, const gl
#endif
}
static bool
CheckObstructed(const lightsurf_t *surf, const vec3_t offset, const vec_t us, const vec_t ut, vec3_t corrected)
{
for (int x = -1; x <= 1; x += 2) {
for (int y = -1; y <= 1; y += 2) {
vec3_t testpoint;
TexCoordToWorld(us + (x/10.0), ut + (y/10.0), &surf->texorg, testpoint);
VectorAdd(testpoint, offset, testpoint);
vec3_t dirn;
VectorSubtract(testpoint, surf->midpoint, dirn);
vec_t dist = VectorNormalize(dirn);
if (dist == 0.0f) {
continue; // testpoint == surf->midpoint
}
// trace from surf->midpoint to testpoint
{
vec_t hitdist = 0;
if (IntersectSingleModel(surf->midpoint, dirn, dist, surf->modelinfo->model, &hitdist)) {
// make a corrected point
VectorMA(surf->midpoint, qmax(0.0f, hitdist - 0.25f), dirn, corrected);
return true;
}
}
// also check against the world, fixes https://github.com/ericwa/tyrutils-ericw/issues/115
if (surf->modelinfo->model != &surf->bsp->dmodels[0]) {
vec_t hitdist = 0;
if (IntersectSingleModel(surf->midpoint, dirn, dist, &surf->bsp->dmodels[0], &hitdist)) {
// make a corrected point
VectorMA(surf->midpoint, qmax(0.0f, hitdist - 0.25f), dirn, corrected);
return true;
}
}
}
}
return false;
}
// Dump points to a .map file
static void
CalcPoints_Debug(const lightsurf_t *surf, const bsp2_t *bsp)
@ -518,130 +436,6 @@ PositionSamplePointOnFace(const bsp2_t *bsp,
return make_tuple(true, face, point, pointNormal);
}
static bool
PointAboveAllPlanes(const vector<blocking_plane_t> &planes, const glm::vec3 &point)
{
for (const blocking_plane_t &plane : planes) {
if (GLM_DistAbovePlane(plane, point) < -POINT_EQUAL_EPSILON) {
return false;
}
}
return true;
}
// returns false if the sample is in the void / couldn't be tweaked, true otherwise
// also returns the face the point was wrapped on to, and the output point
// postconditions: the returned point will be inside the returned face,
// so the caller can interpolate the normal.
static position_t
PositionSamplePoint(const bsp2_t *bsp,
const bsp2_dface_t *face,
const float face_lmscale,
const bool phongshaded,
const std::vector<glm::vec3> &facepoints,
const vector<vec4> &edgeplanes,
const vector<contributing_face_t> &contribfaces,
const vector<blocking_plane_t> &blockers,
const glm::vec3 &point)
{
// Cases to handle:
//
// 0. inside polygon (or on border)?
// a) in solid (world (only possible if the face is a bmodel) or shadow-caster)
// or on the border of a solid?
// => if on border of the polygon, nudge 1 unit inwards. check in solid again, use or drop.
// b) all good, use the point.
//
// 1. else, inside polygon of a "contributing" face?
// contributing faces are on the same plane (and reachable without leaving the plane to cross walls)
// or else reachable by crossing phong shaded neighbours.
//
// a) if we are allocating points for face Y, we may want to
// discard points that cross plane X to avoid light leaking around corners.
// _______________
// | | <-- "contributing face" for Y
// | o o o o x |
// |______________|
// | o o o o|
// | | <-- solid
// | face Y |<- plane X
// |________|
//
// b) if still OK, goto 0.
//
// 2. Now the point is either in a solid or floating over a gap.
//
// a) < 1 sample from polygon edge => snap to polygon edge + nudge 1 unit inwards.
// => goto 0.
// b) >= 1 sample => drop
//
// NOTE: we will need to apply minlight after downsampling, to avoid introducing fringes.
//
// Cases that should work:
// - thin geometry where no sample points are in the polygon
// - door touching world
// - door partly stuck into world with minlight
// - shadowcasting light fixture in middle of world face
// - world light fixture prone to leaking around
// - window (bmodel) with world bars crossing through it
if (GLM_EdgePlanes_PointInside(edgeplanes, point)) {
// 0. Inside polygon.
return PositionSamplePointOnFace(bsp, face, phongshaded, point);
}
// OK: we are outside of the polygon
// self check
const vec4 facePlane = Face_Plane_E(bsp, face);
Q_assert(fabs(GLM_DistAbovePlane(facePlane, point) - sampleOffPlaneDist) <= POINT_EQUAL_EPSILON);
// end self check
// Loop through all contributing faces, and "wrap" the point onto it.
// Check if the "wrapped" point is within that contributing face.
int inside = 0;
for (const auto &cf : contribfaces) {
// This "bends" point to be on the contributing face
const vec4 contribFacePlane = Face_Plane_E(bsp, cf.contribFace);
const vec3 wrappedPoint = GLM_ProjectPointOntoPlane(contribFacePlane, point)
+ (sampleOffPlaneDist * vec3(contribFacePlane));
// self check
Q_assert(fabs(GLM_DistAbovePlane(contribFacePlane, wrappedPoint) - sampleOffPlaneDist) <= POINT_EQUAL_EPSILON);
// end self check
if (GLM_EdgePlanes_PointInside(cf.contribFaceEdgePlanes, wrappedPoint)) {
inside++;
// Check for light bleed
if (PointAboveAllPlanes(blockers, wrappedPoint)) {
// 1.
return PositionSamplePointOnFace(bsp, cf.contribFace, phongshaded, wrappedPoint);
}
}
}
// 2. Try snapping to poly
const pair<int, vec3> closest = GLM_ClosestPointOnPolyBoundary(facepoints, point);
const float texSpaceDist = TexSpaceDist(bsp, face, closest.second, point);
if (texSpaceDist <= face_lmscale) {
// Snap it to the face edge. Add the 1 unit off plane.
const vec3 snapped = closest.second + (sampleOffPlaneDist * vec3(facePlane));
return PositionSamplePointOnFace(bsp, face, phongshaded, snapped);
}
// This point is too far from the polygon to be visible in game, so don't bother calculating lighting for it.
// Dont contribute to interpolating.
// We could safely colour it in pink for debugging.
return make_tuple(false, nullptr, point, glm::vec3());
}
/*
* =================
* CalcPoints
@ -660,14 +454,6 @@ CalcPoints(const modelinfo_t *modelinfo, const vec3_t offset, lightsurf_t *surf,
*/
TexCoordToWorld(surf->exactmid[0], surf->exactmid[1], &surf->texorg, surf->midpoint);
VectorAdd(surf->midpoint, offset, surf->midpoint);
#if 0
// Get faces which could contribute to this one.
const auto contribFaces = SetupContributingFaces(bsp, face, GetEdgeToFaceMap());
// Get edge planes of this face which will block light for the purposes of placing the sample points
// to avoid light leaks.
const auto blockers = BlockingPlanes(bsp, face, GetEdgeToFaceMap());
#endif
surf->width = (surf->texsize[0] + 1) * oversample;
surf->height = (surf->texsize[1] + 1) * oversample;
@ -697,18 +483,6 @@ CalcPoints(const modelinfo_t *modelinfo, const vec3_t offset, lightsurf_t *surf,
TexCoordToWorld(us, ut, &surf->texorg, point);
#if 0
const bool phongshaded = (surf->curved && cfg.phongallowed.boolValue());
const auto res = PositionSamplePoint(bsp, face, surf->lightmapscale, phongshaded,
points, edgeplanes, contribFaces, blockers, vec3_t_to_glm(point));
surf->occluded[i] = !get<0>(res);
glm_to_vec3_t(std::get<2>(res), point);
glm_to_vec3_t(std::get<3>(res), norm);
*realfacenum = Face_GetNum(bsp, std::get<1>(res));
VectorAdd(point, offset, point);
#else
// do this before correcting the point, so we can wrap around the inside of pipes
const bool phongshaded = (surf->curved && cfg.phongallowed.boolValue());
const auto res = CalcPointNormal(bsp, face, vec3_t_to_glm(point), phongshaded, surf->lightmapscale, 0);
@ -720,10 +494,6 @@ CalcPoints(const modelinfo_t *modelinfo, const vec3_t offset, lightsurf_t *surf,
// apply model offset after calling CalcPointNormal
VectorAdd(point, offset, point);
// corrects point
//CheckObstructed(surf, offset, us, ut, point);
#endif
}
}
@ -1267,13 +1037,6 @@ static void LightFace_SampleMipTex(miptex_t *tex, const float *projectionmatrix,
}
}
static void
ProjectPointOntoPlane(const vec3_t point, const plane_t *plane, vec3_t out)
{
vec_t dist = DotProduct(point, plane->normal) - plane->dist;
VectorMA(point, -dist, plane->normal, out);
}
// FIXME: factor out / merge with LightFace
void
GetDirectLighting(const globalconfig_t &cfg, raystream_t *rs, const vec3_t origin, const vec3_t normal, vec3_t colorout)
@ -1866,64 +1629,6 @@ LightFace_Bounce(const bsp2_t *bsp, const bsp2_dface_t *face, const lightsurf_t
Lightmap_Save(lightmaps, lightsurf, lightmap, 0);
}
static void
LightFace_ContribFacesDebug(const lightsurf_t *lightsurf, lightmapdict_t *lightmaps)
{
Q_assert(debugmode == debugmode_contribfaces);
const bsp2_dface_t *dumpface = &lightsurf->bsp->dfaces[dump_facenum];
const auto contribFaces = SetupContributingFaces(lightsurf->bsp, dumpface, GetEdgeToFaceMap());
const auto blockers = BlockingPlanes(lightsurf->bsp, dumpface, GetEdgeToFaceMap());
glm::vec3 color(0);
bool contribOrRef = false;
if (lightsurf->face == dumpface) {
color = glm::vec3(0,255,0);
contribOrRef = true;
} else {
for (const auto &cf : contribFaces) {
Q_assert(cf.refFace == dumpface);
Q_assert(cf.contribFace != cf.refFace);
if (cf.contribFace == lightsurf->face) {
color = glm::vec3(255,0,0);
contribOrRef = true;
break;
}
}
}
if (contribOrRef == false)
return;
/* use a style 0 light map */
lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, 0, lightsurf);
/* Overwrite each point with the debug color... */
for (int i = 0; i < lightsurf->numpoints; i++) {
const vec3 point = vec3_t_to_glm(lightsurf->points[i]);
lightsample_t *sample = &lightmap->samples[i];
// Check blockers
bool ok = true;
for (const auto &blocker : blockers) {
if (GLM_DistAbovePlane(blocker, point) < -POINT_EQUAL_EPSILON) {
ok = false;
break;
}
}
if (ok)
glm_to_vec3_t(color, sample->color);
else
VectorSet(sample->color, 0, 0, 255); // blue for "behind blocker"
}
Lightmap_Save(lightmaps, lightsurf, lightmap, 0);
}
static void
LightFace_OccludedDebug(lightsurf_t *lightsurf, lightmapdict_t *lightmaps)
{
@ -2815,9 +2520,6 @@ LightFace(const bsp2_t *bsp, bsp2_dface_t *face, facesup_t *facesup, const globa
if (debugmode == debugmode_bouncelights)
LightFace_BounceLightsDebug(lightsurf, lightmaps);
if (debugmode == debugmode_contribfaces)
LightFace_ContribFacesDebug(lightsurf, lightmaps);
if (debugmode == debugmode_debugoccluded)
LightFace_OccludedDebug(lightsurf, lightmaps);

View File

@ -178,440 +178,3 @@ glm::vec2 faceextents_t::worldToLMCoord(glm::vec3 world) const {
glm::vec3 faceextents_t::LMCoordToWorld(glm::vec2 lm) const {
return texCoordToWorld(LMCoordToTexCoord(lm));
}
class sample_t {
private:
glm::vec3 numerator;
float denominator;
public:
sample_t() : numerator(0.0f), denominator(0.0f) {}
void addWeightedValue(float weight, glm::vec3 value) {
Q_assert(weight >= 0.0f);
Q_assert(weight <= 1.0f);
numerator += weight * value;
denominator += weight;
}
glm::vec3 value() const {
return numerator / denominator;
}
bool hasValue() const {
return denominator != 0.0f;
}
};
static std::vector<glm::vec3> ConstantColor(const faceextents_t &ext, const glm::vec3 &color) {
std::vector<glm::vec3> res;
for (int i=0; i<ext.numsamples(); i++) {
res.push_back(color);
}
return res;
}
// holder for a face's lightmap texture
class face_samples_t {
public:
faceextents_t faceextents;
vector<sample_t> samples;
vector<glm::vec3> sampleWorldPos;
vector<glm::vec2> sampleTexPos;
face_samples_t() {
}
face_samples_t(const bsp2_t *bsp, const bsp2_dface_t *face) {
faceextents = {face, bsp, 16};
samples.resize(faceextents.numsamples());
sampleWorldPos.resize(faceextents.numsamples());
sampleTexPos.resize(faceextents.numsamples());
}
vector<glm::vec3> getColors() const {
vector<glm::vec3> result;
for (const auto &s : samples) {
result.push_back(s.value());
}
return result;
}
sample_t &mutableSampleAt(int x, int y) {
const int i = faceextents.indexOf(glm::ivec2(x, y));
return samples.at(i);
}
};
struct face_tris_t {
vector<float> areas;
vector<tuple<int,int,int>> tris;
vector<float> normalizedCDF;
glm::vec3 randomPoint(const bsp2_t *bsp) const {
const float triFloat = Random();
const int whichTri = SampleCDF(normalizedCDF, triFloat);
const auto tri = tris.at(whichTri);
tuple<glm::vec3, glm::vec3, glm::vec3> triPts = make_tuple(Vertex_GetPos_E(bsp, get<0>(tri)),
Vertex_GetPos_E(bsp, get<1>(tri)),
Vertex_GetPos_E(bsp, get<2>(tri)));
const glm::vec3 randomBary = Barycentric_Random(Random(), Random());
const glm::vec3 pt = Barycentric_ToPoint(randomBary, triPts);
return pt;
}
};
face_tris_t Face_MakeTris(const bsp2_t *bsp, const bsp2_dface_t *f)
{
face_tris_t res;
/* now just walk around the surface as a triangle fan */
int v1, v2, v3;
v1 = Face_VertexAtIndex(bsp, f, 0);
v2 = Face_VertexAtIndex(bsp, f, 1);
for (int j = 2; j < f->numedges; j++)
{
v3 = Face_VertexAtIndex(bsp, f, j);
const glm::vec3 p1 = Vertex_GetPos_E(bsp, v1);
const glm::vec3 p2 = Vertex_GetPos_E(bsp, v2);
const glm::vec3 p3 = Vertex_GetPos_E(bsp, v3);
const float area = GLM_TriangleArea(p1, p2, p3);
Q_assert(!isnan(area));
res.areas.push_back(area);
res.tris.push_back(make_tuple(v1, v2, v3));
v2 = v3;
}
res.normalizedCDF = MakeCDF(res.areas);
// testing
#if 0
const auto points = GLM_FacePoints(bsp, f);
const auto edgeplanes = GLM_MakeInwardFacingEdgePlanes(points);
if (!edgeplanes.empty()) {
plane_t pl = Face_Plane(bsp, f);
for (int i=0; i<1024; i++) {
glm::vec3 pt = res.randomPoint(bsp);
const float planeDist = DotProduct(&pt[0], pl.normal) - pl.dist;
Q_assert(planeDist < 0.1);
Q_assert(GLM_EdgePlanes_PointInside(edgeplanes, pt));
}
}
#endif
return res;
}
static void
WriteLightmap_Minimal(const bsp2_t *bsp, bsp2_dface_t *face, const faceextents_t &extents,
const std::vector<glm::vec3> &samples)
{
face->styles[0] = 0;
face->styles[1] = 255;
face->styles[2] = 255;
face->styles[3] = 255;
byte *out, *lit, *lux;
GetFileSpace(&out, &lit, &lux, extents.numsamples());
face->lightofs = out - filebase;
for (int t = 0; t < extents.height(); t++) {
for (int s = 0; s < extents.width(); s++) {
const int sampleindex = extents.indexOf(glm::ivec2(s, t));
const glm::vec3 &color = samples.at(sampleindex);
*lit++ = color[0];
*lit++ = color[1];
*lit++ = color[2];
/* Average the color to get the value to write to the
.bsp lightmap. this avoids issues with some engines
that require the lit and internal lightmap to have the same
intensity. (MarkV, some QW engines)
*/
vec_t light = LightSample_Brightness(color);
if (light < 0) light = 0;
if (light > 255) light = 255;
*out++ = light;
}
}
}
glm::vec4 extendTo4(const glm::vec3 &v) {
return glm::vec4(v[0], v[1], v[2], 1.0);
}
static glm::vec3 randomColor() {
return glm::vec3(Random(), Random(), Random()) * 255.0f;
}
struct sample_pos_t {
const bsp2_dface_t *face;
glm::vec3 worldpos;
glm::vec3 color;
};
const bsp2_dface_t *FaceAtPos(const bsp2_t *bsp, const glm::vec3 &pos) {
float minDist = FLT_MAX;
const bsp2_dface_t *bestFace = nullptr;
for (int i=0; i<bsp->numfaces; i++) {
const bsp2_dface_t *f = &bsp->dfaces[i];
glm::vec3 cen = Face_Centroid(bsp, f);
float len = glm::length(cen - pos);
if (len < minDist) {
minDist = len;
bestFace = f;
}
}
const glm::vec3 bcen = Face_Centroid(bsp, bestFace);
std::cout << "FaceAtPos: found face "
<< Face_GetNum(bsp, bestFace)
<< " with centroid "
<< glm::to_string(bcen)
<< " dist "
<< glm::length(bcen - pos)
<< std::endl;
return bestFace;
}
void
LightBatch(bsp2_t *bsp, const batch_t &batch, const all_contrib_faces_t &all_contrib_faces)
{
// self test for contributing faces
#if 0
for (int fnum : batch) {
const bsp2_dface_t *face = &bsp->dfaces[fnum];
const plane_t facePlane = Face_Plane(bsp, face);
const std::vector<contributing_face_t> &contribfaces = all_contrib_faces.at(face);
for (const auto &contribfaceinfo : contribfaces) {
Q_assert(contribfaceinfo.refFace == face);
const bsp2_dface_t *contribface = contribfaceinfo.contribFace;
// This transform should represent "unwrapping" the mesh between `face` and `contribface` so that `contribface` lies on the same plane as `face`.
for (int i=0; i<contribface->numedges; i++) {
const int v = Face_VertexAtIndex(bsp, contribface, i);
const glm::vec4 originalPos = extendTo4(Vertex_GetPos_E(bsp, v));
const glm::vec4 unwrappedPos = contribfaceinfo.contribWorldToRefWorld * glm::vec4(originalPos[0], originalPos[1], originalPos[2], 1.0);
float originalPlaneDist = glm::dot(glm::vec3(facePlane.normal[0],facePlane.normal[1],facePlane.normal[2]), glm::vec3(originalPos)) - facePlane.dist;
float unwrappedPlaneDist = glm::dot(glm::vec3(facePlane.normal[0],facePlane.normal[1],facePlane.normal[2]), glm::vec3(unwrappedPos)) - facePlane.dist;
if (fabs(originalPlaneDist) > 0.1) {
//printf("orig %f %f\n", originalPlaneDist, unwrappedPlaneDist);
Q_assert(fabs(unwrappedPlaneDist) < 0.1);
}
}
}
}
#endif
// good test case: give every face a random color
// => there should be smooth seams (without aliasing) between faces on the
// same plane
map<const bsp2_dface_t *, faceextents_t> extentsForFace;
for (int fnum : batch) {
const bsp2_dface_t *face = &bsp->dfaces[fnum];
extentsForFace[face] = faceextents_t {face, bsp, 16};
}
map<const bsp2_dface_t *, glm::vec3> colorForFace;
for (int fnum : batch) {
const bsp2_dface_t *face = &bsp->dfaces[fnum];
const glm::vec3 color = randomColor();
colorForFace[face] = color;
}
// build trisForFace
map<const bsp2_dface_t *, face_tris_t> trisForFace;
for (int fnum : batch) {
const bsp2_dface_t *face = &bsp->dfaces[fnum];
const face_tris_t tris = Face_MakeTris(bsp, face);
// check area
winding_t *w = WindingFromFace(bsp, face);
float wa = WindingArea(w);
float sum = 0;
for (auto ta : tris.areas) {
sum += ta;
}
if(fabs(wa - sum) > 0.01) {
printf("areas mismatch %g %g\n", wa, sum);
}
free(w);
trisForFace[face] = tris;
}
// generate 64 samples per face
map<const bsp2_dface_t *, vector<sample_pos_t>> samplePossForFace;
for (int fnum : batch) {
const bsp2_dface_t *face = &bsp->dfaces[fnum];
const face_tris_t &tris = trisForFace.at(face);
const glm::vec3 color = colorForFace.at(face);
const auto points = GLM_FacePoints(bsp, face);
const auto edgeplanes = GLM_MakeInwardFacingEdgePlanes(points);
if (edgeplanes.empty())
continue;
auto &vec = samplePossForFace[face];
for (int i=0; i<32; i++) {
sample_pos_t s;
s.face = face;
s.worldpos = tris.randomPoint(bsp);
s.color = color;
Q_assert(GLM_EdgePlanes_PointInside(edgeplanes, s.worldpos));
vec.push_back(s);
}
}
// build storage for final lightmaps
map<const bsp2_dface_t *, face_samples_t> faceSamples;
for (int fnum : batch) {
const bsp2_dface_t *face = &bsp->dfaces[fnum];
face_samples_t fs(bsp, face);
faceSamples[face] = fs;
}
// Now fill in the lightmaps...
for (int fnum : batch) {
const bsp2_dface_t *face = &bsp->dfaces[fnum];
face_samples_t &fs = faceSamples.at(face);
const face_tris_t &tris = trisForFace.at(face);
const faceextents_t &extents = extentsForFace.at(face);
const vector<sample_pos_t> &samples = samplePossForFace.at(face);
// affecing faces
const vector<contributing_face_t> &affectingFaces = all_contrib_faces.at(face);
// Find contributing samples, map them into our own texture space
vector<pair<glm::vec2, sample_pos_t>> contributingSamplesInTexSpace;
for (const contributing_face_t &contributingFace : affectingFaces) {
if (contributingFace.contribFace == face)
continue; // FIXME: make hard error
const auto face_points = GLM_FacePoints(bsp, face);
const auto face_edgeplanes = GLM_MakeInwardFacingEdgePlanes(face_points);
const auto contribface_points = GLM_FacePoints(bsp, contributingFace.contribFace);
const auto contribface_edgeplanes = GLM_MakeInwardFacingEdgePlanes(contribface_points);
const auto &samplePoss = samplePossForFace.at(contributingFace.contribFace);
for (const sample_pos_t &samplePos : samplePoss) {
Q_assert(face == contributingFace.refFace);
Q_assert(samplePos.face == contributingFace.contribFace);
const glm::vec4 refPlane = Face_Plane_E(bsp, face);
const glm::vec3 refWorld = GLM_ProjectPointOntoPlane(refPlane, samplePos.worldpos);
const glm::vec2 faceTC = WorldToTexCoord_HighPrecision(bsp, face, refWorld);
contributingSamplesInTexSpace.push_back(make_pair(faceTC, samplePos));
}
}
// Add our own samples
const auto &samplePoss = samplePossForFace.at(face);
for (const sample_pos_t &samplePos : samplePoss) {
const auto tc = extents.worldToTexCoord(samplePos.worldpos);
contributingSamplesInTexSpace.push_back(make_pair(tc, samplePos));
}
// color in all luxels, by applying a gaussian kernel to a single light sample in the centroid of the face
for (int y=0; y<extents.height(); y++) {
for (int x=0; x<extents.width(); x++) {
sample_t &mutableSample = fs.mutableSampleAt(x, y);
const glm::vec2 texCoord = extents.LMCoordToTexCoord(glm::vec2(x, y));
// loop thru samples
for (const auto &pr : contributingSamplesInTexSpace) {
const glm::vec2 dist = pr.first - texCoord;
float weight = glm::max(0.0f, 16.0f - glm::length(dist)) / 16.0f;
//if (glm::length(dist) < 16) {
mutableSample.addWeightedValue(weight, pr.second.color);
//}
}
}
}
}
// save out..
for (const auto &pr : faceSamples) {
bsp2_dface_t *face = const_cast<bsp2_dface_t *>(pr.first);
const auto &extents = extentsForFace.at(face);
WriteLightmap_Minimal(bsp, face, extents, pr.second.getColors());
}
}
#if 0
// begin test
const texinfo_t *tex = &bsp->texinfo[face->texinfo];
float uv[2];
vec3_t wp;
Face_PointAtIndex(bsp, face, 0, wp);
WorldToTexCoord(wp, tex, uv);
vec3_t wp_roundtrip;
TexCoordToWorld(uv[0], uv[1], &texorg, wp_roundtrip);
// printf("wp: %g %g %g\n tc: %g %g,\nrt: %g %g %g\n",
// wp[0], wp[1], wp[2],
// uv[0], uv[1],
// wp_roundtrip[0],
// wp_roundtrip[1],
// wp_roundtrip[2]
// );
//
// new method:
glm::mat4x4 WT = WorldToTexSpace(bsp, face);
glm::mat4x4 TW = TexSpaceToWorld(bsp, face);
glm::vec4 uv2 = WT * glm::vec4(wp[0], wp[1], wp[2], 1.0);
glm::vec4 wp2 = TW * glm::vec4(uv2[0], uv2[1], uv2[2], uv2[3]);
// printf("uv2: %g %g %g %g\n wp2: %g %g %g %g\n",
// uv2[0], uv2[1], uv2[2], uv2[3],
// wp2[0], wp2[1], wp2[2], wp2[3]
// );
Q_assert(fabs(uv2[2] - 0.0) < 0.01);
Q_assert(fabs(uv2[0] - uv[0]) < 0.01);
Q_assert(fabs(uv2[1] - uv[1]) < 0.01);
Q_assert(fabs(wp2[0] - wp[0]) < 0.01);
Q_assert(fabs(wp2[1] - wp[1]) < 0.01);
Q_assert(fabs(wp2[2] - wp[2]) < 0.01);
// end test
#endif