Browse Source

Store sampled light data per face vertex, so we can individually light each face without having to average lighting values.

Keeping averaged light per vertex intact for now, as sampling isn't quite perfect yet and I like to have some options.
master
Nico de Poel 3 years ago
parent
commit
f596c008d7
  1. 57
      main.cpp
  2. 15
      ps1bsp.h

57
main.cpp

@ -225,20 +225,20 @@ static void export_lightmap(const world_t* world, const face_t* face, const Boun
case 0: case 0:
case 3: case 3:
// Towards X // Towards X
width = ceil(bounds.max.y / 16) - floor(bounds.min.y / 16);
height = ceil(bounds.max.z / 16) - floor(bounds.min.z / 16);
width = (int)(ceil(bounds.max.y / 16) - floor(bounds.min.y / 16));
height = (int)(ceil(bounds.max.z / 16) - floor(bounds.min.z / 16));
break; break;
case 1: case 1:
case 4: case 4:
// Towards Y // Towards Y
width = ceil(bounds.max.x / 16) - floor(bounds.min.x / 16);
height = ceil(bounds.max.z / 16) - floor(bounds.min.z / 16);
width = (int)(ceil(bounds.max.x / 16) - floor(bounds.min.x / 16));
height = (int)(ceil(bounds.max.z / 16) - floor(bounds.min.z / 16));
break; break;
case 2: case 2:
case 5: case 5:
// Towards Z // Towards Z
width = ceil(bounds.max.x / 16) - floor(bounds.min.x / 16);
height = ceil(bounds.max.y / 16) - floor(bounds.min.y / 16);
width = (int)(ceil(bounds.max.x / 16) - floor(bounds.min.x / 16));
height = (int)(ceil(bounds.max.y / 16) - floor(bounds.min.y / 16));
break; break;
default: default:
printf("Error: unknown plane type %d\n", plane->type); printf("Error: unknown plane type %d\n", plane->type);
@ -297,23 +297,18 @@ int process_faces(const world_t* world)
outVertex.y = (short)(inVertex->Y * 4); outVertex.y = (short)(inVertex->Y * 4);
outVertex.z = (short)(inVertex->Z * 4); outVertex.z = (short)(inVertex->Z * 4);
} }
outVertex.baseLight = 0;
outVertex.finalLight = 0;
outVertex.r = 0;
outVertices.push_back(outVertex); outVertices.push_back(outVertex);
} }
std::vector<ps1bsp_triangle_t> outTriangles;
std::vector<ps1bsp_face_t> outFaces; std::vector<ps1bsp_face_t> outFaces;
std::vector<unsigned short> faceVertIndices;
std::vector<ps1bsp_facevertex_t> outFaceVertices;
for (int faceIdx = 0; faceIdx < world->numFaces; ++faceIdx) for (int faceIdx = 0; faceIdx < world->numFaces; ++faceIdx)
{ {
face_t* face = &world->faces[faceIdx]; face_t* face = &world->faces[faceIdx];
ps1bsp_face_t outFace = { 0 }; ps1bsp_face_t outFace = { 0 };
outFace.firstVertexIndex = faceVertIndices.size();
outFace.firstFaceVertex = (unsigned short)outFaceVertices.size();
// Traverse the list of face edges to collect all of the face's vertices // Traverse the list of face edges to collect all of the face's vertices
BoundBox bounds; BoundBox bounds;
@ -325,7 +320,10 @@ int process_faces(const world_t* world)
world->edges[edgeIdx].vertex0 : world->edges[edgeIdx].vertex0 :
world->edges[-edgeIdx].vertex1; world->edges[-edgeIdx].vertex1;
faceVertIndices.push_back(vertIndex);
ps1bsp_facevertex_t faceVertex;
faceVertex.index = vertIndex;
faceVertex.light = 0;
outFaceVertices.push_back(faceVertex);
// Calculate bounding box of this face // Calculate bounding box of this face
const vertex_t* vertex = &world->vertices[vertIndex]; const vertex_t* vertex = &world->vertices[vertIndex];
@ -335,15 +333,18 @@ int process_faces(const world_t* world)
bounds.includePoint(vertex->toVec()); bounds.includePoint(vertex->toVec());
} }
// Accumulate lightmap contribution of this face on each vertex
if (face->lightmap >= 0)
// Sample lightmap contribution of this face on each vertex
for (size_t faceVertIdx = outFace.firstFaceVertex; faceVertIdx < outFaceVertices.size(); ++faceVertIdx)
{ {
for (int indexIdx = outFace.firstVertexIndex; indexIdx < faceVertIndices.size(); ++indexIdx)
ps1bsp_facevertex_t& faceVertex = outFaceVertices[faceVertIdx];
unsigned char lightmap = sample_lightmap(world, face, bounds, world->vertices[faceVertex.index].toVec());
faceVertex.light = lightmap + (0xFF - face->baselight);
if (face->lightmap >= 0)
{ {
int vertIndex = faceVertIndices[indexIdx];
unsigned char light = sample_lightmap(world, face, bounds, world->vertices[vertIndex].toVec());
*(unsigned short*)(&outVertices[vertIndex].baseLight) += light + (0xFF - face->baselight);
outVertices[vertIndex].r++;
ps1bsp_vertex_t& vertex = outVertices[faceVertex.index];
*(unsigned short*)(&vertex.baseLight) += faceVertex.light;
vertex.r++;
} }
} }
@ -351,11 +352,11 @@ int process_faces(const world_t* world)
//if (face->ledge_num >= 10) //if (face->ledge_num >= 10)
// export_lightmap(world, face, bounds, faceIdx); // export_lightmap(world, face, bounds, faceIdx);
outFace.numVertices = faceVertIndices.size() - outFace.firstVertexIndex;
outFace.numFaceVertices = (unsigned short)(outFaceVertices.size() - outFace.firstFaceVertex);
outFaces.push_back(outFace); outFaces.push_back(outFace);
} }
// Average the lightmap values for this vertex
// Average the lightmap values for each vertex
for (auto iter = outVertices.begin(); iter != outVertices.end(); ++iter) for (auto iter = outVertices.begin(); iter != outVertices.end(); ++iter)
{ {
unsigned char count = (*iter).r; unsigned char count = (*iter).r;
@ -369,20 +370,20 @@ int process_faces(const world_t* world)
// Write triangle and face data to file // Write triangle and face data to file
fwrite(outVertices.data(), sizeof(ps1bsp_vertex_t), outVertices.size(), fbsp); fwrite(outVertices.data(), sizeof(ps1bsp_vertex_t), outVertices.size(), fbsp);
fwrite(faceVertIndices.data(), sizeof(unsigned short), faceVertIndices.size(), fbsp);
fwrite(outFaceVertices.data(), sizeof(ps1bsp_facevertex_t), outFaceVertices.size(), fbsp);
fwrite(outFaces.data(), sizeof(ps1bsp_face_t), outFaces.size(), fbsp); fwrite(outFaces.data(), sizeof(ps1bsp_face_t), outFaces.size(), fbsp);
// Update header information // Update header information
outHeader.numVertices = outVertices.size();
outHeader.numFaceVertIndices = faceVertIndices.size();
outHeader.numFaces = outFaces.size();
outHeader.numVertices = (unsigned short)outVertices.size();
outHeader.numFaceVertices = (unsigned short)outFaceVertices.size();
outHeader.numFaces = (unsigned short)outFaces.size();
// Write final header // Write final header
fseek(fbsp, 0, SEEK_SET); fseek(fbsp, 0, SEEK_SET);
fwrite(&outHeader, sizeof(ps1bsp_header_t), 1, fbsp); fwrite(&outHeader, sizeof(ps1bsp_header_t), 1, fbsp);
fclose(fbsp); fclose(fbsp);
printf("PS1BSP: wrote %d vertices, %d indices, %d faces\n", outHeader.numVertices, outHeader.numFaceVertIndices, outHeader.numFaces);
printf("PS1BSP: wrote %d vertices, %d indices, %d faces\n", outHeader.numVertices, outHeader.numFaceVertices, outHeader.numFaces);
return 1; return 1;
} }

