/**
|
* DOC_TBA
|
*
|
* @name czm_rayEllipsoidIntersectionInterval
|
* @glslFunction
|
*/
|
czm_raySegment czm_rayEllipsoidIntersectionInterval(czm_ray ray, vec3 ellipsoid_center, vec3 ellipsoid_inverseRadii)
|
{
|
// ray and ellipsoid center in eye coordinates. radii in model coordinates.
|
vec3 q = ellipsoid_inverseRadii * (czm_inverseModelView * vec4(ray.origin, 1.0)).xyz;
|
vec3 w = ellipsoid_inverseRadii * (czm_inverseModelView * vec4(ray.direction, 0.0)).xyz;
|
|
q = q - ellipsoid_inverseRadii * (czm_inverseModelView * vec4(ellipsoid_center, 1.0)).xyz;
|
|
float q2 = dot(q, q);
|
float qw = dot(q, w);
|
|
if (q2 > 1.0) // Outside ellipsoid.
|
{
|
if (qw >= 0.0) // Looking outward or tangent (0 intersections).
|
{
|
return czm_emptyRaySegment;
|
}
|
else // qw < 0.0.
|
{
|
float qw2 = qw * qw;
|
float difference = q2 - 1.0; // Positively valued.
|
float w2 = dot(w, w);
|
float product = w2 * difference;
|
|
if (qw2 < product) // Imaginary roots (0 intersections).
|
{
|
return czm_emptyRaySegment;
|
}
|
else if (qw2 > product) // Distinct roots (2 intersections).
|
{
|
float discriminant = qw * qw - product;
|
float temp = -qw + sqrt(discriminant); // Avoid cancellation.
|
float root0 = temp / w2;
|
float root1 = difference / temp;
|
if (root0 < root1)
|
{
|
czm_raySegment i = czm_raySegment(root0, root1);
|
return i;
|
}
|
else
|
{
|
czm_raySegment i = czm_raySegment(root1, root0);
|
return i;
|
}
|
}
|
else // qw2 == product. Repeated roots (2 intersections).
|
{
|
float root = sqrt(difference / w2);
|
czm_raySegment i = czm_raySegment(root, root);
|
return i;
|
}
|
}
|
}
|
else if (q2 < 1.0) // Inside ellipsoid (2 intersections).
|
{
|
float difference = q2 - 1.0; // Negatively valued.
|
float w2 = dot(w, w);
|
float product = w2 * difference; // Negatively valued.
|
float discriminant = qw * qw - product;
|
float temp = -qw + sqrt(discriminant); // Positively valued.
|
czm_raySegment i = czm_raySegment(0.0, temp / w2);
|
return i;
|
}
|
else // q2 == 1.0. On ellipsoid.
|
{
|
if (qw < 0.0) // Looking inward.
|
{
|
float w2 = dot(w, w);
|
czm_raySegment i = czm_raySegment(0.0, -qw / w2);
|
return i;
|
}
|
else // qw >= 0.0. Looking outward or tangent.
|
{
|
return czm_emptyRaySegment;
|
}
|
}
|
}
|