From 568f2450eb03329e6f5c58b5da93877367e508e1 Mon Sep 17 00:00:00 2001 From: Nico de Poel Date: Wed, 25 Jan 2023 11:40:10 +0100 Subject: [PATCH] Added a new lighting sampler to take advantage of the improved lightmap indexing: use a pseudo-random jitter pattern to take multiple light samples in an area around the sample point, from all surrounding faces at a shallow angle. This further smooths out the lighting and reduces artifacts, while also better representing each face's entire lightmap. --- bsp.h | 34 +++++++++++++++++++++++++++++++--- lighting.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ lighting.h | 1 + main.cpp | 2 +- 4 files changed, 81 insertions(+), 4 deletions(-) diff --git a/bsp.h b/bsp.h index f954e57..97447e0 100644 --- a/bsp.h +++ b/bsp.h @@ -35,13 +35,42 @@ typedef struct // The BSP file header // nummodels = Size/sizeof(model_t) } dheader_t; -typedef struct +typedef struct Plane { vec3_t normal; // Vector orthogonal to plane (Nx,Ny,Nz) // with Nx2+Ny2+Nz2 = 1 scalar_t dist; // Offset to plane, along the normal vector. // Distance from (0,0,0) to the plane long type; // Type of plane, depending on normal vector. + + double pointDistance(const Vec3& point) const + { + return normal.dotProduct(point) - dist; + } + + void getTangents(Vec3& tangent, Vec3& bitangent) const + { + Vec3 dir; + switch (type) + { + case 0: + case 3: + dir = Vec3(0.f, 1.f, 0.f); + break; + case 1: + case 4: + default: + dir = Vec3(0.f, 0.f, 1.f); + break; + case 2: + case 5: + dir = Vec3(1.f, 0.f, 0.f); + break; + } + + tangent = normal.crossProduct(dir).normalized(); + bitangent = tangent.crossProduct(normal); + } } plane_t; typedef struct BoundBox // Bounding Box, Float values @@ -238,8 +267,7 @@ typedef struct World const plane_t* plane = &planes[face->plane_id]; // Check if the point lies on the face's plane (it's not strictly necessary to do this, but this check makes the whole function a lot faster) - double pointPlaneDist = point.dotProduct(plane->normal) - plane->dist; - if (fabs(pointPlaneDist) > 0.001) + if (fabs(plane->pointDistance(point)) > 0.001) continue; // Check if the point is contained within the face's polygon diff --git a/lighting.cpp b/lighting.cpp index 03167c4..bde36fd 100644 --- a/lighting.cpp +++ b/lighting.cpp @@ -373,3 +373,51 @@ unsigned char compute_faceVertex_light4(const world_t* world, const face_t* refF // We should always end up with at least one sample (that from refFace itself), so if we divide by zero here something is very much wrong return (unsigned char)(light / numSamples); } + +unsigned char compute_faceVertex_light5(const world_t* world, const face_t* refFace, const FaceBounds& faceBounds, Vec3 point) +{ + const int phaseCount = 18; + const float sampleRange = 16; // Increasing this value allows lightmap samples from further away + + if (refFace->lightmap < 0) + return 0; + + auto faces = world->facesWithPoint(point); + if (faces.empty()) + return 0; + + const Plane* refPlane = &world->planes[refFace->plane_id]; + Vec3 refNormal = refFace->side ? -refPlane->normal : refPlane->normal; + + Vec3 tangent, bitangent; + refPlane->getTangents(tangent, bitangent); + + Vec3 jitter; + unsigned int light = 0, numSamples = 0; + for (int index = 0; index < phaseCount; ++index) + { + getJitterOffset(&jitter.x, &jitter.y, index, phaseCount); + Vec3 jitteredPoint = point + (tangent * jitter.x + bitangent * jitter.y) * sampleRange; + + for (auto faceIter = faces.begin(); faceIter != faces.end(); ++faceIter) + { + const face_t* face = *faceIter; + const plane_t* plane = &world->planes[face->plane_id]; + vec3_t normal = face->side ? -plane->normal : plane->normal; + + // Check if the face is at a shallow angle with the reference face + double dot = normal.dotProduct(refNormal); + if (dot < 0.5) + continue; + + unsigned char sample; + if (!sample_lightmap(world, face, faceBounds.find(face)->second, jitteredPoint, &sample)) + continue; + + light += sample + (0xFF - face->baselight); + numSamples++; + } + } + + return (unsigned char)(light / numSamples); +} diff --git a/lighting.h b/lighting.h index 75ea3f7..b010a79 100644 --- a/lighting.h +++ b/lighting.h @@ -29,3 +29,4 @@ unsigned char compute_faceVertex_light2(const world_t* world, const face_t* face SurfaceList group_surfaces(const world_t* world, const VertexFaces& vertexFaces); unsigned char compute_faceVertex_light4(const world_t* world, const face_t* refFace, const FaceBounds& faceBounds, Vec3 point); +unsigned char compute_faceVertex_light5(const world_t* world, const face_t* refFace, const FaceBounds& faceBounds, Vec3 point); diff --git a/main.cpp b/main.cpp index 68b6a4b..0176e7c 100644 --- a/main.cpp +++ b/main.cpp @@ -217,7 +217,7 @@ int process_faces(const world_t* world, const std::vector& tex { ps1bsp_facevertex_t& faceVertex = outFaceVertices[outFace.firstFaceVertex + faceVertIdx]; const vertex_t* vertex = &world->vertices[faceVertex.index]; - faceVertex.light = compute_faceVertex_light4(world, face, faceBounds, vertex->toVec()); + faceVertex.light = compute_faceVertex_light5(world, face, faceBounds, vertex->toVec()); faceVertex.light = (short)((float)faceVertex.light * 1.5f); if (faceVertex.light > 255) faceVertex.light = 255;