예제 #1
0
 public void Remap(SplineNode node, SplineFormer toFormer)
 {
     RemoveNodeImmediately(node);
     toFormer.Nodes.Add(node);
     node.SplineFormer = toFormer;
     InvalidateMesh();
     toFormer.InvalidateMesh();
 }
예제 #2
0
    /// <summary>
    /// Refreshs the node.
    /// </summary>
    public void RefreshNode()
    {
        Clean();
        if (SplineFormer == null)
        {
            return;
        }

        RecalculateBasicValues();
        RecalculateLocalPosition();

        if (_lastPostion != LocalPosition)
        {
            SplineFormer.InvalidateMesh();
        }

        _lastPostion = LocalPosition;
    }
예제 #3
0
    public override void OnInspectorGUI()
    {
        GetSplineFormer();
        DrawHeaderTexture();

        bool needRebuildMesh = false;
        bool needAddNode     = false;

        Color defaultBackColor = GUI.backgroundColor;
        Color defaultColor     = GUI.color;

        EditorGUILayout.LabelField("Lofting Groups");
        var groups = _splineFormer.LoftingGroups.ToList();

        EditorGUILayout.BeginVertical();

        EditorGUI.DrawRect(EditorGUILayout.GetControlRect(GUILayout.Height(2)), _separatorsColor);
        EditorGUI.indentLevel++;
        foreach (var group in groups)
        {
            GUI.backgroundColor = group.IsValid ? _valid : _invalid;
            int groupIndex = groups.IndexOf(group);
            if (groupIndex != 0)
            {
                EditorGUI.DrawRect(EditorGUILayout.GetControlRect(GUILayout.Height(1)), _separatorsColor);
            }

            EditorGUILayout.LabelField(
                String.Format("#{0} - {1}",
                              groupIndex, group.IsValid ? "Ready" : "Not ready")
                );

            EditorGUI.BeginChangeCheck();
            //======================
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Segment Mesh", GUILayout.MinWidth(_fieldWidth));
            EditorGUILayout.LabelField("MeshFilter", GUILayout.MinWidth(_fieldWidth));
            EditorGUILayout.LabelField("MeshCollider", GUILayout.MinWidth(_fieldWidth));
            EditorGUILayout.EndHorizontal();

            EditorGUI.BeginChangeCheck();
            EditorGUILayout.BeginHorizontal();
            group.SegmentMesh =
                (Mesh)EditorGUILayout.ObjectField(group.SegmentMesh, typeof(Mesh), false, GUILayout.MinWidth(_fieldWidth));
            group.MeshFilter =
                EditorGUILayout.ObjectField(group.MeshFilter, typeof(MeshFilter), true, GUILayout.MinWidth(_fieldWidth)) as MeshFilter;
            group.MeshCollider =
                EditorGUILayout.ObjectField(group.MeshCollider, typeof(MeshCollider), true, GUILayout.MinWidth(_fieldWidth)) as MeshCollider;
            EditorGUILayout.EndHorizontal();
            if (EditorGUI.EndChangeCheck())
            {
                if (group.MeshFilter != null)
                {
                    group.MeshFilter.sharedMesh = null;
                }
                if (group.MeshCollider != null)
                {
                    group.MeshCollider.sharedMesh = null;
                }
            }

            EditorGUILayout.LabelField("Interval");
            group.StartPosition = EditorGUILayout.Slider("Start Position", group.StartPosition, 0f, 1f);
            group.EndPosition   = EditorGUILayout.Slider("End Position", group.EndPosition, 0f, 1f);
            //===========================
            if (FoldoutOption("Caps", group))
            {
                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Start Piece");
                group.StartPiece =
                    (Mesh)EditorGUILayout.ObjectField(group.StartPiece, typeof(Mesh), false, GUILayout.MinWidth(_fieldWidth * 2));
                EditorGUILayout.EndHorizontal();
                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("End Piece");
                group.EndPiece =
                    (Mesh)EditorGUILayout.ObjectField(group.EndPiece, typeof(Mesh), true, GUILayout.MinWidth(_fieldWidth * 2));
                EditorGUILayout.EndHorizontal();
            }
            //====================
            if (FoldoutOption("Processing", group))
            {
                group.ProcessOriginNormals = EditorGUILayout.ToggleLeft("Process Origin Normals", group.ProcessOriginNormals);
                if (group.ProcessOriginNormals)
                {
                    group.RecalculateNormals = false;
                    group.SmoothNormals      = false;
                }

                group.ProcessOriginTangents = EditorGUILayout.ToggleLeft("Process Origin Tangents", group.ProcessOriginTangents);

                group.Weld = EditorGUILayout.ToggleLeft("Weld Close Vertices", group.Weld);

                float value = Mathf.Sqrt(group.WeldingDistance * 10f);
                value = EditorGUILayout.Slider("Welding Distance", value, 0.01f, 2f);
                group.WeldingDistance = (value * value) * 0.1f;

                group.RecalculateNormals = EditorGUILayout.ToggleLeft("Recalculate Normals", group.RecalculateNormals);
                if (!group.RecalculateNormals)
                {
                    group.SmoothNormals = false;
                }
                if (group.RecalculateNormals)
                {
                    group.ProcessOriginNormals = false;
                }

                group.SmoothNormals = EditorGUILayout.ToggleLeft("Smooth Normals", group.SmoothNormals);
                if (group.SmoothNormals)
                {
                    group.RecalculateNormals   = true;
                    group.ProcessOriginNormals = false;
                }
            }
            //====================

            if (EditorGUI.EndChangeCheck())
            {
                needRebuildMesh = true;
            }

            //================
            GUI.backgroundColor = defaultBackColor;

            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Remove", GUILayout.Width(_buttonWidth)))
            {
                RecordUndo();
                _splineFormer.LoftingGroups.Remove(group);
            }

            EditorGUILayout.Space();

            EditorGUI.BeginDisabledGroup(group.ResultMesh == null);
            string filename = "-";
            if (group.ResultMesh != null)
            {
                filename = group.ResultMesh.name;
            }
            if (GUILayout.Button("Save to OBJ", GUILayout.Width(_buttonWidth)))
            {
                Exporter.MeshToObjFile(group.ResultMesh, filename, _splineFormer.ExportOptions);
            }

            if (GUILayout.Button("Save to Asset", GUILayout.Width(_buttonWidth)))
            {
                Exporter.MeshToAsset(group.ResultMesh, filename, _splineFormer.ExportOptions);
            }
            EditorGUI.EndDisabledGroup();

            EditorGUILayout.EndHorizontal();

            EditorGUILayout.Separator();
        }
        EditorGUI.indentLevel--;
        EditorGUI.DrawRect(EditorGUILayout.GetControlRect(GUILayout.Height(2)), _separatorsColor);

        EditorGUILayout.EndVertical();

        GUI.backgroundColor = defaultBackColor;
        GUI.color           = defaultColor;

        if (GUILayout.Button("Add Group", GUILayout.Width(_buttonWidth)))
        {
            RecordUndo();
            _splineFormer.LoftingGroups.Add(new SplineFormer.LoftingGroup());
        }

        EditorGUI.BeginChangeCheck();
        _splineFormer.SegmentsNumber = Mathf.Max(1, EditorGUILayout.IntField("Segments Count", _splineFormer.SegmentsNumber));
        _splineFormer.Coefficient    = Mathf.Max(0.01f, EditorGUILayout.FloatField("Coefficient", _splineFormer.Coefficient));
        _splineFormer.LoftAngle      = EditorGUILayout.Slider("Loft Angle", _splineFormer.LoftAngle, 0f, 360f);
        _splineFormer.LoftDirection  = EditorGUILayout.Vector3Field("Loft Direction", _splineFormer.LoftDirection);
        if (_splineFormer.LoftDirection.sqrMagnitude < 0.1f)
        {
            _splineFormer.LoftDirection = Vector3.forward;
        }

        _splineFormer.SegmentScale = EditorGUILayout.Vector3Field("Segment Scale", _splineFormer.SegmentScale);

        _splineFormer.QuadraticSmooth = EditorGUILayout.Toggle("Quadratic Smooth", _splineFormer.QuadraticSmooth);
        var loop = EditorGUILayout.Toggle("Loop", _splineFormer.Loop);

        _splineFormer.RollerCoasterFix = EditorGUILayout.Toggle("Roller Coaster Fix", _splineFormer.RollerCoasterFix);
        EditorGUILayout.Separator();

        if (EditorGUI.EndChangeCheck())
        {
            needRebuildMesh = true;
            RecordDeepUndo();
            if (_splineFormer.Loop != loop)
            {
                Undo.RecordObject(_splineFormer.StartNode.transform, "StartNode move");
                Undo.RecordObject(_splineFormer.EndNode.transform, "EndNode move");
                _splineFormer.Loop = loop;
            }
        }

        EditorGUILayout.Separator();


        _showVisualOptions = EditorGUILayout.Foldout(_showVisualOptions, "Visual Options");
        if (_showVisualOptions)
        {
            EditorGUI.BeginChangeCheck();
            _splineFormer.VisualOptions.NodeSize = Mathf.Max(0.001f,
                                                             EditorGUILayout.FloatField("Node Size", _splineFormer.VisualOptions.NodeSize));

            _splineFormer.VisualOptions.ShowNodeLinks = EditorGUILayout.Toggle("Show Node Links",
                                                                               _splineFormer.VisualOptions.ShowNodeLinks);

            _splineFormer.VisualOptions.ShowSegmentsPath = EditorGUILayout.Toggle("Show Segments Path",
                                                                                  _splineFormer.VisualOptions.ShowSegmentsPath);

            _splineFormer.VisualOptions.ShowTangentNodes = EditorGUILayout.Toggle("Show Tangent Nodes",
                                                                                  _splineFormer.VisualOptions.ShowTangentNodes);

            _splineFormer.VisualOptions.ShowTangents = EditorGUILayout.Toggle("Show Tangents",
                                                                              _splineFormer.VisualOptions.ShowTangents);

            if (EditorGUI.EndChangeCheck())
            {
                EditorUtility.SetDirty(target);
            }
        }

        _showExportOptions = EditorGUILayout.Foldout(_showExportOptions, "Export Options");
        if (_showExportOptions)
        {
            EditorGUI.BeginChangeCheck();
            _splineFormer.ExportOptions.ShowSaveAsDialog = EditorGUILayout.Toggle("Show \"Save As\" Dialog",
                                                                                  _splineFormer.ExportOptions.ShowSaveAsDialog);

            _splineFormer.ExportOptions.ShowExportResultDialog = EditorGUILayout.Toggle("Show Export Result Dialog",
                                                                                        _splineFormer.ExportOptions.ShowExportResultDialog);

            EditorGUILayout.BeginHorizontal();

            var assetsFolder = Path.GetFullPath("Assets/").Replace('\\', '/');

            EditorGUILayout.LabelField("Default Export Folder", _splineFormer.ExportOptions.DefaultFolder);

            if (GUILayout.Button("Select"))
            {
                var defaultFolder = _splineFormer.ExportOptions.DefaultFolder;

                if (!Directory.Exists(defaultFolder))
                {
                    defaultFolder = assetsFolder;
                }
                var selectedFolder = EditorUtility.SaveFolderPanel("Default Export Folder",
                                                                   defaultFolder, "Splines");

                if (!selectedFolder.Contains(assetsFolder))
                {
                    EditorUtility.DisplayDialog(
                        "Path is outside the assets folder",
                        String.Format("Asset can't be saved outside of the folder \"{0}\"",
                                      assetsFolder),
                        "OK");
                }
                else
                {
                    _splineFormer.ExportOptions.DefaultFolder = selectedFolder.Replace(assetsFolder, "");
                }
            }
            EditorGUILayout.EndHorizontal();

            _splineFormer.ExportOptions.ExtendedNaming = EditorGUILayout.Toggle("Extended Naming",
                                                                                _splineFormer.ExportOptions.ExtendedNaming);

            if (_splineFormer.ExportOptions.ExtendedNaming)
            {
                EditorGUI.indentLevel++;

                _splineFormer.ExportOptions.AddObjectName = EditorGUILayout.Toggle("Add Object Name",
                                                                                   _splineFormer.ExportOptions.AddObjectName);

                _splineFormer.ExportOptions.AddLoftingGroupIndex = EditorGUILayout.Toggle("Add Lofting Group Index",
                                                                                          _splineFormer.ExportOptions.AddLoftingGroupIndex);

                _splineFormer.ExportOptions.CustomName = EditorGUILayout.TextField("Custom Name",
                                                                                   _splineFormer.ExportOptions.CustomName);

                _splineFormer.ExportOptions.AddDateTime = EditorGUILayout.Toggle("Add Date/Time Stamp",
                                                                                 _splineFormer.ExportOptions.AddDateTime);

                _splineFormer.ExportOptions.AddAutoIncrementNumber = EditorGUILayout.Toggle("Add Auto Increment Number",
                                                                                            _splineFormer.ExportOptions.AddAutoIncrementNumber);

                EditorGUI.indentLevel--;
            }


            if (EditorGUI.EndChangeCheck())
            {
                EditorUtility.SetDirty(target);
            }
        }

        EditorGUILayout.BeginHorizontal();
        needAddNode     |= GUILayout.Button("Add Node", GUILayout.Width(_buttonWidth));
        needRebuildMesh |= GUILayout.Button("Refresh", GUILayout.Width(_buttonWidth));
        EditorGUILayout.EndHorizontal();

        if (needAddNode)
        {
            _splineFormer.AddNewNode();
        }

        if (needRebuildMesh || needAddNode)
        {
            _splineFormer.InvalidateMesh();
            EditorUtility.SetDirty(target);
        }
    }
