Browse Source

Implemented a more accurate face area computation, allowing for more precise tessellation LOD selection.

Also started putting face-related functions into a separate source file.
master
Nico de Poel 3 years ago
parent
commit
c111a2090c
  1. 2
      PS1BSP.vcxproj
  2. 6
      PS1BSP.vcxproj.filters
  3. 54
      face.cpp
  4. 3
      face.h
  5. 34
      main.cpp

2
PS1BSP.vcxproj

@ -142,6 +142,7 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="face.cpp" />
<ClCompile Include="gpc.cpp" /> <ClCompile Include="gpc.cpp" />
<ClCompile Include="lighting.cpp" /> <ClCompile Include="lighting.cpp" />
<ClCompile Include="main.cpp" /> <ClCompile Include="main.cpp" />
@ -152,6 +153,7 @@
<ItemGroup> <ItemGroup>
<ClInclude Include="bsp.h" /> <ClInclude Include="bsp.h" />
<ClInclude Include="common.h" /> <ClInclude Include="common.h" />
<ClInclude Include="face.h" />
<ClInclude Include="gpc.h" /> <ClInclude Include="gpc.h" />
<ClInclude Include="lighting.h" /> <ClInclude Include="lighting.h" />
<ClInclude Include="matrix.h" /> <ClInclude Include="matrix.h" />

6
PS1BSP.vcxproj.filters

@ -36,6 +36,9 @@
<ClCompile Include="tesselate.cpp"> <ClCompile Include="tesselate.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="face.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="bsp.h"> <ClInclude Include="bsp.h">
@ -86,6 +89,9 @@
<ClInclude Include="matrix.h"> <ClInclude Include="matrix.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="face.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CopyFileToFolders Include="palette.lmp"> <CopyFileToFolders Include="palette.lmp">

54
face.cpp

@ -0,0 +1,54 @@
#include "common.h"
#include "bsp.h"
#include "face.h"
// Heron's formula, yoinked from: https://www.cuemath.com/measurement/area-of-triangle/
static double face_triangleArea(Vec3 v0, Vec3 v1, Vec3 v2)
{
double a = (v1 - v0).magnitude();
double b = (v2 - v0).magnitude();
double c = (v0 - v2).magnitude();
double s = (a + b + c) * 0.5;
double areaSqr = s * (s - a) * (s - b) * (s - c);
if (areaSqr < FLT_EPSILON) // Collapsed triangles can happen, prevent NaN in that situation
return 0.0;
return sqrt(areaSqr);
}
double face_computeArea(const world_t* world, const face_t* face)
{
int i0, i1, i2;
// Get the first edge so we can build a triangle fan
int edgeIdx = world->edgeList[face->ledge_id];
if (edgeIdx > 0)
{
i0 = world->edges[edgeIdx].vertex0;
i1 = world->edges[edgeIdx].vertex1;
}
else
{
i0 = world->edges[-edgeIdx].vertex1;
i1 = world->edges[-edgeIdx].vertex0;
}
// Triangulate the face, compute the area of each triangle and add them all together
double totalArea = 0.0;
for (int edgeListIdx = 1; edgeListIdx < face->ledge_num - 1; ++edgeListIdx)
{
int edgeIdx = world->edgeList[face->ledge_id + edgeListIdx];
i2 = edgeIdx > 0 ? world->edges[edgeIdx].vertex0 : world->edges[-edgeIdx].vertex1;
Vec3 v0 = world->vertices[i0].toVec();
Vec3 v1 = world->vertices[i1].toVec();
Vec3 v2 = world->vertices[i2].toVec();
totalArea += face_triangleArea(v0, v1, v2);
i1 = i2;
}
return totalArea;
}

3
face.h

@ -0,0 +1,3 @@
#pragma once
double face_computeArea(const world_t* world, const face_t* face);

34
main.cpp

@ -4,6 +4,7 @@
#include "ps1bsp.h" #include "ps1bsp.h"
#include "lighting.h" #include "lighting.h"
#include "texture.h" #include "texture.h"
#include "face.h"
#include "tesselate.h" #include "tesselate.h"
static char path[_MAX_PATH]; static char path[_MAX_PATH];
@ -43,35 +44,6 @@ size_t writeAtlasData(const char* timPath, ps1bsp_dentry_t& dentry, FILE* f)
return written; return written;
} }
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
Vec3 tangent, bitangent;
plane->getTangents(tangent, bitangent);
// Project all face vertices onto the face's plane
BoundBox bounds;
for (int edgeListIdx = 0; edgeListIdx < face->ledge_num; ++edgeListIdx)
{
int edgeIdx = world->edgeList[face->ledge_id + edgeListIdx];
int vertIndex = edgeIdx > 0 ?
world->edges[edgeIdx].vertex0 :
world->edges[-edgeIdx].vertex1;
const vertex_t* vertex = &world->vertices[vertIndex];
Vec3 vec = vertex->toVec();
double x = tangent.dotProduct(vec);
double y = bitangent.dotProduct(vec);
bounds.includePoint(Vec3(x, y, 0.0));
}
Vec3 extents = bounds.max - bounds.min;
return extents.x * extents.y;
}
typedef std::unordered_map<const face_t*, std::vector<Tesselator::Polygon>> FacePolygons; typedef std::unordered_map<const face_t*, std::vector<Tesselator::Polygon>> FacePolygons;
int process_faces(const world_t* world, const TextureList& textures) int process_faces(const world_t* world, const TextureList& textures)
@ -156,7 +128,7 @@ int process_faces(const world_t* world, const TextureList& textures)
outFace.numFaceVertices = (unsigned char)(outFaceVertices.size() - outFace.firstFaceVertex); outFace.numFaceVertices = (unsigned char)(outFaceVertices.size() - outFace.firstFaceVertex);
outFace.center = (vertexSum / face->ledge_num).convertWorldPosition(); outFace.center = (vertexSum / face->ledge_num).convertWorldPosition();
float area = computeFaceArea(world, face);
double area = face_computeArea(world, face);
outFace.center.pad = (short)(area / 100); outFace.center.pad = (short)(area / 100);
outFaces.push_back(outFace); outFaces.push_back(outFace);
} }
@ -290,6 +262,8 @@ int process_faces(const world_t* world, const TextureList& textures)
outFace->numPolygons = (unsigned char)(outPolygons.size() - outFace->firstPolygon); outFace->numPolygons = (unsigned char)(outPolygons.size() - outFace->firstPolygon);
outFace->center.pad = (short)sqrt((double)outFace->center.pad * 100 / outFace->numPolygons); outFace->center.pad = (short)sqrt((double)outFace->center.pad * 100 / outFace->numPolygons);
if (outFace->center.pad <= 0)
outFace->center.pad = 1; // Prevent division by zero in the LOD calculation
} }
printf("Converting data...\n"); printf("Converting data...\n");

Loading…
Cancel
Save