Jump to content

Drawing bezier curves in the Tracking Station


Recommended Posts

Hello everyone,

Whitecat here with a question about drawing and rendering lines in the tracking station.

Basically for my Orbital Decay modification I am beginning to implement n-body simulation, the actual simulation and orbit movements are fine, however such movements are 'forbidden' by the tracking station conics system. e.g, An orbit must ellipsoidal under all circumstances forever... Similarly during timewarp the whole affair gets horrifically messy and would make any sort of space rendezvous beyond 1/2 Hill Sphere radii impossible.

However I have a found a solution to this by removing the stock conic rendering for a certain vessel and creating a stepped prediction for the orbit shape and size at various points using position vectors across a period of time. Creating a 'line of best fit path between them. Alas during implementation of this an exception is thrown,

Quote

NullReferenceException
  at (wrapper managed-to-native) UnityEngine.MeshFilter:set_mesh (UnityEngine.Mesh)

Personally I have no experience of any line rendering past creating a GUI, so I have been following the code of Remote Tech's line drawing as a guide. 

If anyone could shed light on any issues with the code below I would be very grateful!

foreach (Orbit orbit in FutureRenderOrbits)
            {
                Vector3 PositionAtStart = orbit.getTruePositionAtUT(time + (TimeSnapshots * FutureRenderOrbits.IndexOf(orbit)));
                Vector3 PositionAt1stDegree = orbit.getTruePositionAtUT(time + (TimeSnapshots * (FutureRenderOrbits.IndexOf(orbit) + (1.0 / 6.0))));
                Vector3 PositionAt2ndDegree = orbit.getTruePositionAtUT(time + (TimeSnapshots * (FutureRenderOrbits.IndexOf(orbit) + (2.0 / 6.0))));
                Vector3 PositionAt3rdDegree = orbit.getTruePositionAtUT(time + (TimeSnapshots * (FutureRenderOrbits.IndexOf(orbit) + (3.0 / 6.0))));
                Vector3 PositionAt4thDegree = orbit.getTruePositionAtUT(time + (TimeSnapshots * (FutureRenderOrbits.IndexOf(orbit) + (4.0 / 6.0))));
                Vector3 PositionAt5thDegree = orbit.getTruePositionAtUT(time + (TimeSnapshots * (FutureRenderOrbits.IndexOf(orbit) + (5.0 / 6.0))));
                Vector3 PositionAtEnd = orbit.getTruePositionAtUT(time + (TimeSnapshots * (FutureRenderOrbits.IndexOf(orbit) + 1)));

                MeshRenderer OrbitBezierRenderer= new MeshRenderer();
                MeshFilter OrbitBezierFilter = new MeshFilter();

                GameObject OrbitBezier = new GameObject("OrbitBezierLine");
                if (gameObject.GetComponent<MeshRenderer>() == null)
                {
                    OrbitBezierRenderer = gameObject.AddComponent<MeshRenderer>();
                }
                if (gameObject.GetComponent<MeshFilter>() == null)
                {
                    OrbitBezierFilter = gameObject.AddComponent<MeshFilter>();
                }
                OrbitBezierFilter.mesh = new Mesh();
                OrbitBezierFilter.mesh.name = "OrbitBezierLine";
                OrbitBezierFilter.mesh.vertices = new Vector3[5];
                OrbitBezierFilter.mesh.uv = new Vector2[5] { new Vector2(0, 1), new Vector2(0,1),
                  new Vector2(0, 0), new Vector2(1, 1), new Vector2(1, 0) };
                  
                OrbitBezierFilter.mesh.SetIndices(new int[] { 0, 2, 1, 2, 3, 1 }, MeshTopology.Triangles, 0);
                OrbitBezierFilter.mesh.colors = Enumerable.Repeat(Color.red, 5).ToArray();
                
                lineMaterial = MapView.fetch.orbitLinesMaterial;

                OrbitBezierRenderer.material = lineMaterial;

                Vector3[] Points2D = new Vector3[4];
                Vector3[] Points3D = new Vector3[5];

                float LineWidth = 1.0f;

                var camera = PlanetariumCamera.Camera;
                var start = camera.WorldToScreenPoint(ScaledSpace.LocalToScaledSpace(PositionAtStart));
                var end = camera.WorldToScreenPoint(ScaledSpace.LocalToScaledSpace(PositionAtEnd));
                var segment = new Vector3(end.y - start.y, start.x - end.x, 0).normalized * (LineWidth / 2);

                 if (!MapView.Draw3DLines)
                 {
                    var dist = Screen.height / 2 + 0.01f;
                    start.z = start.z >= 0.15f ? dist : -dist;
                    end.z = end.z >= 0.15f ? dist : -dist;
                 }
                 OrbitBezier.layer = 31;

                 Points3D[0] = camera.ScreenToWorldPoint(PositionAt1stDegree);
                 Points3D[1] = camera.ScreenToWorldPoint(PositionAt2ndDegree);
                 Points3D[2] = camera.ScreenToWorldPoint(PositionAt3rdDegree);
                 Points3D[3] = camera.ScreenToWorldPoint(PositionAt4thDegree);
                 Points3D[4] = camera.ScreenToWorldPoint(PositionAt5thDegree);

                 OrbitBezierFilter.mesh.vertices = MapView.Draw3DLines ? Points3D : Points2D;
                 OrbitBezierFilter.mesh.RecalculateBounds();
                 OrbitBezierFilter.mesh.MarkDynamic();

Please note: Only 6 degrees of Position vectors during a time interval are being shown here, in reality during a high (1000x time warp) around 50 position vectors will be necessary to ensure accuracy of the tracing. The intention of the code is to draw a 'dot to dot' between the position vectors at the start and end of an orbit snapshot (since the orbit will be changed regularly due to n-body perturbation), using the PositionAtNthDegree vectors to provide vertex points to 'beziate' the line to the correct (accurate) orbital curvature. 

Feedback on how to make the above code actually render a line or two, or even a better method of drawing bezier curves in the Planetarium view would be greatly appreciated! 

Thanks for your time!

Whitecat106 :)

 

