Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Spherical Heightmap

Discussion in 'Scripting' started by Sidus, Jun 16, 2011.

  1. Sidus

    Sidus

    Joined:
    Jun 16, 2011
    Posts:
    3
    Greetings everyone,
    I've been looking for spherical terrains, spherical heightmap and procedural planets.
    All what i've got are just suggests on how to, without many examples or code easy to understand
    (hell yes, i'm new in Unity). I combined two scripts i got on this website, my goal would be:

    1) Generate a simple heightmap on a plane.
    2) Morph it into a sphere.

    The crappy code is here, if some guru can help would be very appreciated. Thanks.

    Code (csharp):
    1.  
    2. // This script is placed in public domain. The author takes no responsibility for any possible harm.
    3.  
    4. var heightMap : Texture2D;
    5. var material : Material;
    6. var size = Vector3(200, 30, 200);
    7. var collision : boolean;
    8.  
    9. var radius: float;
    10. var numSegments: int;
    11. var numStrips: int;
    12.  
    13. function Start ()
    14. {  
    15.     GenerateHeightmap(radius, numSegments, numStrips);
    16. }
    17.  
    18. function GenerateHeightmap (radius: float, numSegments: int, numStrips: int)
    19. {
    20.     // Create the game object containing the renderer
    21.     gameObject.AddComponent(MeshFilter);
    22.     gameObject.AddComponent("MeshRenderer");
    23.     if (material)
    24.         renderer.material = material;
    25.     else
    26.         renderer.material.color = Color.white;
    27.  
    28.     // Retrieve a mesh instance
    29.     var mesh : Mesh = GetComponent(MeshFilter).mesh;
    30.    
    31.     //  The number of rings of vertices is one greater then the number of
    32.     //  horizontal strips and each ring has two vertices at the seam.
    33.     var numYLevels = numStrips + 1;
    34.     var numRingSteps = numSegments + 1;
    35.  
    36.     var width : int = Mathf.Min(heightMap.width, 255);
    37.     var height : int = Mathf.Min(heightMap.height, 255);
    38.     var y = 0;
    39.     var x = 0;
    40.  
    41.     // Build vertices and UVs
    42.     var vertices = new Vector3[height * width];
    43.     var uv = new Vector2[height * width];
    44.     var tangents = new Vector4[height * width];
    45.    
    46.     var uvScale = Vector2 (1.0 / (width - 1), 1.0 / (height - 1));
    47.     var sizeScale = Vector3 (size.x / (width - 1), size.y, size.z / (height - 1));
    48.    
    49.     for (y=0;y<height;y++)
    50.     {
    51.         for (x=0;x<width;x++)
    52.         {
    53.             var pixelHeight = heightMap.GetPixel(x, y).grayscale;
    54.             var vertex = Vector3 (x, pixelHeight, y);
    55.             vertices[y*width + x] = Vector3.Scale(sizeScale, vertex);
    56.             uv[y*width + x] = Vector2.Scale(Vector2 (x, y), uvScale);
    57.  
    58.             // Calculate tangent vector: a vector that goes from previous vertex
    59.             // to next along X direction. We need tangents if we intend to
    60.             // use bumpmap shaders on the mesh.
    61.             var vertexL = Vector3( x-1, heightMap.GetPixel(x-1, y).grayscale, y );
    62.             var vertexR = Vector3( x+1, heightMap.GetPixel(x+1, y).grayscale, y );
    63.             var tan = Vector3.Scale( sizeScale, vertexR - vertexL ).normalized;
    64.             tangents[y*width + x] = Vector4( tan.x, tan.y, tan.z, -1.0 );
    65.         }
    66.     }
    67.    
    68.     // Assign them to the mesh
    69.     mesh.vertices = vertices;
    70.     mesh.uv = uv;
    71.  
    72. // --------------------------------------------------------------------------------------------------------------  
    73. //  Store the normalised X and Z values of a ring for repeated usage (this
    74. //  saves a few Cos and Sin calls overall).
    75.     var ring = new Vector3[numRingSteps];
    76.    
    77.     var fracCircle: float;
    78.    
    79.     for (i = 0; i <= numSegments; i++) {
    80.         fracCircle = (i * 1.0) / (numSegments * 1.0);
    81.         var angle = fracCircle * 2.0 * Mathf.PI;
    82.         ring[i].x = Mathf.Sin(angle);
    83.         ring[i].z = Mathf.Cos(angle);
    84.     }
    85.  
    86.  
    87. //  Calculate the vertex positions from the parameter values. The vertex position
    88. //  is the same as the normal vector multiplied by the radius and the UV is easily
    89. //  obtained from the parameter values.
    90.  
    91.     for (l = 0; l <= numStrips; l++) {
    92.         var fracArc = (l * 1.0) / (numStrips * 1.0);
    93.         var yCoord = Mathf.Cos(fracArc * Mathf.PI);
    94.         var radFrac = Mathf.Sin(fracArc * Mathf.PI);
    95.        
    96.         for (s = 0; s <= numSegments; s++) {
    97.             fracCircle = (s * 1.0) / (numSegments * 1.0);
    98.             var normVert = ring[s] * radFrac;
    99.             normVert.y = yCoord;
    100.             vertices[l * numRingSteps + s] = normVert * radius;
    101.         }
    102.     }
    103.     // --------------------------------------------------------------------------------------------------------------
    104.  
    105.     // Build triangle indices: 3 indices into vertex array for each triangle
    106.     var triangles = new int[(height - 1) * (width - 1) * 6];
    107.     var index = 0;
    108.     for (y=0;y<height-1;y++)
    109.     {
    110.         for (x=0;x<width-1;x++)
    111.         {
    112.             // For each grid cell output two triangles
    113.             triangles[index++] = (y     * width) + x;
    114.             triangles[index++] = ((y+1) * width) + x;
    115.             triangles[index++] = (y     * width) + x + 1;
    116.  
    117.             triangles[index++] = ((y+1) * width) + x;
    118.             triangles[index++] = ((y+1) * width) + x + 1;
    119.             triangles[index++] = (y     * width) + x + 1;
    120.         }
    121.     }
    122.    
    123.     // And assign them to the mesh
    124.     mesh.triangles = triangles;
    125.        
    126.     // Auto-calculate vertex normals from the mesh
    127.     mesh.RecalculateNormals();
    128.    
    129.     // Assign tangents after recalculating normals
    130.     mesh.tangents = tangents;
    131.    
    132.     mesh.vertices = vertices;
    133.    
    134.     // Assign collision
    135.     if (collision == true) {
    136.     GetComponent(MeshCollider).sharedMesh = mesh;
    137.     }
    138. }
    139.  
     
  2. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    I think a better thing to do would be to make 6 heightmaps, and make a cubesphere out of them. I doubt you can get a heightmap to map usefully to a sphere (without distortion).

    --Eric
     
  3. Sidus

    Sidus

    Joined:
    Jun 16, 2011
    Posts:
    3
    Thank you for the answer.
    Do you know where i can find some examples about this method? I mean a package or a tutorial. As i said I'm really new in Unity.
     
    Last edited: Jun 16, 2011
  4. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    the distortions/anomalies at the poles of a lat/long sphere are not that disturbing.

    search the forums. andeeee has posted a script for a parametrical sphere as the unity built in sphere has some serious uv issues at the poles.

    then you must create some noise for surface details and put it in a texture which is mapped on the sphere.

    perlin noise is widely used but i suggest simplex noise. always head for 3d noise because your sphere is a 3d body and with 2d noise you get into problems with tiling. with 3d noise simply take the positions of the pixels on the sphere to calculate the noise there and when you always pick the octaves of noise from a sphere with different radius for different frequenzies/wavelength you have no problem with tiling.

    i'm currently working at a procedural planet generator which i will sell at the assetstore in some months when things go well.
     
  5. Sidus

    Sidus

    Joined:
    Jun 16, 2011
    Posts:
    3
    If you saw my script, Paramsphere.js by Andeeee was already "implemented". Paramsphere.js and HeightmapGenerator.js from Procedural Examples was the two examples i used. Now, as i said two times, i'm a newbie regard procedurals so any method NOT documented by some examples or anything related to it isn't an help for me at all. Maybe do you have a starting example (code or package) on how would be possible spherify a simple heightmap keeping its relief around the sphere?

    Note: Till now i used 3ds Max in order to load my heightmaps directly via displace modifier, so to automatically generate an heightfield around a sphere. I think it is a good method but it loose details because vertices optimizations, so i thought could be better generate it procedurally.

    PS. If you didn't understand what i said, is my fault, English isn't my main language, sorry.
     
  6. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    i have noticed it afterwards.

    some weeks ago i had also been a newbie in this field. only if you work with the stuff you may get above newbie level. if you just pick a ready implementation you probably wont. there are also enough examples and tutorials outside which are not unity specific but the principle is the same. a bit thinking is still required though.

    i just have code which depends on many stuff and as i said i want to sell it. publishing it for free would be something between unwise and stupid.

    same applies for me.

    sorry when i can't be of more help but this is a complicated and wide field. so you probably wont find a ready made solution which fits all your needs. i also started from scratch and in 1 or 2 weeks you could have something ready.
    if you have detailed questions there are many people to help you. but its always a bit probelamtic to request other people doing the work for you (which includes internet search for sources/tutorials etc.).

    for your two goals/questions from the first post i had give you some hints and advises in my previous post. what you make out of it is up to you.
     
  7. L-Tyrosine

    L-Tyrosine

    Joined:
    Apr 27, 2011
    Posts:
    305
    You could also start with a geodesic sphere (mesh or built in run time) and then move each vertex along its original normal by some noise (perlin works great here).