{"id":465,"date":"2013-01-05T23:43:46","date_gmt":"2013-01-05T22:43:46","guid":{"rendered":"http:\/\/piflik.de\/?p=465"},"modified":"2013-01-05T23:43:46","modified_gmt":"2013-01-05T22:43:46","slug":"procedural-splines","status":"publish","type":"post","link":"http:\/\/piflik.de\/?p=465","title":{"rendered":"Procedural Splines"},"content":{"rendered":"<p>For my current project I need some way to show the player which button does what. The easiest and way that doesn&#8217;t show too much or annoy the player is some wires connecting the buttons to their respective mechanisms. First I created some models, but I wanted more, so I decided to write some code to procedurally create wires between two objects.<\/p>\n<p>I divided the problem into three smaller problems:<\/p>\n<ul>\n<li>create a Master Spline between two objects that curves according to gravity (cosh(x))<\/li>\n<li>create multiple sub-Splines that curl around the Master Spline<\/li>\n<li>create the actual mesh by creating and connecting vertices around the sub-Splines<\/li>\n<\/ul>\n<p><!--more--><\/p>\n<p>&nbsp;<\/p>\n<p><strong>Master Spline:<\/strong><\/p>\n<p>For this I first had to write a cosh(x) function, because Unity doesn&#8217;t have one. That was easy thanks to Wikipedia and the almighty exponential function. Then I took the distance between the two objects and divided it into discrete steps and calculated the cosh for each of these steps. This I used to calculate positions that follow the cosh function between the two objects, no matter how I place them in XYZ space. The influence of gravity and number of steps can be easily controlled via public variables.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nusing UnityEngine;\r\nusing System.Collections;\r\n\r\n[ExecuteInEditMode]\r\npublic class Spliner : MonoBehaviour {\r\n\r\n   public GameObject next;\r\n   public float gravity;\r\n   public int steps;\r\n\r\n   private Vector3 nextPosition;\r\n   private Vector3[] pointArr;\r\n\r\n   void Update() {\r\n\r\n      if(steps &lt; 0) steps= 0;\r\n      pointArr = new Vector3[steps];\r\n\r\n      if(next) nextPosition = next.transform.position;\r\n\r\n      for(int i = 0; i &lt; steps; i++) {\r\n          pointArr[i] = Midpoint(i);\r\n      }\r\n   }\r\n\r\n   Vector3 Midpoint(int i) {\r\n      Vector3 direction = nextPosition - transform.position;\r\n\r\n      return transform.position + direction\/steps * i + new Vector3(0, gravity * ((CosH((1.0f * i \/ steps) - 0.5f) - CosH(0.5f))), 0);\r\n   }\r\n\r\n   float CosH(float t) {\r\n      return (Mathf.Exp(t) + Mathf.Exp(-t))\/2;\r\n   }\r\n\r\n   void OnDrawGizmos() {\r\n      foreach(Vector3 temp in pointArr) {\r\n         Gizmos.DrawSphere(temp, 0.1f);\r\n      }\r\n   }\r\n}\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Sub-Spline:<\/strong><br \/>\nThis was a bit more difficult. I used the points calculated for the Master Spline and calculated a cosine-sine spiral around them to make the sub-Splines curl around the Master Spline. I also added some randomness to frequency, amplitude and start-point of the sin\/cos functions for each sub-Spline.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nusing UnityEngine;\r\nusing System.Collections;\r\n\r\n[ExecuteInEditMode]\r\npublic class Spliner : MonoBehaviour {\r\n\r\n   public GameObject next;\r\n   public float gravity;\r\n   public int sides;\r\n   public int steps;\r\n\r\n   public int subSplines;\r\n   public float frequency;\r\n   public float amplitude;\r\n\r\n   private Vector3 curPosition;\r\n   private Vector3 nextPosition;\r\n   private Vector3[] mainPointArr = new Vector3[0];\r\n\r\n   private Vector3[,] subPointArr = new Vector3[0,0];\r\n\r\n   void Update() {\r\n      if(next) {\r\n         nextPosition = next.transform.position - 2.8f * next.transform.forward;    \/\/the offset here and in the next line are optional, they are important for my current project only\r\n         curPosition = transform.position - 2.8f * transform.forward;\r\n\r\n         if(sides &lt; 3) sides = 3;\r\n\r\n         if(steps &lt; 1) steps= 1;\r\n\r\n         mainPointArr = new Vector3[steps + 1];\r\n\r\n         for(int i = 0; i &lt;= steps; i++) {\r\n            mainPointArr[i] = DrawCosH(i);\r\n         }\r\n\r\n         if(subSplines &lt; 1) subSplines = 1;\r\n\r\n         subPointArr = new Vector3[subSplines, steps];\r\n\r\n         for(int i = 0; i &lt; subSplines; i++) {\r\n            DrawSubSpline(i);\r\n         }\r\n      }\r\n   }\r\n\r\n   \/\/create master spline\r\n   Vector3 DrawCosH(int i) {\r\n      Vector3 direction = nextPosition - curPosition;\r\n\r\n      return curPosition + direction\/steps * i + new Vector3(0, gravity * (CosH((1.0f * i \/ steps) - 0.5f) - CosH(0.5f)), 0) - Vector3.up;    \/\/this last Vector3.up is optional, like the offset at the top\r\n   }\r\n\r\n   \/\/calculate cosh\r\n   float CosH(float t) {\r\n      return (Mathf.Exp(t) + Mathf.Exp(-t))\/2;\r\n   }\r\n\r\n   \/\/create sub splines\r\n   void DrawSubSpline(int i) {\r\n      float locAmp = amplitude * Random.Range(0.5f, 1.2f) \/ 10;\r\n      float locFreq = frequency * Random.Range(0.8f, 1.2f);\r\n      float offset = Random.Range(0.0f, 1.0f);\r\n      int cw = (Random.Range(0.0f, 1.0f) &gt; 0.5 ? -1 : 1);\r\n\r\n      for(int j = 0; j &lt; steps; j++) {\r\n         Vector3 direction = mainPointArr[j + 1] - mainPointArr[j];\r\n         Quaternion rot = Quaternion.LookRotation(direction);\r\n\r\n         subPointArr[i, j] = mainPointArr[j] + rot * (Vector3.up * Mathf.Sin(1.0f * j * locFreq \/ steps + offset) + Vector3.right * cw * Mathf.Cos(1.0f * j * locFreq \/ steps + offset)) * locAmp;\r\n      }\r\n   }\r\n\r\n   \/\/draw Gizmos for visualization in the Editor\r\n   void OnDrawGizmos() {\r\n      if(next) {\r\n         Gizmos.color = Color.yellow;\r\n         \/\/foreach(Vector3 temp in mainPointArr) {\r\n         \/\/   Gizmos.DrawSphere(temp, 0.1f);\r\n         \/\/}\r\n\r\n         if(subSplines &gt; 0) {\r\n            Gizmos.color = Color.red;\r\n            foreach(Vector3 temp in subPointArr) {\r\n               Gizmos.DrawSphere(temp, 0.05f);\r\n            }\r\n         }\r\n      }\r\n   }\r\n}\r\n<\/pre>\n<p>Now I have to read into creating meshes in code. Hopefully I will be able to finish this soon.<\/p>\n<p>But first an image showing how the wires look like currently (for this I calculated many steps and drew a sphere gizmo for each of the points).<\/p>\n<p><a rel=\"attachment wp-att-477\" href=\"http:\/\/piflik.de\/?attachment_id=477\"><img loading=\"lazy\" class=\"aligncenter size-full wp-image-477\" title=\"BlobScreen06\" src=\"http:\/\/piflik.de\/wp-content\/uploads\/2013\/01\/BlobScreen06.jpg\" alt=\"\" width=\"1022\" height=\"700\" srcset=\"http:\/\/piflik.de\/wp-content\/uploads\/2013\/01\/BlobScreen06.jpg 1022w, http:\/\/piflik.de\/wp-content\/uploads\/2013\/01\/BlobScreen06-300x205.jpg 300w\" sizes=\"(max-width: 1022px) 100vw, 1022px\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>For my current project I need some way to show the player which button does what. The easiest and way that doesn&#8217;t show too much or annoy the player is some wires connecting the buttons to their respective mechanisms. First I created some models, but I wanted more, so I decided to write some code [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[13,12,4],"tags":[],"_links":{"self":[{"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/posts\/465"}],"collection":[{"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/piflik.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=465"}],"version-history":[{"count":15,"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/posts\/465\/revisions"}],"predecessor-version":[{"id":481,"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/posts\/465\/revisions\/481"}],"wp:attachment":[{"href":"http:\/\/piflik.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=465"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/piflik.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=465"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/piflik.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=465"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}