15
ps1bsp.h

@ -22,7 +22,7 @@ Probable rendering process:
typedef struct typedef struct
{ {
unsigned short numVertices; unsigned short numVertices;
unsigned short numFaceVertIndices;
unsigned short numFaceVertices;
unsigned short numFaces; unsigned short numFaces;
} ps1bsp_header_t; } ps1bsp_header_t;
@ -51,19 +51,16 @@ typedef struct
unsigned char b : 5; unsigned char b : 5;
} ps1bsp_vertex_t; } ps1bsp_vertex_t;
// Instead of edges as in the original BSP format, we store triangles for easy consumption by the PS1
// Note: it may actually be more efficient to render quads for faces with 4+ vertices
typedef struct typedef struct
{ {
unsigned short vertex0;
unsigned short vertex1;
unsigned short vertex2;
} ps1bsp_triangle_t;
unsigned short index;
unsigned char light;
} ps1bsp_facevertex_t;
typedef struct typedef struct
{ {
unsigned short firstVertexIndex;
unsigned short numVertices;
unsigned short firstFaceVertex;
unsigned short numFaceVertices;
} ps1bsp_face_t; } ps1bsp_face_t;
// Pre-parsed and encoded entity data (this runs the risk of becoming too bloated) // Pre-parsed and encoded entity data (this runs the risk of becoming too bloated)

Loading…
Cancel
Save