Browse Source

Implemented backface culling per face, by adding plane and center point fields to the face struct and checking the plane's normal against the camera vector to the center point.

This eliminates the need for per-polygon normal clipping and reduces the amount of redundant vertex copying, for a measurable speed boost.
tess_experiment
Nico de Poel 3 years ago
parent
commit
bbf87bbf58
  1. 5
      ps1bsp.h
  2. 4
      qmath.h
  3. BIN
      test.ps1bsp
  4. 55
      world.c

5
ps1bsp.h

@ -71,9 +71,14 @@ typedef struct
typedef struct typedef struct
{ {
unsigned short planeId;
unsigned short side;
unsigned short firstFaceVertex; unsigned short firstFaceVertex;
unsigned short numFaceVertices; unsigned short numFaceVertices;
SVECTOR centerPoint;
u_long drawFrame; // Which frame was this face last drawn on? Used to check if this face should be drawn. u_long drawFrame; // Which frame was this face last drawn on? Used to check if this face should be drawn.
} ps1bsp_face_t; } ps1bsp_face_t;

4
qmath.h

@ -3,9 +3,9 @@
MATRIX *RotMatrixQ(SVECTOR *r, MATRIX *m); MATRIX *RotMatrixQ(SVECTOR *r, MATRIX *m);
INLINE short m_dot12(const SVECTOR *a, const SVECTOR *b)
INLINE short m_dot12s(const SVECTOR a, const SVECTOR b)
{ {
return ((a->vx * b->vx) >> 12) + ((a->vy * b->vy) >> 12) + ((a->vz * b->vz) >> 12);
return (short)(((int)a.vx * b.vx) >> 12) + (((int)a.vy * b.vy) >> 12) + (((int)a.vz * b.vz) >> 12);
} }
// TODO: worth a benchmark: is it faster to copy these vectors and use them from the stack, or to do six pointer dereferences? // TODO: worth a benchmark: is it faster to copy these vectors and use them from the stack, or to do six pointer dereferences?

BIN
test.ps1bsp

55
world.c

@ -65,12 +65,6 @@ static INLINE void drawface_triangle_fan(const ps1bsp_face_t *face, SVECTOR *vec
gte_ldv3(v0, v1, v2); gte_ldv3(v0, v1, v2);
gte_rtpt(); // Rotation, translation, perspective projection gte_rtpt(); // Rotation, translation, perspective projection
// Normal clipping for backface culling
gte_nclip();
gte_stopz(&p);
if (p < 0)
continue;
// Average Z for depth sorting and culling // Average Z for depth sorting and culling
gte_avsz3(); gte_avsz3();
gte_stotz(&p); gte_stotz(&p);
@ -127,12 +121,6 @@ static INLINE void drawface_triangle_strip(const ps1bsp_face_t *face, SVECTOR *v
gte_ldv3(v0, v1, v2); gte_ldv3(v0, v1, v2);
gte_rtpt(); // Rotation, translation, perspective projection gte_rtpt(); // Rotation, translation, perspective projection
// Normal clipping for backface culling
gte_nclip();
gte_stopz(&p);
if (p < 0)
continue;
// Average Z for depth sorting and culling // Average Z for depth sorting and culling
gte_avsz3(); gte_avsz3();
gte_stotz(&p); gte_stotz(&p);
@ -183,12 +171,6 @@ static INLINE void drawface_quad_strip(const ps1bsp_face_t *face, SVECTOR *vecs)
gte_ldv3(v0, v1, v2); gte_ldv3(v0, v1, v2);
gte_rtpt(); // Rotation, translation, perspective projection gte_rtpt(); // Rotation, translation, perspective projection
// Normal clipping for backface culling (TODO: should be necessary only once per face, using plane normal & camera direction)
gte_nclip();
gte_stopz(&p);
if (p < 0)
continue;
// Average Z for depth sorting and culling // Average Z for depth sorting and culling
gte_avsz3(); gte_avsz3();
gte_stotz(&p); gte_stotz(&p);
@ -221,9 +203,25 @@ static INLINE void drawface_quad_strip(const ps1bsp_face_t *face, SVECTOR *vecs)
} }
} }
static INLINE short world_pointPlaneDist(const VECTOR *point, const ps1bsp_plane_t *plane)
{
// TODO: can be optimized for axis-aligned planes, no need for a dot product there
return m_pointPlaneDist2(*point, plane->normal, plane->dist);
}
static void world_drawface(const world_t *world, const ps1bsp_face_t *face) static void world_drawface(const world_t *world, const ps1bsp_face_t *face)
{ {
const CVECTOR *col = &colors[(u_long)face % numColors];
// Backface culling using the face's plane and center point
// This eliminates the need for normal clipping per polygon
SVECTOR cam_vec, center = face->centerPoint;
cam_vec.vx = center.vx - cam_pos.vx;
cam_vec.vy = center.vy - cam_pos.vy;
cam_vec.vz = center.vz - cam_pos.vz;
const ps1bsp_plane_t *plane = &world->planes[face->planeId];
short dot = m_dot12s(cam_vec, plane->normal);
if ((dot >= 0) ^ face->side)
return;
SVECTOR *vecs = (SVECTOR*)(scratchpad + 256); SVECTOR *vecs = (SVECTOR*)(scratchpad + 256);
@ -273,21 +271,8 @@ static void world_drawnode(const world_t *world, short nodeIdx, u_char *pvs)
} }
const ps1bsp_node_t *node = &world->nodes[nodeIdx]; const ps1bsp_node_t *node = &world->nodes[nodeIdx];
// Still not sure why we have faces attached to nodes... Try to remove this and see what happens
// ps1bsp_face_t *face = &world->faces[node->firstFace];
// for (u_short faceIdx = 0; faceIdx < node->numFaces; ++faceIdx, ++face)
// {
// // Check if we've already drawn this face on the current frame
// if (face->drawFrame == frameNum)
// continue;
// world_drawface(world, face);
// face->drawFrame = frameNum;
// }
const ps1bsp_plane_t *plane = &world->planes[node->planeId]; const ps1bsp_plane_t *plane = &world->planes[node->planeId];
short dist = m_pointPlaneDist2(cam_pos, plane->normal, plane->dist);
short dist = world_pointPlaneDist(&cam_pos, plane);
// Draw child nodes in front-to-back order; adding faces to the OT will reverse the drawing order // Draw child nodes in front-to-back order; adding faces to the OT will reverse the drawing order
if (dist > 0) if (dist > 0)
@ -356,9 +341,7 @@ static u_short world_leafAtPoint(const world_t *world, const VECTOR *point)
const ps1bsp_node_t *node = &world->nodes[nodeIdx]; const ps1bsp_node_t *node = &world->nodes[nodeIdx];
const ps1bsp_plane_t *plane = &world->planes[node->planeId]; const ps1bsp_plane_t *plane = &world->planes[node->planeId];
// TODO: can be optimized for axis-aligned planes, no need for a dot product there
short dist = m_pointPlaneDist2(*point, plane->normal, plane->dist);
short dist = world_pointPlaneDist(point, plane);
nodeIdx = dist > 0 ? node->front : node->back; // TODO: this can be done branchless with (dist < 0)^1 nodeIdx = dist > 0 ? node->front : node->back; // TODO: this can be done branchless with (dist < 0)^1
} }

Loading…
Cancel
Save