Issues with Parallel Frustum Size Control in Animations

ALSO Consistency Between Parallel and Perspective Projection in Rhino Camera and

Hello everyone,

I am an architect and a frequent user of Rhino. Most of the time, I prefer to use parallel projection over perspective projection due to its relevance in architectural visualization. However, I’ve encountered several challenges when working with parallel projection, especially when animating camera movements.

Here are the key issues I’m facing:

  1. Parallel Projection Lens Length Limitation

    • When using parallel projection, the LensLength parameter becomes ineffective.
    • The ChangeToParallelProjection method does not incorporate LensLength, making it difficult to control the field of view (FOV).
    • In parallel mode, the only way to influence the viewport’s FOV is by adjusting the camera position relative to the target point. However, this is cumbersome and often results in an unexpectedly narrow view.
  2. Erratic Viewport Behavior During Animations

    • I’m trying to create a “hovering” animation where the camera follows a circular path around a target, akin to a drone circling a building.
    • While using sliders to animate the camera, the viewport often becomes uncontrollably wide during the rotation.
  3. Inconsistencies Between Perspective and Parallel Projections

    • Perspective projection works as expected, maintaining a predictable FOV.
    • However, switching to parallel projection introduces significant changes in the viewport.
    • Interestingly, when I toggle from perspective to parallel projection, the frustum’s intersection with the target plane remains consistent. I observed this by comparing two images: one taken in perspective mode (Image A) and the other in parallel mode (Image B).
      Perspective Frustum:

Parallel Frustum:

  1. Workaround Attempts

    • To control the frustum size, I tried the following approach:
      • First, set the camera to perspective mode and adjust the LensLength to control the frustum size.
      • Then, switch to parallel mode to maintain the adjusted frustum size.
      • To automate this, I used two camera components and introduced a delay of 100 ms (System.Threading.Thread.Sleep(100)) before activating the second (parallel) camera.
      • While this method works about 70% of the time, the viewport still behaves erratically during some animations (similar to the issue described above).
  2. Heteroptera Camera Crane

    • I experimented with the Heteroptera plugin’s Camera Crane component. While it allows LensLength to influence the frustum in parallel mode, the resulting FOV remains unexpectedly narrow.

Questions:

  • Is there a more reliable method to control the frustum size in parallel projection?
  • How can I ensure consistent viewport behavior during animations using parallel projection?
  • Are there any best practices or existing scripts/plugins to address these issues?

Attached are example images (Image A, Image B, and Image 3 from Heteroptera) to better illustrate the problem.

Any insights or recommendations would be greatly appreciated!

Thank you in advance!

After 2 days debugging with GPT.
I have a version of solution now.

Very time we set the camera in perspective way at first.
And calculate the corners of the view, and store them.
Input the viewport, return the targetCorners.

// Get the 3D corners of the target rectangle from the viewport
    public static List<Point3d> GetTargetRectCorners(Rhino.Display.RhinoViewport viewport)
    {
        Point3d[] nearCorners = viewport.GetNearRect();
        Point3d[] farCorners = viewport.GetFarRect();
        Point3d targetPoint = viewport.CameraTarget;

        // Define the target plane at the camera target location
        Plane nearPlane;
        viewport.GetFrustumNearPlane(out nearPlane);
        Plane targetPlane = new Plane(targetPoint, nearPlane.ZAxis);

        List<Point3d> intersectionPoints = new List<Point3d>();

        // Calculate intersections between frustum edges and the target plane
        for (int i = 0; i < nearCorners.Length; i++)
        {
            Line frustumEdge = new Line(nearCorners[i], farCorners[i]);
            if (Rhino.Geometry.Intersect.Intersection.LinePlane(frustumEdge, targetPlane, out double t))
            {
                Point3d intersectionPoint = frustumEdge.PointAt(t);
                intersectionPoints.Add(intersectionPoint);
            }
        }
        return intersectionPoints;

And then if the perspective type is Parallel, use the ZoomWindow method to adjust the size of the viewport. Use WorldToClient on the stored points, then ZoomWindow.

So that we can use the LensLength to control the Parallel camera as we do it in Perspective.