• 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
1
Question by Komak57 · Jan 01, 2015 at 12:04 AM · terrainproceduralplanet

QuadPlane to Sphere Terrain Generator Misaligned

Some time ago, I began looking into terrain generation alternatives. I wanted a game world in which upwards of thousands of players could play on one planet (for now, we'll ignore the hardware requirements, as there's numerous solutions for). My research showed that the normal Unity terrain generators wouldn't suffice. They have very limited functionality when it comes to edges. You could teleport the player, provide RollingGrid tiling methods, etc. None of these felt appropriate. Then I came across some weblinks defining a method called ClipMapping (alternatively, MipMapping), which was a GPU rendering of terrain based on a height map and clipped for various definition, mixed with some procedurally generated algorithms to produce more detailed terrain. This was impressive because it used a shader to focus all of the rendering on the GPU side.

That aside, I've recently come upon some documentation that depicts methods to procedurally generate through C# (CPU based) that helps me step into the process with a little more ease. The process very generically described building a plane mesh based on Perlin noise, and further along, Gaussian. By using various algorithms, you can generate hills, mountains, valleys, and just about anything else you could want, that would generate in as much detail as you wanted. Because this process was SO general, I had to research quite a few sites before I got a working model.

Now, to solve the previous edge-travel scenarios, I found some formulas and algorithms that allow you to take a plane mesh (or in our case, a generated terrain mesh) and warp it via a normalized radial expansion, and create 6 of these to generate a sphere.

[tldr;] This is where things get tricky. I have my planet, and the 6 sides, but they aren't lining up very smoothly. Definitely not close enough to write a sewing algorithm to fit them together without some rough stretching. I need some help looking through the code for errors, and solutions to said errors to help generate a quad-plane sphere, with the future ability to subdivide, each producing better detail (the local variable for detail is Samples).

bad alignment

 using UnityEngine;
 using System.Collections;
 using System.Collections.Generic;
 
 [ExecuteInEditMode()]
 [RequireComponent(typeof(MeshFilter))]
 [RequireComponent(typeof(MeshRenderer))]
 public class LiveMeshGen : MonoBehaviour {
     public Texture2D heightmap = null;
     public float Width {
         get { return transform.localScale.x; }
     }
     [Range(0,254)]
     public int Samples = 100;
     public float DistMod = 9.9f;
     public float Radius = 100f;
     public bool NeedsUpdate = false;
     public bool Generate = false;
     public bool Spherify = false;
     
     public Material mat;
     private MeshRenderer mr;
     private MeshFilter mf;
     private MeshCollider mc;
     
     void Start () {
     }
     void Update() {
         if (mf == null)
             mf = GetComponent<MeshFilter> ();
         if (mr == null)
             mr = GetComponent<MeshRenderer> ();
 
         if (NeedsUpdate) {
             if (Generate) {
                 heightmap = new Texture2D (Samples, Samples);
             }
             GenerateMesh();
             
             mat.mainTexture = heightmap;
             mr.material = mat;
             NeedsUpdate = false;
         }
     }
     
     void GenerateMesh ()
     {
         //float start_time = Time.time;
         System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch ();
         sw.Start ();
         
         float perSample = (float) 1 / (Samples-1);
         Vector3[] verts = new Vector3[Samples*Samples];
         List<int> tris = new List<int>();
         //int[] tris = new int[verts.Length * 3];
         Vector2[] uvs = new Vector2[Samples*Samples];
         
         for (int i = 0, p = 0; i < Samples; i++) {  
             for (int j = 0; j < Samples; j++) {
                 // Current vertex
                 var center = new Vector3(i * perSample, 0, j * perSample);
                 // Height of this vertex (from heightmap)
                 float h = GetHeight(center.x, center.z);
                 center.y = h+(DistMod);
                 // offset to center
                 center = center-new Vector3(1f/2,0,1f/2);
 
                 verts[p] = center; // translate position
                 
                 // UV coords in [0,1] space
                 uvs[p++] = new Vector2(i/(Samples - 1f),
                                        j/(Samples - 1f));
                 // not right, or bottom border
                 if (j+1 < Samples && i+1 < Samples) {
                     tris.Add((j)*Samples+(i)); // triangulate this vertex
                     tris.Add((j)*Samples+(i+1)); // triangulate right vertex
                     tris.Add((j+1)*Samples+(i)); // triangulate bottom vertex
                 }
                 // not left, or bottom border
                 if (j+1 < Samples && i-1 >= 0) {
                     tris.Add((j)*Samples+(i)); // triangulate this vertex
                     tris.Add((j+1)*Samples+(i)); // triangulate bottom vertex
                     tris.Add((j+1)*Samples+(i-1)); // triangulate bottom-left vertex
                 }
             }
         }
         // Generate the mesh object.
         Mesh ret = new Mesh();
         if (Spherify) {
             for (int i = 0; i < verts.Length; i++)
                 verts[i] = verts[i].normalized * Radius;
         }
         ret.vertices = verts;
         ret.triangles = tris.ToArray();
         ret.uv = uvs;//.ToArray();
         
         // Assign the mesh object and update it.
         ret.RecalculateBounds();
         ret.RecalculateNormals();
         mf.mesh = ret;
         
         sw.Stop ();
         Debug.Log("ProceduralTerrain was generated in " + sw.ElapsedMilliseconds + "ms.");
     }
     public float GetHeight(float x, float z) {
         return 0; // flat plane for debugging
         //if (Generate)
             //return Mathf.PerlinNoise (x, z);
         //return heightmap.GetPixel (Mathf.RoundToInt((float)x/Width*heightmap.width), Mathf.RoundToInt((float)z/Width*heightmap.height)).r/256f;
     }
 }
 

Recap: In order to get the planes close to the proper spacing, I had to add a custom variable "DistMod" that is multiplied on the vertex height which changes it from a very malformed beanie cap, to a quad-sphere shape. None of the research pages I searched through showed much of any of this, so I'm sure theres something I'm missing. Also, as I wanted to make quick tweaks without compiling over and over, I ran this script in execution mode. I created a boolean NeedsUpdate to force a re-generation only when I wanted it. I'm sure there's other ways, but it worked.

[**EDIT**]: Redacted some work to work on the plane itself to ensure it was centered properly, and scaled properly. With redundant code removed, and everything working properly, I need to know the height-offset required to generate 1/6th of a sphere when the normalized vertex is multiplied by the radius.

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

1 Reply

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

Answer by Komak57 · Jan 01, 2015 at 04:53 PM

Answer: The initial offset was generated because the terrain had not been centered properly (every vertex must be offset). The next issue was the scaling. EDGE was a variable for Samples per Unity, but in order for Unity's localScale to matter, you have to adjust everything based on 1 unity width. Finally, to offset for 1/6th of a sphere, you need to push every vertex vertically (meaning height) by half of your unscaled height (0.5f).

Notes: A mesh can only be 4-254 vertecies squared because there is a limit of 65,000 vertecies in a mesh. I'll be writing a script to generate the sphere as one, and generate all the meshes so that I can subdivide when necessary.

Comment
Add comment · 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

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.

Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.



Follow this Question

Answers Answers and Comments

25 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

Related Questions

Is terrain generation on GPU possible/supported? 1 Answer

Simple LOD not working correctly. 0 Answers

Planet made out of terrains 3 Answers

Procedural Terrain Generation on a Map the Scale of the Milky Way 2 Answers

How to create a terrain in a sphere with Perlin Noise 0 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