|
|
@ -325,139 +325,9 @@ SurfaceList group_surfaces(const world_t* world, const VertexFaces& vertexFaces) |
|
|
return surfaces; |
|
|
return surfaces; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// To sample lightmap at any arbitrary world position:
|
|
|
|
|
|
// - Find the surface that the face belongs to
|
|
|
|
|
|
// - Select all faces from the surface where the position lies in its plane and is inside polygon boundaries
|
|
|
|
|
|
// - Sample those faces at the specified position (sample_lightmap) and average
|
|
|
|
|
|
std::vector<const face_t*> find_facesWithPoint(const world_t* world, const face_t* refFace, const SurfaceList& surfaces, Vec3 point) |
|
|
|
|
|
{ |
|
|
|
|
|
std::vector<const face_t*> faces; |
|
|
|
|
|
|
|
|
|
|
|
// Find the surface that the face belongs to
|
|
|
|
|
|
for (auto surfIter = surfaces.begin(); surfIter != surfaces.end(); ++surfIter) |
|
|
|
|
|
{ |
|
|
|
|
|
if (surfIter->faces.find(refFace) == surfIter->faces.end()) |
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
// Select all faces from the surface where the point lies in its plane and is inside polygon boundaries
|
|
|
|
|
|
for (auto faceIter = surfIter->faces.begin(); faceIter != surfIter->faces.end(); ++faceIter) |
|
|
|
|
|
{ |
|
|
|
|
|
const face_t* face = *faceIter; |
|
|
|
|
|
const plane_t* plane = &world->planes[face->plane_id]; |
|
|
|
|
|
|
|
|
|
|
|
// Check if the point lies on the face's plane
|
|
|
|
|
|
float pointPlaneDist = (point.x * plane->normal.x + point.y * plane->normal.y + point.z * plane->normal.z) - plane->dist; |
|
|
|
|
|
if (fabs(pointPlaneDist) > FLT_EPSILON) |
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
// Simple case first: check if this point lies on one of the face's edges
|
|
|
|
|
|
bool onEdge = false; |
|
|
|
|
|
for (int edgeListIdx = 0; edgeListIdx < face->ledge_num; ++edgeListIdx) |
|
|
|
|
|
{ |
|
|
|
|
|
int edgeIdx = world->edgeList[face->ledge_id + edgeListIdx]; |
|
|
|
|
|
const edge_t* edge = &world->edges[abs(edgeIdx)]; |
|
|
|
|
|
|
|
|
|
|
|
Vec3 vert0 = world->vertices[edge->vertex0].toVec(); |
|
|
|
|
|
Vec3 vert1 = world->vertices[edge->vertex1].toVec(); |
|
|
|
|
|
|
|
|
|
|
|
Vec3 dir0 = vert1 - vert0; |
|
|
|
|
|
Vec3 dir1 = point - vert0; |
|
|
|
|
|
float mag0 = dir0.magnitude(); |
|
|
|
|
|
float mag1 = dir1.magnitude(); |
|
|
|
|
|
|
|
|
|
|
|
if (mag1 / mag0 <= 1.0f + FLT_EPSILON && dir0.dotProduct(dir1) >= (mag0 - FLT_EPSILON) * (mag1 - FLT_EPSILON)) |
|
|
|
|
|
onEdge = true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (onEdge) |
|
|
|
|
|
faces.push_back(face); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return faces; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
unsigned char compute_faceVertex_light3(const world_t* world, const face_t* refFace, const SurfaceList& surfaces, const FaceBounds& faceBounds, Vec3 point) |
|
|
|
|
|
{ |
|
|
|
|
|
auto faces = find_facesWithPoint(world, refFace, surfaces, point); |
|
|
|
|
|
if (faces.empty()) |
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
|
|
unsigned int light = 0; |
|
|
|
|
|
for (auto faceIter = faces.begin(); faceIter != faces.end(); ++faceIter) |
|
|
|
|
|
{ |
|
|
|
|
|
const face_t* face = *faceIter; |
|
|
|
|
|
light += sample_lightmap(world, face, faceBounds.find(face)->second, point) + (0xFF - face->baselight); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return (unsigned char)(light / faces.size()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Find the list of all faces that contain the given point, i.e. the point lies on the face's plane and is contained within its polygon bounds
|
|
|
|
|
|
std::vector<const face_t*> world_facesWithPoint(const world_t* world, Vec3 point) |
|
|
|
|
|
{ |
|
|
|
|
|
std::vector<const face_t*> faces; |
|
|
|
|
|
for (int faceIdx = 0; faceIdx < world->numFaces; ++faceIdx) |
|
|
|
|
|
{ |
|
|
|
|
|
const face_t* face = &world->faces[faceIdx]; |
|
|
|
|
|
const plane_t* plane = &world->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)
|
|
|
|
|
|
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) |
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
// Check if the point is contained within the face's polygon
|
|
|
|
|
|
double angleSum = 0; |
|
|
|
|
|
for (int edgeListIdx = 0; edgeListIdx < face->ledge_num; ++edgeListIdx) |
|
|
|
|
|
{ |
|
|
|
|
|
int edgeIdx = world->edgeList[face->ledge_id + edgeListIdx]; |
|
|
|
|
|
|
|
|
|
|
|
Vec3 v0, v1; |
|
|
|
|
|
if (edgeIdx > 0) |
|
|
|
|
|
{ |
|
|
|
|
|
const edge_t* edge = &world->edges[edgeIdx]; |
|
|
|
|
|
v0 = world->vertices[edge->vertex0].toVec(); |
|
|
|
|
|
v1 = world->vertices[edge->vertex1].toVec(); |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
const edge_t* edge = &world->edges[-edgeIdx]; |
|
|
|
|
|
v0 = world->vertices[edge->vertex1].toVec(); |
|
|
|
|
|
v1 = world->vertices[edge->vertex0].toVec(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Vec3 p0 = v0 - point; |
|
|
|
|
|
Vec3 p1 = v1 - point; |
|
|
|
|
|
double m0 = p0.magnitude(); |
|
|
|
|
|
double m1 = p1.magnitude(); |
|
|
|
|
|
|
|
|
|
|
|
if ((m0 * m1) <= 0.0001) |
|
|
|
|
|
{ |
|
|
|
|
|
faces.push_back(face); |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
double dot = p0.dotProduct(p1) / (m0 * m1); |
|
|
|
|
|
angleSum += acos(dot); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (fabs(2 * M_PI - angleSum) <= 0.0001) |
|
|
|
|
|
faces.push_back(face); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return faces; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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) |
|
|
{ |
|
|
{ |
|
|
auto faces = world_facesWithPoint(world, point); |
|
|
|
|
|
|
|
|
auto faces = world->facesWithPoint(point); |
|
|
if (faces.empty()) |
|
|
if (faces.empty()) |
|
|
return 0; |
|
|
return 0; |
|
|
|
|
|
|
|
|
|