diff --git a/n64start.ps1bsp b/n64start.ps1bsp index 63275cc..130f0da 100755 Binary files a/n64start.ps1bsp and b/n64start.ps1bsp differ diff --git a/world.c b/world.c index 86f506c..b3f5f83 100644 --- a/world.c +++ b/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; - // } + // Check if the face is behind the camera // 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;