qbsp: add "-midsplitsurffraction n" option as an alt. to -maxnodesize

switch to midsplit if the node contains more than this fraction of the
model's total surfaces. Try 0.15 to 0.5. Works better than
maxNodeSize for maps with a 3D skybox (e.g. +-128K unit maps)
This commit is contained in:
Eric Wasylishen 2019-02-11 00:52:38 -07:00
parent a940e506ff
commit ad65449cef
3 changed files with 43 additions and 6 deletions

View File

@ -358,6 +358,13 @@ public:
int dxSubdivide;
int dxLeakDist;
int maxNodeSize;
/**
* if 0 (default), use maxNodeSize for deciding when to switch to midsplit bsp heuristic.
*
* if 0 < midsplitSurfFraction <=1, switch to midsplit if the node contains more than this fraction of the model's
* total surfaces. Try 0.15 to 0.5. Works better than maxNodeSize for maps with a 3D skybox (e.g. +-128K unit maps)
*/
float midsplitSurfFraction;
char szMapName[512];
char szBSPName[512];
char wadPath[512];
@ -390,6 +397,7 @@ public:
this->fixRotateObjTexture = true;
this->fOldaxis = true;
this->maxNodeSize = 1024;
this->midsplitSurfFraction = 0;
this->on_epsilon = 0.0001;
this->worldExtent = 65536;
}

View File

@ -854,6 +854,14 @@ ParseOptions(char *szOptions)
if (!szTok2)
Error("Invalid argument to option %s", szTok);
options.maxNodeSize= atoi(szTok2);
szTok = szTok2;
} else if (!Q_strcasecmp(szTok, "midsplitsurffraction")) {
szTok2 = GetTok(szTok + strlen(szTok) + 1, szEnd);
if (!szTok2)
Error("Invalid argument to option %s", szTok);
options.midsplitSurfFraction = qclamp(atof(szTok2), 0.0f, 1.0f);
logprint("Switching to midsplit when node contains more than fraction %f of model's surfaces\n", options.midsplitSurfFraction);
szTok = szTok2;
} else if (!Q_strcasecmp(szTok, "epsilon")) {
szTok2 = GetTok(szTok + strlen(szTok) + 1, szEnd);

View File

@ -31,6 +31,11 @@ static int c_solid, c_empty, c_water, c_detail, c_detail_illusionary, c_detail_f
static int c_illusionary_visblocker;
static bool usemidsplit;
/**
* Total number of surfaces in the map
*/
static int mapsurfaces;
//============================================================================
void
@ -508,13 +513,24 @@ SelectPartition(surface_t *surfaces)
maxs[i] = surf->maxs[i];
}
bool largenode = false;
if (options.maxNodeSize >= 64) {
const vec_t maxnodesize = options.maxNodeSize - ON_EPSILON;
// how much of the map are we partitioning?
double fractionOfMap = surfcount / (double)mapsurfaces;
largenode = (maxs[0] - mins[0]) > maxnodesize
|| (maxs[1] - mins[1]) > maxnodesize
|| (maxs[2] - mins[2]) > maxnodesize;
bool largenode = false;
// decide if we should switch to the midsplit method
if (options.midsplitSurfFraction != 0.0) {
// new way (opt-in)
largenode = (fractionOfMap > options.midsplitSurfFraction);
} else {
// old way (ericw-tools 0.15.2+)
if (options.maxNodeSize >= 64) {
const vec_t maxnodesize = options.maxNodeSize - ON_EPSILON;
largenode = (maxs[0] - mins[0]) > maxnodesize
|| (maxs[1] - mins[1]) > maxnodesize
|| (maxs[2] - mins[2]) > maxnodesize;
}
}
if (usemidsplit || largenode) // do fast way for clipping hull
@ -1044,6 +1060,11 @@ SolidBSP(const mapentity_t *entity, surface_t *surfhead, bool midsplit)
c_detail_illusionary = 0;
c_detail_fence = 0;
c_illusionary_visblocker = 0;
// count map surfaces; this is used when deciding to switch between midsplit and the expensive partitioning
mapsurfaces = 0;
for (surface_t *surf = surfhead; surf; surf = surf->next) {
mapsurfaces++;
}
PartitionSurfaces(surfhead, headnode);