Search code examples
3dgeometryphysicsrenderer

How to describe an ellipse suitable for 3D (geometry, renderer, physics), in any language


I can think of two ways to create an Ellipse class.

In math, an ellipse is described by two focal points and the major or semi-major axis length.

A typical structure would be like this:

  • focus1: Vector3D
  • focus2: Vector3D
  • semiMajorAxis: double
  • planeNormal: Vector3D

However, I found it to be sub-optimal, because 99% of time, I don't really care about the focal points.

It looks harder to figure out how to intersect with lines/rays, or to perform projections.

Instead, I would represent an ellipse as a stretched circle along a vector.

The structure would be something like this:

  • center: Vector3D
  • radius: double
  • stretchVector: Vector3D (the axis along which the stretch is applied)
  • stretchRate: double
  • planeNormal: Vector3D

The idea is to perform all tests/traces/projections as if it was done against a mere circle, simply by scaling in and out values before sending them to my circle methods.

However I'm lacking experience in that domain, so I'm not sure which one is:

  • the easier to use
  • the faster to compute (it's 3D, so I need good perfs!)

EDIT: Actually I need ellipse as faces of volume (cylinder section, cone section) rather than movements. So my main use would be to raycast or to intersect it with lines, planes, circles, other ellipses, etc...


Solution

  • The shape of an ellipse is defined by the lengths of major axis a and minor axis b. Next it is probably a good idea to define the containing plane via center point C and the normal vector n_0 normalized to length one. The remaining information you need is the direction of the major axis. This could be specified by just an angle to a default line in the specified plane, but I do not know of a natural and efficient way to do this. So I would choose to specify the direction vector v_a of the major axis. This introduces some redundancy since n_0 . v_a = 0 must hold and additionally |v_a| = 1 or |v_a| = a (the first condition is more efficient for your needs). The direction vector v_b of the minor axis can be computed from the above information, but for efficiency one would probably prefer to have it precomputed.

    Alltogether one could represent an ellipse in 3D with the following data:

    • a, b: real values designating length of major and minor axis, resp.
    • C: 3D point, center of ellipse
    • n_0: 3D vector, normal vector of containing plane
    • v_a, v_b: 3D vectors designating direction of major and minor, resp.

    fulfilling the following conditions:

    • a >= b > 0
    • |n_0| = |v_a| = |v_b| = 1
    • n_0 = v_a x v_b
    • v_a . v_b = 0

    An efficient intersection test can now be done this way:

    1. Compute the intersection point P of e.g. a ray with the containing plane defined by C and n_0.
    2. Transform the intersection point P to the canonical ellipse position in 2D (center = (0,0), major axis parallel to the x-axis) by computing P* = M . (P-C) (see the definition of the 2x3 matrix M below).
    3. Transform the ellipse to a circle with radius b by computing P** = (b/a P*_x, P*_y)
    4. Now P is inside the original 3D-ellipse if and only if the following holds: P**_x^2 + P**_y^2 <= b^2.

    The transformation matrix M is simply

     / v_a_x v_b_x n_0_x \
     \ v_a_y v_b_y n_0_y /