diff --git a/bsp.h b/bsp.h index c6841d8..be9ff20 100644 --- a/bsp.h +++ b/bsp.h @@ -49,7 +49,7 @@ typedef struct BoundBox // Bounding Box, Float values vec3_t min; // minimum values of X,Y,Z vec3_t max; // maximum values of X,Y,Z - BoundBox() { } + BoundBox(): min(FLT_MAX, FLT_MAX, FLT_MAX), max(FLT_MIN, FLT_MIN, FLT_MIN) { } void init(vec3_t point) { @@ -75,10 +75,19 @@ typedef struct BoundBox // Bounding Box, Float values } } boundbox_t; -typedef struct // Bounding Box, Short values +typedef struct BBoxShort // Bounding Box, Short values { short min[3]; // minimum values of X,Y,Z short max[3]; // maximum values of X,Y,Z + + vec3_t getCenter() const + { + return vec3_t( + ((float)max[0] + (float)min[0]) / 2, + ((float)max[1] + (float)min[1]) / 2, + ((float)max[2] + (float)min[2]) / 2 + ); + } } bboxshort_t; typedef struct // Mip texture list header diff --git a/common.h b/common.h index 9fe56f3..dc6cc3c 100644 --- a/common.h +++ b/common.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,16 @@ typedef struct Vec3 // Vector or Position return Vec3(x + other.x, y + other.y, z + other.z); } + Vec3 operator-(const Vec3& other) const + { + return Vec3(x - other.x, y - other.y, z - other.z); + } + + Vec3 operator*(float mul) const + { + return Vec3(x * mul, y * mul, z * mul); + } + Vec3 operator/(float div) const { return Vec3(x / div, y / div, z / div); @@ -32,9 +43,25 @@ typedef struct Vec3 // Vector or Position { return Vec3(-x, -y, -z); } -} vec3_t; -inline float dotProduct(vec3_t a, vec3_t b) -{ - return a.x * b.x + a.y * b.y + a.z * b.z; -} + float magnitude() const + { + return sqrtf(x * x + y * y + z * z); + } + + Vec3 normalized() const + { + float invMag = 1.0f / magnitude(); + return Vec3(x * invMag, y * invMag, z * invMag); + } + + float dotProduct(const Vec3 &other) const + { + return x * other.x + y * other.y + z * other.z; + } + + Vec3 crossProduct(const Vec3 &other) const + { + return Vec3(y * other.z - z * other.y, z * other.x - x * other.z, x * other.y - y * other.x); + } +} vec3_t; diff --git a/lighting.cpp b/lighting.cpp index d899d9e..306556c 100644 --- a/lighting.cpp +++ b/lighting.cpp @@ -147,7 +147,7 @@ std::unordered_map analyze_edges(const world_t* world) const plane_t* planeB = &world->planes[faceB->plane_id]; vec3_t normalA = faceA->side ? -planeA->normal : planeA->normal; vec3_t normalB = faceB->side ? -planeB->normal : planeB->normal; - float dot = dotProduct(normalA, normalB); + float dot = normalA.dotProduct(normalB); bool isSmooth = dot >= 0.5f;//&& dot <= 1; iter->second.isSharpEdge = !isSmooth; break; @@ -239,7 +239,7 @@ unsigned char compute_faceVertex_light2(const world_t* world, const face_t* face const plane_t* otherPlane = &world->planes[otherFace->plane_id]; vec3_t otherNormal = otherFace->side ? -otherPlane->normal : otherPlane->normal; - float dot = dotProduct(thisNormal, otherNormal); + float dot = thisNormal.dotProduct(otherNormal); if (dot < 0.5f) continue; // Sharp edge, we don't want light contribution from this face @@ -249,3 +249,8 @@ unsigned char compute_faceVertex_light2(const world_t* world, const face_t* face return (unsigned char)(light / numSamples); } + +// Further improvements: +// - Reconstruct connected surfaces through vertices and edges, so we can fully sample all adjacent lightmaps. +// Right now we don't properly detect when one face has vertices halfway along the edge of an adjacent face. +// - Sample more lightmap points around each vertex to obtain a more representative average value diff --git a/main.cpp b/main.cpp index 5d9607e..decb936 100644 --- a/main.cpp +++ b/main.cpp @@ -179,7 +179,7 @@ static SVECTOR convertNormal(vec3_t normal) return outNormal; } -static SVECTOR convertPoint(vec3_t point) +static SVECTOR convertWorldPosition(vec3_t point) { SVECTOR outPoint; outPoint.vx = (short)(point.x * 4); @@ -189,6 +189,42 @@ static SVECTOR convertPoint(vec3_t point) return outPoint; } +static float computeFaceArea(const world_t* world, const face_t* face) +{ + const plane_t* plane = &world->planes[face->plane_id]; + + // Construct a tangent and bitangent for the plane using the face's first vertex + int edgeIdx = world->edgeList[face->ledge_id]; + unsigned short vertIndex = edgeIdx > 0 ? + world->edges[edgeIdx].vertex0 : + world->edges[-edgeIdx].vertex1; + + const vertex_t* vertex = &world->vertices[vertIndex]; + Vec3 refPoint = plane->normal * plane->dist; + Vec3 tangent = (vertex->toVec() - refPoint).normalized(); + Vec3 bitangent = plane->normal.crossProduct(tangent); + + // Project all face vertices onto the face's plane + BoundBox bounds; + for (int edgeListIdx = 0; edgeListIdx < face->ledge_num; ++edgeListIdx) + { + edgeIdx = world->edgeList[face->ledge_id + edgeListIdx]; + vertIndex = edgeIdx > 0 ? + world->edges[edgeIdx].vertex0 : + world->edges[-edgeIdx].vertex1; + + vertex_t* vertex = &world->vertices[vertIndex]; + Vec3 vec = vertex->toVec(); + + float x = tangent.dotProduct(vec); + float y = bitangent.dotProduct(vec); + bounds.includePoint(Vec3(x, y, 0)); + } + + Vec3 extents = bounds.max - bounds.min; + return extents.x * extents.y; +} + int process_faces(const world_t* world) { // Write some data to a file @@ -241,9 +277,8 @@ int process_faces(const world_t* world) outFace.side = face->side; outFace.firstFaceVertex = (unsigned short)outFaceVertices.size(); - Vec3 vertexSum; - // Traverse the list of face edges to collect all of the face's vertices + Vec3 vertexSum; BoundBox bounds; for (int edgeListIdx = 0; edgeListIdx < face->ledge_num; ++edgeListIdx) { @@ -283,7 +318,9 @@ int process_faces(const world_t* world) // export_lightmap(world, face, bounds, faceIdx); outFace.numFaceVertices = (unsigned short)(outFaceVertices.size() - outFace.firstFaceVertex); - outFace.centerPoint = convertPoint(vertexSum / outFace.numFaceVertices); + outFace.centerPoint = convertWorldPosition(vertexSum / outFace.numFaceVertices); + float area = computeFaceArea(world, face); + outFace.centerPoint.pad = (short)(sqrt(area)); outFaces.push_back(outFace); } @@ -363,6 +400,8 @@ int process_faces(const world_t* world) outLeaf.firstLeafFace = leaf->lface_id; outLeaf.numLeafFaces = leaf->lface_num; + //outLeaf.center = convertWorldPosition(leaf->bound.getCenter()); + outLeaves.push_back(outLeaf); } diff --git a/ps1bsp.h b/ps1bsp.h index 29325f4..6ab705e 100644 --- a/ps1bsp.h +++ b/ps1bsp.h @@ -105,7 +105,8 @@ typedef struct int type; int vislist; - // TODO: add bounding box for frustum culing + // TODO: add bounding box for frustum culling (or do we? could save half the number of bounds checks if we only check nodes) + //SVECTOR center; u_short firstLeafFace; u_short numLeafFaces;