Draw Manager: Simplify the algorithm that extract the BoundingSphere of a Frustum

The idea is to separate the most common case from symmetrical frustum. And to make a simple but efficient calculation.

The new radius is usually 98% the size of the radius size of the asymmetric solution.

Thanks to @fclem for reviewing the patch on IRC
This commit is contained in:
Germano Cavalcante 2018-03-06 19:27:43 -03:00
parent faf70e1e64
commit 267e816b9a
Notes: blender-bot 2023-02-14 09:29:42 +01:00
Referenced by issue #54491, Default cube disappear in Front or Side view
1 changed files with 54 additions and 26 deletions

View File

@ -420,15 +420,57 @@ static void draw_clipping_setup_from_view(void)
}
/* Extract Bounding Sphere */
/**
* Compute bounding sphere for the general case and not only symmetric frustum:
* We put the sphere center on the line that goes from origin to the center of the far clipping plane.
* This is the optimal position if the frustum is symmetric or very asymmetric and probably close
* to optimal for the general case. The sphere center position is computed so that the distance to
* the near and far extreme frustum points are equal.
**/
if (projmat[3][3] == 0.0f) {
/* Perspective */
if (projmat[3][3] != 0.0f) {
/* Orthographic */
/* The most extreme points on the near and far plane. (normalized device coords). */
float *nearpoint = bbox.vec[0];
float *farpoint = bbox.vec[6];
mul_project_m4_v3(projinv, nearpoint);
mul_project_m4_v3(projinv, farpoint);
/* just use median point */
mid_v3_v3v3(bsphere->center, farpoint, nearpoint);
bsphere->radius = len_v3v3(bsphere->center, farpoint);
}
else if (projmat[2][0] == 0.0f && projmat[2][1] == 0.0f) {
/* Perspective with symmetrical frustum. */
/* We obtain the center and radius of the circumscribed circle of the
* isosceles trapezoid composed by the diagonals of the near and far clipping plane */
/* center of each clipping plane */
float mid_min[3], mid_max[3];
mid_v3_v3v3(mid_min, bbox.vec[3], bbox.vec[4]);
mid_v3_v3v3(mid_max, bbox.vec[2], bbox.vec[5]);
/* square length of the diagonals of each clipping plane */
float a_sq = len_squared_v3v3(bbox.vec[3], bbox.vec[4]);
float b_sq = len_squared_v3v3(bbox.vec[2], bbox.vec[5]);
/* distance squared between clipping planes */
float h_sq = len_squared_v3v3(mid_min, mid_max);
float fac = (4 * h_sq + b_sq - a_sq) / (8 * h_sq);
BLI_assert(fac >= 0.0f);
/* The goal is to get the smallest sphere,
* not the sphere that passes through each corner */
if (fac > 1.0f) {
fac = 1.0f;
}
interp_v3_v3v3(bsphere->center, mid_min, mid_max, fac);
/* distance from the center to one of the points of the far plane (1, 2, 5, 6) */
bsphere->radius = len_v3v3(bsphere->center, bbox.vec[1]);
}
else {
/* Perspective with asymmetrical frustum. */
/* We put the sphere center on the line that goes from origin
* to the center of the far clipping plane. */
/* Detect which of the corner of the far clipping plane is the farthest to the origin */
float nfar[4]; /* most extreme far point in NDC space */
float farxy[2]; /* farpoint projection onto the near plane */
@ -483,24 +525,10 @@ static void draw_clipping_setup_from_view(void)
bsphere->center[1] = farcenter[1] * z/e;
bsphere->center[2] = z;
bsphere->radius = len_v3v3(bsphere->center, farpoint);
/* Transform to world space. */
mul_m4_v3(viewinv, bsphere->center);
}
else {
/* Orthographic */
/* The most extreme points on the near and far plane. (normalized device coords) */
float nearpoint[3] = {-1.0f, -1.0f, -1.0f};
float farpoint[3] = { 1.0f, 1.0f, 1.0f};
mul_project_m4_v3(projinv, nearpoint);
mul_project_m4_v3(projinv, farpoint);
/* just use median point */
mid_v3_v3v3(bsphere->center, farpoint, nearpoint);
bsphere->radius = len_v3v3(bsphere->center, farpoint);
}
/* Transform to world space. */
mul_m4_v3(viewinv, bsphere->center);
}
/* Return True if the given BoundSphere intersect the current view frustum */