Draw infinite world axes

With the following class derived from Model you can draw the infinite world axes as shown in the following image: 

The axes are drawn in 3 overridden methods:

DrawViewportBackground: the part of the axes beyond the far plane

DrawViewport: the part between the camera planes

DrawOverlay: the part nearer than the camera near plane

[Update] The code has been improved to support multiple Viewports. Requires Eyeshot 9 >= 9.0.490 or Eyeshot 10 >= 10.0.859

internal class MyModel : Model
    {

        public Color AxisXColor { get; set; } = Color.Red;
        public Color AxisYColor { get; set; } = Color.Green;
        public Color AxisZColor { get; set; } = Color.Blue;
        // Intersections with the camera planes
        Point3D ptXNear, ptXFar, ptYNear, ptYFar, ptZNear, ptZFar;
        protected override void DrawViewportBackground(DrawSceneParams data)
        {
            base.DrawViewportBackground(data);

            ComputeNearFarIntersections(data.Viewport);

            var rc = data.RenderContext;
            rc.PushDepthStencilState();

            rc.SetState(depthStencilStateType.DepthTestOff);
            rc.SetShader(shaderType.NoLights);

            // Draw in 2D the parts of the lines beyond the far camera plane

            // X axis 
            DrawLinesBeyondFar(data.Viewport, ptXNear, ptXFar, AxisXColor);

            // Y axis 
            DrawLinesBeyondFar(data.Viewport, ptYNear, ptYFar, AxisYColor);

            // Z axis 
            DrawLinesBeyondFar(data.Viewport, ptZNear, ptZFar, AxisZColor);

            rc.PopDepthStencilState();
        }

        private void ComputeNearFarIntersections(Viewport viewport)
        {
            Plane farPlane = viewport.Camera.FarPlane;
            Plane nearPlane = viewport.Camera.NearPlane;

            Segment3D sX = new Segment3D(0, 0, 0, 1, 0, 0);
            Segment3D sY = new Segment3D(0, 0, 0, 0, 1, 0);
            Segment3D sZ = new Segment3D(0, 0, 0, 0, 0, 1);
            // Compute the intersections with the camera planes
            if (!Vector3D.AreParallel(viewport.Camera.ViewNormal, Vector3D.AxisX))
            {
                sX.IntersectWith(nearPlane, true, out ptXNear);
                sX.IntersectWith(farPlane, true, out ptXFar);
                if (ptXNear == null)
                {
                    ptXNear = new Point3D(-1e10, 0, 0);
                    ptXFar = new Point3D(1e10, 0, 0);

                }
            }
            else
            {
                ptXNear = null;
                ptXFar = null;
            }

            if (!Vector3D.AreParallel(viewport.Camera.ViewNormal, Vector3D.AxisY))
            {
                sY.IntersectWith(nearPlane, true, out ptYNear);
                sY.IntersectWith(farPlane, true, out ptYFar);
                if (ptYNear == null)
                {
                    ptYNear = new Point3D(0, -1e10, 0);
                    ptYFar = new Point3D(0, 1e10, 0);
                }
            }
            else
            {
                ptYNear = null;
                ptYFar = null;
            }
            if (!Vector3D.AreParallel(viewport.Camera.ViewNormal, Vector3D.AxisZ))
            {
                sZ.IntersectWith(nearPlane, true, out ptZNear);
                sZ.IntersectWith(farPlane, true, out ptZFar);
                if (ptZNear == null)
                {
                    ptZNear = new Point3D(0, 0, -1e10);
                    ptZFar = new Point3D(0, 0, 1e10);
                }
            }

            
            else
            {
                ptZNear = null;
                ptZFar = null;
            }
            
        }

        protected override void DrawViewport(DrawSceneParams myParams)
        {
            base.DrawViewport(myParams);

            var rc = myParams.RenderContext;

            rc.SetShader(shaderType.NoLights);

            // Draw the 3D lines between the camera planes

            if (ptXNear != null && ptXFar != null)
            {
                rc.SetColorWireframe(AxisXColor);
                rc.DrawLines(new Point3D[] { ptXNear, ptXFar });
            }

            if (ptYNear != null && ptYFar != null)
            {
                rc.SetColorWireframe(AxisYColor);
                rc.DrawLines(new Point3D[] { ptYNear, ptYFar });
            }

            if (ptZNear != null && ptZFar != null)
            {
                rc.SetColorWireframe(AxisZColor);
                rc.DrawLines(new Point3D[] { ptZNear, ptZFar });
            }

        }

        protected override void DrawOverlay(DrawSceneParams data)
        {


            // Draw in 2D the parts of the lines before the near camera plane
            renderContext.SetShader(shaderType.NoLights);

            for (int i = 0; i < Viewports.Count; i++)
            {
                ComputeNearFarIntersections(Viewports[i]);

                // X axis 
                DrawLinesBeforeNear(Viewports[i], ptXNear, ptXFar, AxisXColor);

                // Y axis 
                DrawLinesBeforeNear(Viewports[i], ptYNear, ptYFar, AxisYColor);

                // Z axis 
                DrawLinesBeforeNear(Viewports[i], ptZNear, ptZFar, AxisZColor);
            }


        }

        private void DrawLinesBeyondFar(Viewport viewport, Point3D nearPt, Point3D farPt, Color color)
        {
            if (farPt == null || nearPt == null)
                return;

            Vector3D dir = Vector3D.Subtract(farPt, nearPt);
            dir.Normalize();

            if (viewport == null)
                viewport = ActiveViewport;

            Point3D pt1 = viewport.WorldToScreen(farPt);
            Point3D pt2 = viewport.WorldToScreen(farPt + dir);
            DrawLine(viewport, pt1, pt2, color, true);
        }

        private void DrawLinesBeforeNear(Viewport viewport, Point3D nearPt, Point3D farPt, Color color)
        {
            if (farPt == null || nearPt == null)
                return;

            Vector3D dir = Vector3D.Subtract(farPt, nearPt);
            dir.Normalize();

            if (viewport == null)
                viewport = ActiveViewport;

            var pt1 = viewport.WorldToScreen(nearPt);
            var pt2 = viewport.WorldToScreen(nearPt - dir);
            DrawLine(viewport, pt1, pt2, color, false);
        }

        private void DrawLine(Viewport viewport, Point3D pt1, Point3D pt2, Color color, bool convertToViewport)
        {
            if (pt1 == null || pt2 == null)
                return;

            Segment2D screenLine = new Segment2D(pt1, pt2);

            int[] viewFrame = viewport.GetViewFrame();

            double left = viewFrame[0];
            double right = viewFrame[0] + viewFrame[2];
            double bottom = viewFrame[1];
            double top = viewFrame[1] + viewFrame[3] - 1;
            Point2D lowerLeft = new Point2D(left, bottom);
            Point2D lowerRight = new Point2D(right, bottom);
            Point2D upperLeft = new Point2D(left, top);
            Point2D upperRight = new Point2D(right, top);


            Segment2D[] screenLines = new Segment2D[]
            {
            new Segment2D(lowerLeft, lowerRight),
            new Segment2D(upperLeft, upperRight),
            new Segment2D(lowerLeft, upperLeft),
            new Segment2D(lowerRight, upperRight)
            };

            Point2D ptAxis1 = null, ptAxis2 = null;

            Vector2D dir = Vector2D.Subtract(pt2, pt1);
            dir.Normalize();

            // extend the segment outside the window limits
            screenLine.P1 = screenLine.P0 + dir * (viewport.Size.Width + viewport.Size.Height);

            // Compute the intersection of the screen line against the lower and upper border of the viewport 
            Segment2D.Intersection(screenLine, screenLines[0], out ptAxis1);
            Segment2D.Intersection(screenLine, screenLines[1], out ptAxis2);

            if (ptAxis1 != null)

                screenLine.P1 = ptAxis1;

            if (ptAxis2 != null)

                screenLine.P1 = ptAxis2;

            bool clipAgainstVertical = true;

            // Compute the intersection of the infinite screen line against the left and right border of the viewport 
            Segment2D.Intersection(screenLine, screenLines[2], out ptAxis1);
            Segment2D.Intersection(screenLine, screenLines[3], out ptAxis2);

            if (ptAxis1 != null)

                screenLine.P1 = ptAxis1;

            if (ptAxis2 != null)

                screenLine.P1 = ptAxis2;

            renderContext.SetLineSize(1);
            renderContext.EnableThickLines();
            renderContext.SetColorWireframe(color);

            var tol = 1e-6;

            // Consider some tolerance
            if (screenLine.P0.X >= left - tol && screenLine.P0.X <= right + tol &&
                screenLine.P0.Y >= bottom - tol && screenLine.P0.Y <= top + tol &&
                screenLine.P1.X >= left - tol && screenLine.P1.X <= right + tol &&
                screenLine.P1.Y >= bottom - tol && screenLine.P1.Y <= top + tol)
            {
                if (convertToViewport)
                {
                    // When drawing the lines beyond far inside the DrawViewportBackground, the camera is set to just the Viewport, not to the whole ViewportLayout,
                    // so if we have multiple viewports we must adjust the screen coordinates
                    screenLine.P0 = new Point2D(screenLine.P0.X - left, screenLine.P0.Y - bottom);
                    screenLine.P1 = new Point2D(screenLine.P1.X - left, screenLine.P1.Y - bottom);
                }

                renderContext.DrawLines(new float[]
                {
                (float) screenLine.P0.X, (float) screenLine.P0.Y, 0,
                (float) screenLine.P1.X, (float) screenLine.P1.Y, 0
                });
            }
        }
        
    }

Previous versions of this article: Eyeshot 12, Eyeshot 8, Eyeshot 7

Was this article helpful?
1 out of 1 found this helpful
Have more questions? Submit a request

Comments

0 comments

Please sign in to leave a comment.