Browse Source

Included face area value in tessellation LOD level calculation.

Could probably use some more finetuning in practice, but this is already pretty good.
master
Nico de Poel 3 years ago
parent
commit
090cde5f89
  1. BIN
      n64start.ps1bsp
  2. 59
      world.c

BIN
n64start.ps1bsp

59
world.c

@ -64,59 +64,38 @@ static INLINE short world_pointPlaneDist(const VECTOR *point, const ps1bsp_plane
return (short)m_pointPlaneDist2(point, &plane->normal, plane->dist);
}
static INLINE short world_planeDot(const SVECTOR *dir, const ps1bsp_plane_t *plane)
{
// Make use of axis-aligned planes to skip the need for a dot product
if (plane->type < 3)
return ((short*)dir)[plane->type];
return (short)m_dot12(dir, &plane->normal);
}
static INLINE short world_cull_backface(const world_t *world, const ps1bsp_face_t *face)
{
// Backface culling using the face's plane and center point
// This eliminates the need for normal clipping per polygon
SVECTOR cam_vec;
cam_vec.vx = face->center.vx - cam_pos.vx;
cam_vec.vy = face->center.vy - cam_pos.vy;
cam_vec.vz = face->center.vz - cam_pos.vz;
VECTOR cam_vec;
cam_vec.vx = (int)face->center.vx - cam_pos.vx;
cam_vec.vy = (int)face->center.vy - cam_pos.vy;
cam_vec.vz = (int)face->center.vz - cam_pos.vz;
// Check if the face's plane points towards the camera
const ps1bsp_plane_t *plane = &world->planes[face->planeId];
int planeDot = world_planeDot(&cam_vec, plane);
int planeDot = m_dot12(&cam_vec, &plane->normal);
if ((planeDot >= 0) ^ face->side)
return 0;
// Check if the face is behind the camera
// TODO: this may cull faces close to the camera, use VectorNormalS to normalize and check for angles < -60 degrees
// TODO: or, just check against all corners of the face...
// const ps1bsp_facevertex_t *faceVertices = &world->faceVertices[face->firstFaceVertex];
// for (int vertIdx = 0; vertIdx < face->numFaceVertices; ++vertIdx)
// {
// const ps1bsp_vertex_t *vert = &world->vertices[faceVertices[vertIdx].index];
// cam_vec.vx = vert->x - cam_pos.vx;
// cam_vec.vy = vert->y - cam_pos.vy;
// cam_vec.vz = vert->z - cam_pos.vz;
// if (m_dot12(cam_vec, cam_dir) >= 0)
// return 0;
// }
// NOTE: disabling the behind-the-camera check does *not* actually solve the problem of polygons disappearing when too close to the camera!
// This means that the GPU probably already clips polygons that stretch too far outside the drawing area. Tessellation should solve this.
int camDot = m_dot12(&cam_vec, &cam_dir);
if (camDot < 0)
return 0;
int vecLenSqr = m_dot12(&cam_vec, &cam_vec);
// Flip angle for faces that are on the opposite side of their plane
char flip = 2 * face->side - 1;
planeDot = planeDot * flip;
int foo = (planeDot * vecLenSqr) / (camDot + 1);
// TODO: include face area
return (short)foo;
// Calculate an LOD value for this face, based on camera position & direction, face normal & area and distance.
// This is used to determine how many tessellation subdivisions are necessary to prevent texture warping.
int vecLenSqr = m_dot12(&cam_vec, &cam_vec);
int lod = (planeDot * vecLenSqr) / (camDot + 1);
lod = (lod << 6) / (face->center.pad + 1);
return (short)lod;
}
static u_short world_leafAtPoint(const world_t *world, const VECTOR *point)
@ -235,19 +214,19 @@ static ps1bsp_face_t *world_sortFaces(const world_t *world, const ps1bsp_leaf_t
face->drawFrame = frameNum;
// NOTE: this value could be REALLY useful for determining the tessellation subdivisions. It has camera distance *and* angle in it.
// Just include the face size/area for an approximate screen size. Maybe also separate x/y/z for angle-dependent tessellation.
short dot = world_cull_backface(world, face);
if (!dot)
// Cull faces that are facing away from the camera
// This also returns an LOD value used to determine tessellation level
short lod = world_cull_backface(world, face);
if (!lod)
continue;
face->flags &= ~3;
if (dot < 64)
if (lod < 64)
face->flags |= 1;
else if (dot < 128)
else if (lod < 128)
face->flags |= 2;
else if (dot < 256)
face->flags |= 3;
// else if (lod < 256)
// face->flags |= 3;
// Sort the faces to draw in front-to-back order
face->nextFace = firstFace;

Loading…
Cancel
Save