light: delete some dead code
This commit is contained in:
parent
a6f56d9111
commit
69d5669773
|
|
@ -157,7 +157,6 @@ typedef enum {
|
|||
debugmode_dirt,
|
||||
debugmode_bounce,
|
||||
debugmode_bouncelights,
|
||||
debugmode_contribfaces,
|
||||
debugmode_debugoccluded
|
||||
} debugmode_t;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
330
light/light2.cc
330
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<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;
|
||||
}
|
||||
|
|
|
|||
298
light/ltface.cc
298
light/ltface.cc
|
|
@ -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
|
||||
|
|
@ -661,14 +455,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;
|
||||
const float starts = (surf->texmins[0] - 0.5 + (0.5 / oversample)) * surf->lightmapscale;
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
@ -2816,9 +2521,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);
|
||||
|
||||
|
|
|
|||
437
light/ltface2.cc
437
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<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
|
||||
|
|
|
|||
Loading…
Reference in New Issue