Link to comment
Share on other sites

An exception with a trace that looks like that is usually a good sign that the native side of the object is missing, usually because the component/GO was destroyed or because it was created incorrectly. Both MeshFilter and MeshRenderer are Components which must be attached to a GameObject and should never be created using new, so these lines are definitely wrong (maybe just an oversight?):

MeshRenderer OrbitBezierRenderer= new MeshRenderer();
MeshFilter OrbitBezierFilter = new MeshFilter();

This is why you're seeing the exception. The very first run through the foreach, gameObject* doesn't have a MeshRenderer or MeshFilter so the values from the above are tossed out and the correct method to create them is used. The second iteration then attempts to use the wrongly constructed object because the script's GO has a MeshRenderer and MeshFilter now.

* note your logic error there: surely you intended to use the GameObject [BezierOrbit] you've created for the orbit, in which case the MeshRenderer/MeshFilter checks are unnecessary anyway

 

Edited by xEvilReeperx
Link to comment
Share on other sites

14 hours ago, xEvilReeperx said:

An exception with a trace that looks like that is usually a good sign that the native side of the object is missing, usually because the component/GO was destroyed or because it was created incorrectly. Both MeshFilter and MeshRenderer are Components which must be attached to a GameObject and should never be created using new, so these lines are definitely wrong (maybe just an oversight?):


MeshRenderer OrbitBezierRenderer= new MeshRenderer();
MeshFilter OrbitBezierFilter = new MeshFilter();

This is why you're seeing the exception. The very first run through the foreach, gameObject* doesn't have a MeshRenderer or MeshFilter so the values from the above are tossed out and the correct method to create them is used. The second iteration then attempts to use the wrongly constructed object because the script's GO has a MeshRenderer and MeshFilter now.

* note your logic error there: surely you intended to use the GameObject [BezierOrbit] you've created for the orbit, in which case the MeshRenderer/MeshFilter checks are unnecessary anyway

 

Thanks for your feedback! I have adjusted the following code to this:


                MeshRenderer OrbitBezierRenderer;
                MeshFilter OrbitBezierFilter;
                
                GameObject OrbitBezier = new GameObject("OrbitBezierLine");


                if (OrbitBezier.GetComponent<MeshRenderer>() == null)
                {
                     OrbitBezierRenderer = OrbitBezier.AddComponent<MeshRenderer>();
                }
                if (OrbitBezier.GetComponent<MeshFilter>() == null)
                {
                     OrbitBezierFilter = OrbitBezier.AddComponent<MeshFilter>();
                }

                OrbitBezierFilter = OrbitBezier.GetComponent<MeshFilter>();
                OrbitBezierRenderer = OrbitBezier.GetComponent<MeshRenderer>();

However this time, although no errors appear, no line is rendered either, anywhere in the tracking station. :( Any suggestions? The full code is available here if anything else is necessary. I'm very much a novice with this and sadly so little information on the subject seems available, with different plugins using widely different methods, for example, Remote Tech appears to use the more simple method of visible line drawing than say KSP Trajectories, even though the trajectories mod is more akin to what I require. 

Whitecat106 :)

Link to comment
Share on other sites

You might want to try just creating a line where you want it before you throw in all the orbit stuff. There's at least two errors in there: you're creating a mesh in scaled space but trying to use points in local space, and 2) this makes no sense:

Vector3 PositionAt1stDegree = orbit.getTruePositionAtUT(time + (TimeSnapshots * (FutureRenderOrbits.IndexOf(orbit) + (1.0 / 6.0))));
                Vector3 PositionAt2ndDegree = orbit.getTruePositionAtUT(time + (TimeSnapshots * (FutureRenderOrbits.IndexOf(orbit) + (2.0 / 6.0))));
// etc

Points3D[0] = camera.ScreenToWorldPoint(PositionAt1stDegree);
Points3D[1] = camera.ScreenToWorldPoint(PositionAt2ndDegree);
// etc

1) you're taking a point in world space and passing it through a transformation like it was in screen space (oversight?)

2) the camera you're using for the transformation is set up for scaled world space. Convert your vectors from local to scaled space before trying to use the planetarium camera with them

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...