diff --git a/include/light/light.hh b/include/light/light.hh index 6b6d7b66..3051a4d0 100644 --- a/include/light/light.hh +++ b/include/light/light.hh @@ -157,7 +157,6 @@ typedef enum { debugmode_dirt, debugmode_bounce, debugmode_bouncelights, - debugmode_contribfaces, debugmode_debugoccluded } debugmode_t; diff --git a/include/light/light2.hh b/include/light/light2.hh index d03d492b..bd5bc36e 100644 --- a/include/light/light2.hh +++ b/include/light/light2.hh @@ -45,34 +45,6 @@ #include #include - -using batch_t = std::vector; -using batches_t = std::vector; - -class contributing_face_t { -public: - const bsp2_dface_t *contribFace; - const bsp2_dface_t *refFace; - - std::vector contribFaceEdgePlanes; -}; - -using all_contrib_faces_t = std::map>; -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 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 SetupContributingFaces(const bsp2_t *bsp, const bsp2_dface_t *face, const edgeToFaceMap_t &edgeToFaceMap); - std::pair RotationAboutLineSegment(glm::vec3 p0, glm::vec3 p1, glm::vec3 face0Norm, glm::vec3 face1Norm); diff --git a/include/light/ltface2.hh b/include/light/ltface2.hh index 0a6675fb..a8d2d1ab 100644 --- a/include/light/ltface2.hh +++ b/include/light/ltface2.hh @@ -31,7 +31,6 @@ #include 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: diff --git a/light/light.cc b/light/light.cc index 9f041b59..b09f531d 100644 --- a/light/light.cc +++ b/light/light.cc @@ -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; diff --git a/light/light2.cc b/light/light2.cc index a49a5e21..2ac2514b 100644 --- a/light/light2.cc +++ b/light/light2.cc @@ -103,333 +103,3 @@ glm::mat4x4 TexSpaceToWorld(const bsp2_t *bsp, const bsp2_dface_t *f) return glm::inverse(T); } - -using bbox2 = pair; -using bbox3 = pair; - -using contribface_stackframe_t = const bsp2_dface_t *; - -// Returns the next stack frames to process -vector 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 *faceidx_handled, - vector *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 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 BlockingPlanes(const bsp2_t *bsp, const bsp2_dface_t *f, const edgeToFaceMap_t &edgeToFaceMap) -{ - vector 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 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 SetupContributingFaces(const bsp2_t *bsp, const bsp2_dface_t *face, const edgeToFaceMap_t &edgeToFaceMap) -{ - vector faceidx_handled(static_cast(bsp->numfaces), false); - vector 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 queue { face }; - - while (!queue.empty()) { - const contribface_stackframe_t frame = queue.front(); - queue.pop_front(); - - vector 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 *faceidx_handled, std::vector *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 faceidx_handled(static_cast(bsp->numfaces), false); - - batches_t batches; - - for (int i = 0; i < bsp->numfaces; i++) { - if (faceidx_handled.at(i)) - continue; - - std::vector 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(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; -} diff --git a/light/ltface.cc b/light/ltface.cc index d083634a..f9e8b22c 100644 --- a/light/ltface.cc +++ b/light/ltface.cc @@ -42,25 +42,6 @@ std::atomic 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 &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 &facepoints, - const vector &edgeplanes, - const vector &contribfaces, - const vector &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 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); diff --git a/light/ltface2.cc b/light/ltface2.cc index def65cdf..95754f00 100644 --- a/light/ltface2.cc +++ b/light/ltface2.cc @@ -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 ConstantColor(const faceextents_t &ext, const glm::vec3 &color) { - std::vector res; - for (int i=0; i samples; - vector sampleWorldPos; - vector 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 getColors() const { - vector 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 areas; - vector> tris; - - vector 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 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 &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; inumfaces; 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 &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; inumedges; 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 extentsForFace; - for (int fnum : batch) { - const bsp2_dface_t *face = &bsp->dfaces[fnum]; - extentsForFace[face] = faceextents_t {face, bsp, 16}; - } - - map colorForFace; - for (int fnum : batch) { - const bsp2_dface_t *face = &bsp->dfaces[fnum]; - const glm::vec3 color = randomColor(); - - colorForFace[face] = color; - } - - // build trisForFace - map 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> 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 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 &samples = samplePossForFace.at(face); - - // affecing faces - const vector &affectingFaces = all_contrib_faces.at(face); - - // Find contributing samples, map them into our own texture space - vector> 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(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