예제 #4
0
    // Gets new data from Sense
    public void NewData(string d)
    {
        // Remove any existing sankey
        foreach (Transform child in transform)
        {
            GameObject.Destroy(child.gameObject);
        }
        transform.rotation = Quaternion.identity;
        transform.position = new Vector3(0, 0, 0);
        pathGOs.Clear();

        Debug.Log("data: " + d);
        JSONNode JPaths = JSON.Parse(d);
        //var pathList = new List<Path>();
        var Paths          = new Dictionary <int, Dictionary <string, int> >();
        var CompletedPaths = new Dictionary <int, float>();
        var Groups         = new Dictionary <int, Dictionary <string, float> >();
        int MaxSteps       = 0;

        for (int i = 0; i < JPaths.AsArray.Count; i++)
        {
            // Splice path
            string p = JPaths[i];
            //Debug.Log("path: " + p);
            string   path  = p.Substring(1, p.Length - 2);
            string[] nodes = path.Split(',');
            if (nodes.Length < 2)
            {
                continue;
            }

            for (int j = 0; j < nodes.Length; j++)
            {
                string n = nodes[j];
                //Debug.Log("node: " + n);
                if (Paths.ContainsKey(j))
                {
                    if (Paths[j].ContainsKey(n))
                    {
                        Paths[j][n]++;
                    }
                    else
                    {
                        Paths[j][n] = 1;
                    }
                }
                else
                {
                    Paths.Add(j, new Dictionary <string, int>());
                    Paths[j][n] = 1;
                }
                MaxSteps = MaxSteps > Paths[j][n] ? MaxSteps : Paths[j][n];
                //Original
                //MaxSteps = MaxSteps > Paths[j][n] ? MaxSteps : Paths[j][n];

                MaxSteps = MaxSteps > nodes.Length ? MaxSteps : nodes.Length;
                Debug.Log("SANKEY MaxSteps: " + MaxSteps);
            }
        }

        for (int i = 0; i < JPaths.AsArray.Count; i++)
        {
            string   p     = JPaths[i];
            string   path  = p.Substring(1, p.Length - 2);
            string[] nodes = path.Split(',');
            if (nodes.Length < 2)
            {
                continue;
            }
            if (nodes.Length < Paths.Count)
            {
                Paths[Paths.Count - 1][nodes[nodes.Length - 1]] = 1;
            }
        }
        Debug.Log("Last pos length: " + Paths[Paths.Count - 1].Count);

        for (int i = 0; i < JPaths.AsArray.Count; i++)
        {
            // Splice path
            string p = JPaths[i];
            Debug.Log("path: " + p);
            string   path  = p.Substring(1, p.Length - 2);
            string[] nodes = path.Split(',');
            if (nodes.Length < 2)
            {
                continue;
            }

            GameObject go = createSpline();
            Vector3    pp = transform.position;
            //            go.transform.position = new Vector3(pp.x, chartHeight / (float)JPaths.AsArray.Count * (float)i, pp.z);
            go.transform.position = new Vector3(pp.x, pp.y, pp.z);
            pathGOs.Add(go);

            // Setup nodes
            SplineFormer sf = go.GetComponent <SplineFormer>();

            for (int j = 0; j < nodes.Length; j++)
            {
                string n = nodes[j];
                //Debug.Log("node: " + n);

                //                float zStep= chartLength / (nodes.Length-1);
                float zStep = chartLength / MaxSteps;
                //                float zPos = zStep * (float)j;
                float zPos;
                zPos = j < (nodes.Length - 1) ? zStep * (float)j : chartLength;

                if (j < nodes.Length - 1)
                {
                    if (CompletedPaths.ContainsKey(j))
                    {
                        CompletedPaths[j]++;
                    }
                    else
                    {
                        CompletedPaths.Add(j, 1f);
                    }
                }
                else
                {
                    if (CompletedPaths.ContainsKey(Paths[Paths.Count - 1].Count))
                    {
                        CompletedPaths[Paths[Paths.Count - 1].Count]++;
                    }
                    else
                    {
                        CompletedPaths.Add(Paths[Paths.Count - 1].Count, 1f);
                    }
                }

                SplineNode sn = null;
                if (j > 1)
                {
                    sn = sf.AddNodeImmediately();
                    Vector3 f = sn.transform.position;
                    float   hOffset;
                    if (j < nodes.Length - 1)
                    {
                        if (Groups.ContainsKey(j))
                        {
                            if (Groups[j].ContainsKey(n))
                            {
                                hOffset = Groups[j][n];
                            }
                            else
                            {
                                Groups[j][n] = chartHeight / (float)(Paths[j].Count + 1) * CompletedPaths[j];
                                hOffset      = Groups[j][n];
                            }
                        }
                        else
                        {
                            Groups.Add(j, new Dictionary <string, float>());
                            Groups[j][n] = chartHeight / (float)(Paths[j].Count + 1) * CompletedPaths[j];
                            hOffset      = Groups[j][n];
                        }
                    }
                    else
                    {
                        //hOffset = chartHeight / (float)(Paths[Paths.Count - 1].Count + 1) * CompletedPaths[Paths[Paths.Count - 1].Count];
                        if (Groups.ContainsKey(Paths.Count - 1))
                        {
                            if (Groups[Paths.Count - 1].ContainsKey(n))
                            {
                                hOffset = Groups[Paths.Count - 1][n];
                            }
                            else
                            {
                                Groups[Paths.Count - 1][n] = chartHeight / (float)(Paths[Paths.Count - 1].Count + 1) * CompletedPaths[Paths[Paths.Count - 1].Count];
                                hOffset = Groups[Paths.Count - 1][n];
                            }
                        }
                        else
                        {
                            Groups.Add(Paths.Count - 1, new Dictionary <string, float>());
                            Groups[Paths.Count - 1][n] = chartHeight / (float)(Paths[Paths.Count - 1].Count + 1) * CompletedPaths[Paths[Paths.Count - 1].Count];
                            hOffset = Groups[Paths.Count - 1][n];
                        }
                    }


                    f = f + Vector3.up * hOffset;
                    sn.transform.position = new Vector3(f.x, f.y, zPos);
                }
                else if (j == 1)
                {
                    sn = sf.Nodes[j];
                    Vector3 f = sn.transform.position;
                    float   hOffset;
                    if (j < nodes.Length - 1)
                    {
                        //Debug.Log("Path count: " + Paths[j][n]);
                        if (Paths[j][n] > 1)
                        {
                            if (Groups.ContainsKey(j))
                            {
                                if (Groups[j].ContainsKey(n))
                                {
                                    hOffset = Groups[j][n];
                                }
                                else
                                {
                                    Groups[j][n] = chartHeight / (float)(Paths[j].Count + 1) * CompletedPaths[j];
                                    hOffset      = Groups[j][n];
                                }
                            }
                            else
                            {
                                Groups.Add(j, new Dictionary <string, float>());
                                Groups[j][n] = chartHeight / (float)(Paths[j].Count + 1) * CompletedPaths[j];
                                hOffset      = Groups[j][n];
                            }
                        }
                        else
                        {
                            hOffset = chartHeight / (float)(Paths[j].Count + 1) * CompletedPaths[j];
                        }
                    }
                    else
                    {
                        //hOffset = chartHeight / (float)(Paths[Paths.Count - 1].Count + 1) * CompletedPaths[Paths[Paths.Count - 1].Count];
                        if (Groups.ContainsKey(Paths.Count - 1))
                        {
                            if (Groups[Paths.Count - 1].ContainsKey(n))
                            {
                                hOffset = Groups[Paths.Count - 1][n];
                            }
                            else
                            {
                                Groups[Paths.Count - 1][n] = chartHeight / (float)(Paths[Paths.Count - 1].Count + 1) * CompletedPaths[Paths[Paths.Count - 1].Count];
                                hOffset = Groups[Paths.Count - 1][n];
                            }
                        }
                        else
                        {
                            Groups.Add(Paths.Count - 1, new Dictionary <string, float>());
                            Groups[Paths.Count - 1][n] = chartHeight / (float)(Paths[Paths.Count - 1].Count + 1) * CompletedPaths[Paths[Paths.Count - 1].Count];
                            hOffset = Groups[Paths.Count - 1][n];
                        }
                    }

                    f = f + Vector3.up * hOffset;
                    sn.transform.position = new Vector3(f.x, f.y, zPos);
                }
                else if (j == 0)
                {
                    sn = sf.Nodes[j];
                    Vector3 f = sn.transform.position;

                    float yStep = chartHeight / (float)JPaths.AsArray.Count;
                    ////                    f = f + Vector3.up * -((float)i-1f) * yStep;
                    //                    f = f + Vector3.up * chartHeight / (float)(Paths[j].Count+1);
                    //Debug.Log("NumNodesAtPos " + j + ": " + Paths[j].Count + " for path " + i + " = " + chartHeight / (float)(Paths[j].Count + 1));

                    if (Groups.ContainsKey(j))
                    {
                        if (!Groups[j].ContainsKey(n))
                        {
                            Groups[j][n] = chartHeight / (float)(Paths[j].Count + 1);
                        }
                    }
                    else
                    {
                        Groups.Add(j, new Dictionary <string, float>());
                        Groups[j][n] = chartHeight / (float)(Paths[j].Count + 1);
                    }

                    f = f + Vector3.up * Groups[j][n];
                    sn.transform.position = f;
                }

                // Add Sphere Nodes to nodes
                GameObject spNode = (GameObject)Instantiate(Resources.Load("SankeyNode"), sn.transform.position, sn.transform.rotation);
                Vector3    vec    = new Vector3(0f, 1f, 0f);
                spNode.transform.Rotate(vec, 180f);
                spNode.transform.SetParent(sn.transform);
                float _nodeScaler = Mathf.Lerp(0.1f, 0.2f, Paths[j][n] / MaxSteps);
                spNode.transform.localScale = new Vector3(_nodeScaler, _nodeScaler, _nodeScaler);

                // Add Text Labels to nodes
                GameObject label = spNode.transform.GetChild(0).gameObject;
                label.transform.RotateAround(sn.transform.position, Vector3.up, 90);
                GameObject txt = label.transform.GetChild(0).gameObject;
                txt.GetComponent <UnityEngine.UI.Text>().text = n;

                // Add Tap Handler
                SelectMgr hit = spNode.AddComponent <SelectMgr>();
            }
            sf.InvalidateMesh();
        }

        // Move Sankey above patient

        /*Vector3 pPos = patient.transform.position;
         * pPos.x -= 0.4f;
         * pPos.y += 0.8f;
         * pPos.z -= 0.5f;
         * gameObject.transform.position = pPos;
         * Quaternion pRot = patient.transform.rotation;
         * pRot.y -= Mathf.PI * 0.25f;
         * gameObject.transform.rotation = pRot;
         */
        ReTag(gameObject.transform, LayerMask.NameToLayer("Sankey"));
    }
예제 #5
0
 public void Remap(SplineNode node, SplineFormer toFormer)
 {
     RemoveNodeImmediately(node);
     toFormer.Nodes.Add(node);
     node.SplineFormer = toFormer;
     InvalidateMesh();
     toFormer.InvalidateMesh();
 }
예제 #6
0
 void Update()
 {
     splineFormer.LoftAngle = 180 * Mathf.Sin(Time.timeSinceLevelLoad);
     splineFormer.InvalidateMesh();
 }