Browse Source

Improved lightmap sampling accuracy. The generated UVs now more closely match what Quake is doing, we can reject invalid UVs, and we're getting less false rejects of valid faces to sample from.

master
Nico de Poel 3 years ago
parent
commit
161ef0acee
  1. 6
      bsp.h
  2. 10
      common.h
  3. 58
      lighting.cpp
  4. 1
      lighting.h

6
bsp.h

@ -239,7 +239,7 @@ typedef struct World
// 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) // 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 = ((double)point.x * plane->normal.x + (double)point.y * plane->normal.y + (double)point.z * plane->normal.z) - plane->dist; double pointPlaneDist = ((double)point.x * plane->normal.x + (double)point.y * plane->normal.y + (double)point.z * plane->normal.z) - plane->dist;
if (fabs(pointPlaneDist) > 0.0001)
if (fabs(pointPlaneDist) > 0.001)
continue; continue;
// Check if the point is contained within the face's polygon // Check if the point is contained within the face's polygon
@ -267,7 +267,7 @@ typedef struct World
double m0 = p0.magnitude(); double m0 = p0.magnitude();
double m1 = p1.magnitude(); double m1 = p1.magnitude();
if ((m0 * m1) <= 0.0001)
if ((m0 * m1) <= 0.001)
{ {
// Point is on one of the vertices // Point is on one of the vertices
outFaces.push_back(face); outFaces.push_back(face);
@ -279,7 +279,7 @@ typedef struct World
} }
// If the point is inside the polygon, then the sum of all the above angles will be exactly 360 degrees // If the point is inside the polygon, then the sum of all the above angles will be exactly 360 degrees
if (fabs(2 * M_PI - angleSum) <= 0.0001)
if (fabs(2 * M_PI - angleSum) <= 0.001)
outFaces.push_back(face); outFaces.push_back(face);
} }

10
common.h

@ -65,4 +65,14 @@ typedef struct Vec3 // Vector or Position
{ {
return Vec3(y * other.z - z * other.y, z * other.x - x * other.z, x * other.y - y * other.x); return Vec3(y * other.z - z * other.y, z * other.x - x * other.z, x * other.y - y * other.x);
} }
Vec3 floor() const
{
return Vec3(floorf(x), floorf(y), floorf(z));
}
Vec3 ceil() const
{
return Vec3(ceilf(x), ceilf(y), ceilf(z));
}
} vec3_t; } vec3_t;

58
lighting.cpp

@ -1,51 +1,64 @@
#include "common.h" #include "common.h"
#include "lighting.h" #include "lighting.h"
unsigned char sample_lightmap(const world_t* world, const face_t* face, const BoundBox& bounds, const Vec3& point)
bool sample_lightmap(const world_t* world, const face_t* face, const BoundBox& bounds, const Vec3& point, unsigned char* outSample)
{ {
if (face->lightmap < 0) if (face->lightmap < 0)
return 0;
return false;
const unsigned char* lightmap = &world->lightmap[face->lightmap]; const unsigned char* lightmap = &world->lightmap[face->lightmap];
const plane_t* plane = &world->planes[face->plane_id]; const plane_t* plane = &world->planes[face->plane_id];
Vec3 minBounds = (bounds.min / 16).floor() * 16;
Vec3 maxBounds = (bounds.max / 16).ceil() * 16;
int width, height; int width, height;
float u, v;
int u, v;
switch (plane->type) switch (plane->type)
{ {
case 0: case 0:
case 3: case 3:
// Towards X // Towards X
width = (int)(ceil(bounds.max.y / 16) - floor(bounds.min.y / 16)) * 16;
height = (int)(ceil(bounds.max.z / 16) - floor(bounds.min.z / 16)) * 16;
u = (point.y - bounds.min.y) / (bounds.max.y - bounds.min.y);
v = (point.z - bounds.min.z) / (bounds.max.z - bounds.min.z);
width = (int)(maxBounds.y - minBounds.y);
height = (int)(maxBounds.z - minBounds.z);
u = (int)(point.y - minBounds.y);
v = (int)(point.z - minBounds.z);
break; break;
case 1: case 1:
case 4: case 4:
// Towards Y // Towards Y
width = (int)(ceil(bounds.max.x / 16) - floor(bounds.min.x / 16)) * 16;
height = (int)(ceil(bounds.max.z / 16) - floor(bounds.min.z / 16)) * 16;
u = (point.x - bounds.min.x) / (bounds.max.x - bounds.min.x);
v = (point.z - bounds.min.z) / (bounds.max.z - bounds.min.z);
width = (int)(maxBounds.x - minBounds.x);
height = (int)(maxBounds.z - minBounds.z);
u = (int)(point.x - minBounds.x);
v = (int)(point.z - minBounds.z);
break; break;
case 2: case 2:
case 5: case 5:
// Towards Z // Towards Z
width = (int)(ceil(bounds.max.x / 16) - floor(bounds.min.x / 16)) * 16;
height = (int)(ceil(bounds.max.y / 16) - floor(bounds.min.y / 16)) * 16;
u = (point.x - bounds.min.x) / (bounds.max.x - bounds.min.x);
v = (point.y - bounds.min.y) / (bounds.max.y - bounds.min.y);
width = (int)(maxBounds.x - minBounds.x);
height = (int)(maxBounds.y - minBounds.y);
u = (int)(point.x - minBounds.x);
v = (int)(point.y - minBounds.y);
break; break;
default: default:
printf("Error: unknown plane type %d\n", plane->type); printf("Error: unknown plane type %d\n", plane->type);
return 0; return 0;
} }
height >>= 4;
width >>= 4;
if (u < 0 || v < 0 || u > width || v > height)
return false;
return lightmap[(int)(v * (width + 1) + u)];
*outSample = lightmap[(v >> 4) * (width >> 4) + (u >> 4)];
return true;
}
unsigned char sample_lightmap(const world_t* world, const face_t* face, const BoundBox& bounds, const Vec3& point)
{
unsigned char sample;
if (!sample_lightmap(world, face, bounds, point, &sample))
return 0;
return sample;
} }
void export_lightmap(const world_t* world, const face_t* face, const BoundBox& bounds, int faceIdx) void export_lightmap(const world_t* world, const face_t* face, const BoundBox& bounds, int faceIdx)
@ -327,6 +340,9 @@ 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_light4(const world_t* world, const face_t* refFace, const FaceBounds& faceBounds, Vec3 point)
{ {
if (refFace->lightmap < 0)
return 0;
auto faces = world->facesWithPoint(point); auto faces = world->facesWithPoint(point);
if (faces.empty()) if (faces.empty())
return 0; return 0;
@ -346,7 +362,11 @@ unsigned char compute_faceVertex_light4(const world_t* world, const face_t* refF
if (dot < 0.5f) if (dot < 0.5f)
continue; continue;
light += sample_lightmap(world, face, faceBounds.find(face)->second, point) + (0xFF - face->baselight);
unsigned char sample;
if (!sample_lightmap(world, face, faceBounds.find(face)->second, point, &sample))
continue;
light += sample + (0xFF - face->baselight);
numSamples++; numSamples++;
} }

1
lighting.h

@ -19,6 +19,7 @@ typedef std::unordered_map<const face_t*, BoundBox> FaceBounds;
typedef std::unordered_map<const vertex_t*, std::unordered_set<const face_t*>> VertexFaces; typedef std::unordered_map<const vertex_t*, std::unordered_set<const face_t*>> VertexFaces;
typedef std::vector<Surface> SurfaceList; typedef std::vector<Surface> SurfaceList;
bool sample_lightmap(const world_t* world, const face_t* face, const BoundBox& bounds, const Vec3& point, unsigned char* outSample);
unsigned char sample_lightmap(const world_t* world, const face_t* face, const BoundBox& bounds, const Vec3& point); unsigned char sample_lightmap(const world_t* world, const face_t* face, const BoundBox& bounds, const Vec3& point);
void export_lightmap(const world_t* world, const face_t* face, const BoundBox& bounds, int faceIdx); void export_lightmap(const world_t* world, const face_t* face, const BoundBox& bounds, int faceIdx);

Loading…
Cancel
Save