From c58528499dcd54cee7fb4dde80406cf7adf59529 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Tue, 26 Apr 2016 00:29:50 -0600 Subject: [PATCH] light: when interpolating a normal that lies outside of a face, recursively look it up on adjacent faces --- include/light/light.h | 6 +++++ light/light.cc | 58 ++++++++++++++++++++++++++++++++++++++++--- light/ltface.c | 18 ++++++++++++-- 3 files changed, 76 insertions(+), 6 deletions(-) diff --git a/include/light/light.h b/include/light/light.h index b7a39ad5..8d427eb2 100644 --- a/include/light/light.h +++ b/include/light/light.h @@ -222,6 +222,9 @@ void MakeTnodes(const bsp2_t *bsp); /* access the final phong-shaded vertex normal */ const vec_t *GetSurfaceVertexNormal(const bsp2_t *bsp, const bsp2_dface_t *f, const int v); + +const bsp2_dface_t * +Face_EdgeIndexSmoothed(const bsp2_t *bsp, const bsp2_dface_t *f, const int edgeindex); extern float scaledist; extern float rangescale; @@ -300,6 +303,9 @@ Face_TextureName(const bsp2_t *bsp, const bsp2_dface_t *face); void Face_MakeInwardFacingEdgePlanes(const bsp2_t *bsp, const bsp2_dface_t *face, plane_t *out); +plane_t Face_Plane(const bsp2_t *bsp, const bsp2_dface_t *f); +void Face_Normal(const bsp2_t *bsp, const bsp2_dface_t *f, vec3_t norm); + /* vis testing */ const bsp2_dleaf_t *Light_PointInLeaf( const bsp2_t *bsp, const vec3_t point ); int Light_PointContents( const bsp2_t *bsp, const vec3_t point ); diff --git a/light/light.cc b/light/light.cc index b77836ea..181d420d 100644 --- a/light/light.cc +++ b/light/light.cc @@ -350,7 +350,8 @@ public: std::map> vertex_normals; std::set interior_verts; - +map> smoothFaces; +map> vertsToFaces; /* given a triangle, just adds the contribution from the triangle to the given vertexes normals, based upon angles at the verts. * v1, v2, v3 are global vertex indices */ @@ -381,7 +382,7 @@ static int GetSurfaceVertex(const bsp2_t *bsp, const bsp2_dface_t *f, int v) return bsp->dedges[edge].v[0]; } -static void +void Face_Normal(const bsp2_t *bsp, const bsp2_dface_t *f, vec3_t norm) { if (f->side) @@ -411,12 +412,63 @@ FacesOnSamePlane(const std::vector &faces) return true; } +static void +Vertex_GetPos(const bsp2_t *bsp, int num, vec3_t out) +{ + assert(num >= 0 && num < bsp->numvertexes); + const dvertex_t *v = &bsp->dvertexes[num]; + + for (int i=0; i<3; i++) + out[i] = v->point[i]; +} + +plane_t +Face_Plane(const bsp2_t *bsp, const bsp2_dface_t *f) +{ + const int vertnum = GetSurfaceVertex(bsp, f, 0); + vec3_t vertpos; + Vertex_GetPos(bsp, vertnum, vertpos); + + plane_t res; + Face_Normal(bsp, f, res.normal); + res.dist = DotProduct(vertpos, res.normal); + return res; +} + +const bsp2_dface_t * +Face_EdgeIndexSmoothed(const bsp2_t *bsp, const bsp2_dface_t *f, const int edgeindex) +{ + if (smoothFaces.find(f) == smoothFaces.end()) { + return nullptr; + } + + int v0 = GetSurfaceVertex(bsp, f, edgeindex); + int v1 = GetSurfaceVertex(bsp, f, (edgeindex + 1) % f->numedges); + + const auto &v0_faces = vertsToFaces.at(v0); + const auto &v1_faces = vertsToFaces.at(v1); + + // find a face f2 that has both verts v0 and v1 + for (auto f2 : v0_faces) { + if (f2 == f) + continue; + if (find(v1_faces.begin(), v1_faces.end(), f2) != v1_faces.end()) { + const auto &f_smoothfaces = smoothFaces.at(f); + bool smoothed = (f_smoothfaces.find(f2) != f_smoothfaces.end()); + return smoothed ? f2 : nullptr; + } + } + return nullptr; +} + static void CalcualateVertexNormals(const bsp2_t *bsp) { // clear in case we are run twice vertex_normals.clear(); interior_verts.clear(); + smoothFaces.clear(); + vertsToFaces.clear(); // read _phong and _phong_angle from entities for compatiblity with other qbsp's, at the expense of no // support on func_detail/func_group @@ -436,7 +488,6 @@ CalcualateVertexNormals(const bsp2_t *bsp) } // build "vert index -> faces" map - std::map> vertsToFaces; for (int i = 0; i < bsp->numfaces; i++) { const bsp2_dface_t *f = &bsp->dfaces[i]; for (int j = 0; j < f->numedges; j++) { @@ -455,7 +506,6 @@ CalcualateVertexNormals(const bsp2_t *bsp) printf("CalcualateVertexNormals: %d interior verts\n", (int)interior_verts.size()); // build the "face -> faces to smooth with" map - std::map> smoothFaces; for (int i = 0; i < bsp->numfaces; i++) { bsp2_dface_t *f = &bsp->dfaces[i]; diff --git a/light/ltface.c b/light/ltface.c index e9c9f445..68d2e10e 100644 --- a/light/ltface.c +++ b/light/ltface.c @@ -19,6 +19,7 @@ #include #include +#include /* ======================================================================== */ @@ -460,8 +461,10 @@ FractionOfLine(const vec3_t v, const vec3_t w, const vec3_t p) { return t; } -static void CalcPointNormal(const bsp2_t *bsp, const bsp2_dface_t *face, plane_t surfplane, vec_t *norm, const vec_t *point) +static void CalcPointNormal(const bsp2_t *bsp, const bsp2_dface_t *face, vec_t *norm, const vec_t *point, int inside) { + plane_t surfplane = Face_Plane(bsp, face); + // project `point` onto the surface plane (it's hovering 1 unit above) vec3_t pointOnPlane; { @@ -507,6 +510,17 @@ static void CalcPointNormal(const bsp2_t *bsp, const bsp2_dface_t *face, plane_t if (dist < ON_EPSILON) { // behind this plane + const bsp2_dface_t *smoothed = Face_EdgeIndexSmoothed(bsp, face, i); + if (smoothed) { + if (inside < 3) { + free(edgeplanes); + + // call recursively to look up normal in the adjacent face + CalcPointNormal(bsp, smoothed, norm, point, inside + 1); + return; + } + } + v1 = GetSurfaceVertexPoint(bsp, face, i); v2 = GetSurfaceVertexPoint(bsp, face, (i+1)%face->numedges); @@ -620,7 +634,7 @@ CalcPoints(const modelinfo_t *modelinfo, const vec3_t offset, lightsurf_t *surf, if (surf->curved) { - CalcPointNormal(bsp, face, surf->plane, norm, point); + CalcPointNormal(bsp, face, norm, point, 0); } else {