Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Vosheck · Jun 07, 2020 at 10:07 AM · mapmapsmesh manipulationmap-generationspherical

How to curve country meshes based upon a flat projection, into a sphere?

I'm generating country meshes for my grand strategy game by pinging preset positions on a political map image, flood-filling the extents of a country on the political map, and then generating a mesh representation that additionally reflects terrain by getting the greyscale of a black-white heightmap image that has the same proportions and positions like the political map image.

I would like to curve the generated spheres so that all of them form a sphere, in the shape of Earth. I'm sure there is a mathematical formula for what I'm trying to achieve, I'm just so bad at math that I don't even know where to start looking.

The relevant code is:

 GameObject seperateLandmass = new GameObject("Landmass" + s);
 seperateLandmass.transform.parent = container.transform;
 List<GameObject> subMeshes = new List<GameObject>();
 seperateLandmass.transform.position = new Vector3(startingCoordinates[s].Item1,0,                    startingCoordinates[s].Item2);
 List<int[]> delimitedCoordinates = seperateCoordinates.Select((x, i) => new { Index = i, Value = x }).GroupBy(x => x.Index / 16383).Select(x => x.Select(v => v.Value).ToArray()).ToList();

   for (int i = 0; i < delimitedCoordinates.Count; i++){
     vertexIndex = 0;
     triangleIndex = 0;
     Vector3[] verts = new Vector3[delimitedCoordinates[i].Length * 4];
     int[] tris = new int[delimitedCoordinates[i].Length * 6];
     for (int j = 0; j < delimitedCoordinates[i].Length; j++){
           int x = delimitedCoordinates[i][j] % width;
           int y = delimitedCoordinates[i][j] / width;
           verts[vertexIndex] = new Vector3(x, heightmap.GetPixel(x, y).grayscale * heightmapMultiplier, y);
           verts[vertexIndex+1] = new Vector3(x+1, heightmap.GetPixel(x+1, y).grayscale *heightmapMultiplier,y);
           verts[vertexIndex + 2] = new Vector3(x, heightmap.GetPixel(x, y + 1).grayscale * heightmapMultiplier, y + 1);
           verts[vertexIndex + 3] = new Vector3(x + 1, heightmap.GetPixel(x + 1, y + 1).grayscale * heightmapMultiplier, y + 1);
           tris[triangleIndex] = vertexIndex;
           tris[triangleIndex + 1] = vertexIndex + 2;
           tris[triangleIndex + 2] = vertexIndex + 1;
           tris[triangleIndex + 3] = vertexIndex + 3;
           tris[triangleIndex + 4] = vertexIndex + 1;
           tris[triangleIndex + 5] = vertexIndex + 2;
 
           vertexIndex += 4;
           triangleIndex += 6;
       }
    Vector2[] uvs = new Vector2[verts.Length];
    for (var k = 0; k < uvs.Length; k++) //Give UV coords X,Z world coords
           uvs[k] = new Vector2(verts[k].x, verts[k].z);
 
     subMeshes.Add(new GameObject(i.ToString()));
     subMeshes[subMeshes.Count - 1].AddComponent<MeshFilter>();
     MeshRenderer mr = subMeshes[subMeshes.Count - 1].AddComponent<MeshRenderer>();
     Mesh procMesh = new Mesh();
     procMesh.vertices = verts.ToArray(); //Assign verts, uvs, and tris to the mesh
     procMesh.uv = uvs;
     procMesh.triangles = tris.ToArray();
     procMesh.RecalculateNormals(); //Determines which way the triangles are facing

The result looks like: alt text alt text

12.png (358.2 kB)
13.png (366.4 kB)
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by Vosheck · Jul 07, 2020 at 01:43 PM

The x and y were the pixel coordinates in the equirectangular projection of the world map, so I converted them to longitude and latitude through:

 float longitude=2f * Mathf.PI * (float)x / (float)mapWidth - Mathf.PI;
 float latitude=return Mathf.PI * ((float)pixelY / (float)mapSize);

Then, the following formula gave me the x,y,z coordinates of vertices arranged in a sphere:

 float sinLatitudeRadius = finalRadius * Mathf.Sin(latitude);
 new Vector3(sinLatitudeRadius * Mathf.Cos(longitude), finalRadius * Mathf.Cos(latitude), sinLatitudeRadius * Mathf.Sin(longitude));

Additionally, to distort the mesh according to a heightmap, simply multiply the alpha of the heightmap with the final radius in the previous formula.

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image BastianUrbach · Jul 07, 2020 at 02:24 PM 0
Share

I hope you realize that that is almost exactly what I wrote. The first two lines are what my Remap function is for and the rest uses the formulas I gave you, just with Sine and Cosine swapped, which is why you had to change the input ranges slightly. The changes you made are mathematically meaningless, both versions essentially do the same thing.

avatar image Vosheck BastianUrbach · Jul 07, 2020 at 02:41 PM 0
Share

Umm, the latitude turned out to need to be in the range of 0 - Pi, ins$$anonymous$$d of -Pi/2 to Pi/2. Sure, mathematically it is the same range, but functionally they are different values.

Both of the Sine and Cosine formulas result in a sphere being formed, but with a different orientation.

And there was no mention of relief distortion through a radius multiplier.

Thank you for your help. Your answer led me to the path of solving my issue. But, I just felt like a more concise answer that solved my particular problem would be useful here. Ultimately, people are free to read both answers.

avatar image
1

Answer by BastianUrbach · Jun 07, 2020 at 11:19 AM

To convert latitude and longitude (which is what you currently seem to use as z and x coordinates) to a point on the unit sphere, you can use these formulas:

x = cos(latitude) * cos(longitude)
y = sin(latitude)
z = cos(latitude) * sin(longitude)

For this to work, latitude has to be in the range -Pi/2 to Pi/2 and longitude has to be in the range -Pi to Pi.
(That is -90° to 90° and -180° to 180°, converted to radians)

Sine, Cosine and Pi are available in Unity as Mathf.Sin(x), Mathf.Cos(x) and Mathf.PI.

You can remap your coordinates to the ranges given above using Lerp and InverseLerp (or you can do it by hand but this is easier in my opinion):
newValue = Mathf.Lerp(newMin, newMax, Mathf.InverseLerp(oldMin, oldMax, oldValue));
Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Vosheck · Jun 08, 2020 at 06:12 PM 0
Share

Doesn't quite work. I've seen other videos and answers of the need to remap the coordinates to longitude and latitude, and I've done that successfully.

I don't think that your formula for the sphere's coordinates works, because it makes very distorted meshes. I've implemented the formula from wiki:

 x = sin(latitude) * cos(longitude)
 y = cos(latitude)
 z = sin(latitude) * sin(longitude)

and while it does draw a country's mesh well, it doesn't curve it along a sphere at all, it just angles it differently than it previously was.

avatar image BastianUrbach Vosheck · Jun 08, 2020 at 07:51 PM 1
Share

No the formulas definitely work. Here is a simple usage example, put that script on Unity's default plane object, hit Play and you'll get a sphere as expected:

 using UnityEngine;
 using static UnityEngine.$$anonymous$$athf;
 
 public class $$anonymous$$akeSpherical : $$anonymous$$onoBehaviour {
     float Remap(float value, float old$$anonymous$$in, float old$$anonymous$$ax, float new$$anonymous$$in, float new$$anonymous$$ax) {
         return Lerp(new$$anonymous$$in, new$$anonymous$$ax, InverseLerp(old$$anonymous$$in, old$$anonymous$$ax, value));
     }
 
     void Start() {
         var mesh = GetComponent<$$anonymous$$eshFilter>().mesh;
         var vertices = mesh.vertices;
 
         var old$$anonymous$$in = mesh.bounds.$$anonymous$$;
         var old$$anonymous$$ax = mesh.bounds.max;
 
         for (var i = 0; i < vertices.Length; i++) {
             var v = vertices[i];
 
             var lon = Remap(v.x, old$$anonymous$$in.x, old$$anonymous$$ax.x, PI, -PI);
             var lat = Remap(v.y, old$$anonymous$$in.y, old$$anonymous$$ax.y, -PI / 2, PI / 2);
 
             vertices[i] = new Vector3(Cos(lon) * Cos(lat), Sin(lat), Sin(lon) * Cos(lat));
         }
 
         mesh.vertices = vertices;
         mesh.RecalculateBounds();
         mesh.RecalculateNormals();
 
         GetComponent<$$anonymous$$eshFilter>().mesh = mesh;
     }
 }
avatar image Vosheck · Jun 09, 2020 at 04:05 PM 0
Share

I tried your script with a primitive cube and I don't see a way how the -1 and 1 variance of the y is supposed to draw a sphere.

alt text

untitled.png (36.4 kB)
avatar image BastianUrbach Vosheck · Jun 09, 2020 at 04:23 PM 0
Share

Those are the correct values, it's just that a standard cube mesh is exceptionally badly suited for this. First of all, you can't build anything remotely spherical from the 12 triangles of a standard cube mesh. Second, half of the vertices of a cube are at $$anonymous$$ z, which is mapped to the south pole (0, -1, 0) and the other half is at max z, which is mapped to the north pole (0, +1, 0). Think of a world map and how the entire top edge of the map "shrinks" into the north pole when you map it to a globe. That's exactly what's happening here. Try it with a subdivided cube with a lot more vertices and you'll get something that looks a lot more spherical. That being said, the script doesn't do magic, it expects the mesh to be somewhat reasonable for the given task. Perhaps I misunderstood you but the way I understood it is that you have a fairly high resolution mesh of the world that's flat in the XZ-Plane and should be mapped to a sphere ins$$anonymous$$d. That is what the script does (it's just an example for how to use the formulas though, you might have to adapt it a little to your specific usecase).

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

128 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How do I make an interactive map on Unity? 0 Answers

What is the best way I could recolor all the pixels of a certain country on a texture of a political map(for achieving a map mode system such as in a grand strategy game)? 2 Answers

Assigning UV Map to model at runtime 0 Answers

Quality Reduction only reduces my player sprite quality 0 Answers

What is Mip Maps (Pictures) 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges