Browse Source

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.
master
Nico de Poel 3 years ago
parent
commit
568f2450eb
  1. 34
      bsp.h
  2. 48
      lighting.cpp
  3. 1
      lighting.h
  4. 2
      main.cpp

34
bsp.h

@ -35,13 +35,42 @@ typedef struct // The BSP file header
// nummodels = Size/sizeof(model_t) // nummodels = Size/sizeof(model_t)
} dheader_t; } dheader_t;
typedef struct
typedef struct Plane
{ {
vec3_t normal; // Vector orthogonal to plane (Nx,Ny,Nz) vec3_t normal; // Vector orthogonal to plane (Nx,Ny,Nz)
// with Nx2+Ny2+Nz2 = 1 // with Nx2+Ny2+Nz2 = 1
scalar_t dist; // Offset to plane, along the normal vector. scalar_t dist; // Offset to plane, along the normal vector.
// Distance from (0,0,0) to the plane // Distance from (0,0,0) to the plane
long type; // Type of plane, depending on normal vector. 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; } plane_t;
typedef struct BoundBox // Bounding Box, Float values typedef struct BoundBox // Bounding Box, Float values
@ -238,8 +267,7 @@ typedef struct World
const plane_t* plane = &planes[face->plane_id]; 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) // 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; continue;
// Check if the point is contained within the face's polygon // Check if the point is contained within the face's polygon

48
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 // 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); 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);
}

1
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); 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);
unsigned char compute_faceVertex_light5(const world_t* world, const face_t* refFace, const FaceBounds& faceBounds, Vec3 point);

2
main.cpp

@ -217,7 +217,7 @@ int process_faces(const world_t* world, const std::vector<ps1bsp_texture_t>& tex
{ {
ps1bsp_facevertex_t& faceVertex = outFaceVertices[outFace.firstFaceVertex + faceVertIdx]; ps1bsp_facevertex_t& faceVertex = outFaceVertices[outFace.firstFaceVertex + faceVertIdx];
const vertex_t* vertex = &world->vertices[faceVertex.index]; 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); faceVertex.light = (short)((float)faceVertex.light * 1.5f);
if (faceVertex.light > 255) if (faceVertex.light > 255)
faceVertex.light = 255; faceVertex.light = 255;

Loading…
Cancel
Save