Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Height-map on Sphere, Which method is best?

Discussion in 'Editor & General Support' started by VortexGamer, Jan 3, 2016.

  1. VortexGamer

    VortexGamer

    Joined:
    Apr 27, 2015
    Posts:
    49
    So I want to put a height map on a sphere.
    Here are some of the ways I have seen people do it.
    1: Something to do with 6-sided plane cubes and scripting to make it look like a sphere, I don't know how it works, I don't know how to apply a height map to it and I don't know how to texture it.
    2: I saw somewhere you could do it with one plane? I don't know if you can though
    3: Do it in blender. I have no idea how to use blender and following that one creating planets in blender and wilbur tutorial is outdated. I got a heightmap on the sphere but it's all distorted, Blender would be my least preferred method.
    Also a game made in unity, Kerbal Space Program does this. How does it do it there?
    Thanks for any help in advance!
     
    ThiagoCunhaTCB likes this.
  2. greg-harding

    greg-harding

    Joined:
    Apr 11, 2013
    Posts:
    519
    "Which method is best?" - any method that works for you :) Any of the solutions you've mentioned might work just fine but without knowing how you want to use it there's no choice for a best method. Is it a static model or something that needs to procedurally change or change with different textures/height maps? Do you want to paint or generate the textures/height maps externally or would using some scripted noise functions in the editor or in-game be ok? What sort of limits do you have with regards to mesh size, texture size, etc?

    If you'd prefer not to model assets externally there are lots of sites around that cover generating spheres with primitives and then texturing or applying noise to them. In our game (http://elementgame.com) we have a generator in the editor and in the game to dynamically generate small, low resolution planets offline and in realtime using a bunch of basic parameters to apply various amounts of subdivision, scale, noise, etc. to primitives like icosahedrons. Experimenting a bit with things like this should help you decide how to approach building the assets you need - externally, internally, offline, at runtime, various resolutions, using textures/height maps and/or using scripted noise functions, applying textures and/or using custom shaders to add more detail, etc.
     
  3. VortexGamer

    VortexGamer

    Joined:
    Apr 27, 2015
    Posts:
    49
    @greg harding
    I've crossed of method 3. Have no Idea.
    Looks like I'm going with either method 1 or 2.
    Although I don't understand how to do any of them...
    Can someone explain?
     
  4. VortexGamer

    VortexGamer

    Joined:
    Apr 27, 2015
    Posts:
    49
  5. dyox

    dyox

    Joined:
    Aug 19, 2011
    Posts:
    619
    You can check here :
    http://mathproofs.blogspot.fr/2005/07/mapping-cube-to-sphere.html

    You can also generate an heightmap texture with LibNoise or WorldMachine.


    Code (CSharp):
    1.  
    2.     using UnityEngine;
    3.  
    4.     public class SphereMath
    5.     {
    6.  
    7.         public static Vector3 CoordinatesToVector3(Vector2 coordinates, float radius = 1f)
    8.         {
    9.             return CoordinatesToVector3(coordinates.x, coordinates.y, radius);
    10.         }
    11.  
    12.         public static Vector3 CoordinatesToVector3(float longitude, float latitude, float radius = 1f)
    13.         {
    14.  
    15.             longitude *= Mathf.Deg2Rad;
    16.             latitude *= Mathf.Deg2Rad;
    17.  
    18.             float r_e = Mathf.Cos(latitude);
    19.             float y_e = Mathf.Sin(latitude);
    20.  
    21.             float x_s = r_e * Mathf.Sin(longitude) * -1;
    22.             float z_s = r_e * Mathf.Cos(longitude);
    23.  
    24.             return new Vector3(x_s, y_e, z_s).normalized * radius;
    25.         }
    26.  
    27.         public static Vector2 Vector3ToCoordinates(Vector3 position)
    28.         {
    29.             position = Vector3.Normalize(position);
    30.  
    31.             float x_s = position.x;
    32.             float y_e = position.y;
    33.             float z_s = position.z;
    34.  
    35.             float latitude = Mathf.Asin(y_e);
    36.             float r_e = Mathf.Cos(latitude);
    37.             float longitude = Mathf.Acos(x_s / r_e);
    38.  
    39.             Vector2 coordinates = new Vector2(longitude, latitude) * Mathf.Rad2Deg;
    40.  
    41.             if (z_s <= 0)
    42.             {
    43.                 if (x_s <= 0)
    44.                 {
    45.                     coordinates.x = 180 - (coordinates.x - 90);
    46.                 }
    47.                 else
    48.                 {
    49.                     coordinates.x = -90 - coordinates.x;
    50.                 }
    51.             }
    52.             else
    53.             {
    54.                 coordinates.x -= 90;
    55.             }
    56.  
    57.             return coordinates;
    58.         }
    59.  
    60.         public static float ArcDistance(Vector3 positionA, Vector3 positionB, float radius)
    61.         {
    62.  
    63.             if (Vector3.SqrMagnitude(positionA - positionB) == 0) return 0f;
    64.  
    65.             return (Mathf.Acos(Vector3.Dot(positionA.normalized, positionB.normalized)) * Mathf.Rad2Deg * Mathf.PI * radius) / 180f;
    66.  
    67.         }
    68.  
    69.         public static int SegmentIntersections(Vector3 start, Vector3 end, Vector3 center, float radius, out Vector3 intersection1, out Vector3 intersection2)
    70.         {
    71.  
    72.             Vector4 data = ComputeSegmentIntersection(start, end, center, radius);
    73.  
    74.             intersection1 = Vector3.zero;
    75.             intersection2 = Vector3.zero;
    76.  
    77.             if (data.w < 0)
    78.             {
    79.                 return 0;
    80.             }
    81.  
    82.             float mu;
    83.  
    84.             if (data.w == 0)
    85.             {
    86.                 mu = -data.y / (2 * data.x);
    87.                 intersection1 = start + mu * (end - start);
    88.  
    89.                 return 1;
    90.             }
    91.  
    92.             if (data.w > 0)
    93.             {
    94.  
    95.                 Vector3 pa = Vector3.zero;
    96.                 Vector3 pb = Vector3.zero;
    97.  
    98.                 mu = (-data.y + Mathf.Sqrt(Mathf.Pow(data.y, 2) - 4 * data.x * data.z)) / (2 * data.x);
    99.                 pa = start + mu * (end - start);
    100.  
    101.                 mu = (-data.y - Mathf.Sqrt(Mathf.Pow(data.y, 2) - 4 * data.x * data.z)) / (2 * data.x);
    102.                 pb = start + mu * (end - start);
    103.  
    104.                 float da = Vector3.Distance(start, pa);
    105.                 float db = Vector3.Distance(start, pb);
    106.  
    107.                 if (da < db)
    108.                 {
    109.                     intersection1 = pa;
    110.                     intersection2 = pb;
    111.                 }
    112.                 else
    113.                 {
    114.  
    115.                     intersection1 = pb;
    116.                     intersection2 = pa;
    117.                 }
    118.  
    119.                 return 2;
    120.             }
    121.  
    122.             return 0;
    123.         }
    124.  
    125.         private static Vector4 ComputeSegmentIntersection(Vector3 start, Vector3 end, Vector3 center, float radius)
    126.         {
    127.             Vector3 segment = end - start;
    128.             float a = segment.sqrMagnitude;
    129.  
    130.             Vector3 offset = start - center;
    131.             float b = 2 * (segment.x * offset.x + segment.y * offset.y + segment.z * offset.z);
    132.  
    133.             float c = Mathf.Pow(center.x, 2) + Mathf.Pow(center.y, 2) + Mathf.Pow(center.z, 2) + Mathf.Pow(start.x, 2) + Mathf.Pow(start.y, 2) + Mathf.Pow(start.z, 2) - 2 * (center.x * start.x + center.y * start.y + center.z * start.z) - Mathf.Pow(radius, 2);
    134.             float i = b * b - 4 * a * c;
    135.  
    136.             return new Vector4(a, b, c, i);
    137.         }
    138.  
    139.         // from http://mathproofs.blogspot.fr/2005/07/mapping-cube-to-sphere.html
    140.         public static Vector3 CubeToSphere(Vector3 position, float radius = 0.5f)
    141.         {
    142.             Vector3 result = Vector3.zero;
    143.  
    144.             float x2 = position.x * position.x;
    145.             float y2 = position.y * position.y;
    146.             float z2 = position.z * position.z;
    147.  
    148.             result.x = position.x * Mathf.Sqrt(1 - y2 * 0.5f - z2 * 0.5f + (y2 * z2) / 3f);
    149.             result.y = position.y * Mathf.Sqrt(1 - z2 * 0.5f - x2 * 0.5f + (z2 * x2) / 3f);
    150.             result.z = position.z * Mathf.Sqrt(1 - x2 * 0.5f - y2 * 0.5f + (x2 * y2) / 3f);
    151.  
    152.             return result * radius;
    153.         }
    154.  
    155.         // thanks to Boby, the god of Maths
    156.         public static Vector3 SphereToCube(Vector3 position, float size = 0.5f)
    157.         {
    158.             int i0, i1, i2;
    159.             position = position.normalized;
    160.  
    161.             float xs = position.x;
    162.             float ys = position.y;
    163.             float zs = position.z;
    164.             float sx = Mathf.Sign(xs);
    165.             float sy = Mathf.Sign(ys);
    166.             float sz = Mathf.Sign(zs);
    167.             float[] e = new float[3];
    168.  
    169.             xs = Mathf.Abs(xs);
    170.             ys = Mathf.Abs(ys);
    171.             zs = Mathf.Abs(zs);
    172.  
    173.             float x = xs;
    174.             float y = ys;
    175.             float z = zs;
    176.             float t;
    177.             if (y >= x && y >= z)
    178.             {
    179.                 i0 = 0; i1 = 2; i2 = 1;
    180.                 x = xs; y = zs; z = ys;
    181.  
    182.                 e[i2] = sy;
    183.                 t = sy;
    184.                 sy = sz;
    185.                 sz = t;
    186.             }
    187.             else if (z >= x)
    188.             {
    189.                 i0 = 0; i1 = 1; i2 = 2;
    190.                 x = xs; y = ys; z = zs;
    191.  
    192.                 e[i2] = sz;
    193.             }
    194.             else
    195.             {
    196.                 i0 = 2; i1 = 1; i2 = 0;
    197.                 x = zs; y = ys; z = xs;
    198.  
    199.                 e[i2] = sx;
    200.                 t = sx;
    201.                 sx = sz;
    202.                 sz = t;
    203.             }
    204.  
    205.             if (x < 0.0001f)
    206.             {
    207.                 e[i0] = 0f;
    208.                 e[i1] = sy * Mathf.Sqrt(2f - 2f * z * z);
    209.  
    210.                 position.x = e[0];
    211.                 position.y = e[1];
    212.                 position.z = e[2];
    213.  
    214.                 return position * size;
    215.  
    216.             }
    217.             else if (y < 0.0001f)
    218.             {
    219.                 e[i1] = 0f;
    220.                 e[i0] = sx * Mathf.Sqrt(2f - 2f * z * z);
    221.  
    222.                 position.x = e[0];
    223.                 position.y = e[1];
    224.                 position.z = e[2];
    225.  
    226.                 return position * size;
    227.             }
    228.  
    229.             float x2 = x * x;
    230.             float y2 = y * y;
    231.             e[i1] = Mathf.Sqrt(1.5f - x2 + y2 - Mathf.Sqrt(x2 * x2 + y2 * y2 - 3f * (x2 + y2) - 2f * x2 * y2 + 2.25f));
    232.  
    233.             e[i0] = x / Mathf.Sqrt(0.5f - e[i1] * e[i1] * 0.5f + e[i1] * e[i1] / 3f);
    234.  
    235.             e[i0] = Mathf.Abs(e[i0]) * sx;
    236.             e[i1] = Mathf.Abs(e[i1]) * sy;
    237.  
    238.             position.x = e[0];
    239.             position.y = e[1];
    240.             position.z = e[2];
    241.  
    242.             return position * size;
    243.         }
    244.  
    245.     }
    246.  

    LibNoise


    Code (CSharp):
    1.  
    2.  
    3. ///<summary>
    4. /// Returns the value of the mathematical constant PI.
    5. ///</summary>
    6. public static readonly double PI = 3.1415926535897932385;
    7.  
    8. ///<summary>
    9. /// Returns the square root of 2.
    10. ///</summary>
    11. public static readonly double Sqrt2 = 1.4142135623730950488;
    12.  
    13. ///<summary>
    14. /// Returns the square root of 3.
    15. ///</summary>
    16. public static readonly double Sqrt3 = 1.7320508075688772935;
    17.  
    18. ///<summary>
    19. /// Returns PI/180.0, used for converting degrees to radians.
    20. ///</summary>
    21. public static readonly double DEG_TO_RAD = PI / 180.0;
    22.  
    23. ///<summary>
    24. /// Returns noise mapped to the given location in the sphere.
    25. ///</summary>
    26. public double GetValue(double latitude, double longitude)
    27. {
    28. if (SourceModule == null)
    29. throw new NullReferenceException("A source module must be provided.");
    30.  
    31. double x=0, y=0, z=0;
    32. LatLonToXYZ(latitude, longitude, ref x, ref y, ref z);
    33.  
    34. return SourceModule.GetValue(x, y, z);
    35. }
    36.  
    37. protected void LatLonToXYZ(double lat, double lon, ref double x, ref double y, ref double z)
    38. {
    39. double r = System.Math.Cos (DEG_TO_RAD * lat);
    40. x = r * System.Math.Cos(DEG_TO_RAD * lon);
    41. y = System.Math.Sin(DEG_TO_RAD * lat);
    42. z = r * System.Math.Sin(DEG_TO_RAD * lon);
    43. }
    44.  
     
  6. VortexGamer

    VortexGamer

    Joined:
    Apr 27, 2015
    Posts:
    49
    Sorry, I don't understand this that much, (I'm in 7'nth grade)
    What do I do with this and once I generated my heightmap how do I place it on the planet??
     
  7. VortexGamer

    VortexGamer

    Joined:
    Apr 27, 2015
    Posts:
    49
  8. dyox

    dyox

    Joined:
    Aug 19, 2011
    Posts:
    619
    Post your heightmap texture, i will create an example script for you.
    If you plan to create a planet, you will need more advanced systems like LOD and Multi-threading.
     
  9. VortexGamer

    VortexGamer

    Joined:
    Apr 27, 2015
    Posts:
    49
    @dyox
    Here,

    Thanks for the examples...
    How do I add LOD to this???
    Do I add more verts near the character and less away?

    EDIT:
    I know it isn't a heightmap that aligns but I can change it if you can give me the base examples
     
  10. VortexGamer

    VortexGamer

    Joined:
    Apr 27, 2015
    Posts:
    49
    @dyox
    Are you still there?
     
  11. VortexGamer

    VortexGamer

    Joined:
    Apr 27, 2015
    Posts:
    49
  12. dyox

    dyox

    Joined:
    Aug 19, 2011
    Posts:
    619
    Yes, no time for the moment, i will upload something asap.
    But it's very simple, take a cube, size 1,1,1. Create each face (Vertices/Indices), and move them around origin (0,0,0) using formula on SphereMath i posted above. (Move each vertex on array)
     
  13. VortexGamer

    VortexGamer

    Joined:
    Apr 27, 2015
    Posts:
    49
    @dyox
    Can you show your example?
     
  14. VortexGamer

    VortexGamer

    Joined:
    Apr 27, 2015
    Posts:
    49
    @dyox
    You still there?
     
  15. dyox

    dyox

    Joined:
    Aug 19, 2011
    Posts:
    619
    It's the max i can do for you :
    -Dx11 shader with heightmap. (you can move vertices directly inside code if you want, but it's useless at this scale without a correct LOD system)
    I can not help you to create a planet system like kerbal. Here it's just a simple sphere generator.
    Link : https://www.dropbox.com/s/3pjp9v3e409b978/PlanetExample.rar?dl=0
    Unity 2016-01-13 05-35-23-40.jpg Unity 2016-01-13 05-34-52-35.jpg Unity 2016-01-13 05-40-20-89.jpg Unity 2016-01-13 05-37-44-50.jpg
    Unity 2016-01-13 05-49-40-12.jpg
     
    Last edited: Jan 13, 2016
  16. VortexGamer

    VortexGamer

    Joined:
    Apr 27, 2015
    Posts:
    49
    wow thank you @dyox
    So this only works with dx11?
    nice
     
  17. JetMorris

    JetMorris

    Joined:
    Apr 2, 2018
    Posts:
    1
    @dyox I know this is old, but do you still have this? I would love to have a play around with it.
     
    twicejiggled likes this.
  18. MaTaXeToS

    MaTaXeToS

    Joined:
    Apr 9, 2014
    Posts:
    2
    @dyox Could you share the rar file again?

    I'm having some trouble going from a 256x256 heightmap to a cube sphere
    Especially with the upper and lower faces

    Thanks!
     

    Attached Files: