Search Unity

Question SetHeights dosen't apply array to terrain heights

Discussion in 'Scripting' started by AndreasHHH, Feb 12, 2021.

  1. AndreasHHH

    AndreasHHH

    Joined:
    Dec 10, 2016
    Posts:
    4
    Hello, I'm trying to apply a set of heights calculated using a function to my terrain. Here is my code:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class terrainGenerator : MonoBehaviour
    6. {
    7.     public int depth = 2;
    8.  
    9.     public int height = 256;
    10.     public int width = 256;
    11.  
    12.     public float scale = 20f;
    13.  
    14.     public float test = 100f;
    15.  
    16.     void Update() {
    17.         Terrain terrain = GetComponent<Terrain>();
    18.         terrain.terrainData = GenerateTerrain(terrain.terrainData);
    19.     }
    20.  
    21.     TerrainData GenerateTerrain(TerrainData terrainData) {
    22.         terrainData.heightmapResolution = width + 1;
    23.         terrainData.size = new Vector3(width, depth, height);
    24.         terrainData.SetHeights(0, 0, GenerateHeigths());
    25.         if(Input.GetKey("t")) {
    26.             print(terrainData.GetHeight(0,0));
    27.             //print(GenerateHeigths()[0,0]);
    28.             //print(GenerateHeigths().Rank);
    29.         }
    30.         return terrainData;
    31.     }
    32.  
    33.     float[,] GenerateHeigths() {
    34.         float[,] heights = new float[width, height];
    35.  
    36.         for(int x = 0; x < width; x++) {
    37.             for(int y = 0; y < height; y++) {
    38.                 heights[x,y] = CalculateHeights(x, y);
    39.             }
    40.         }
    41.  
    42.         //  if(Input.GetKey("t")) {
    43.         //      print(CalculateHeights(254, 254));
    44.         //  }
    45.         return heights;
    46.     }
    47.  
    48.     float CalculateHeights(int x, int y) {
    49.         float returnValue = 32;
    50.  
    51.         float xCoord = (float)x / width * scale;
    52.         float yCoord = (float)y / height * scale;
    53.  
    54.         float fx = (float)x;
    55.         float fy = (float)y;
    56.  
    57.         //returnValue += Mathf.PerlinNoise(xCoord, yCoord) / 8;
    58.         //returnValue += Mathf.PerlinNoise(xCoord, yCoord);
    59.         //returnValue += Mathf.PerlinNoise(xCoord / 32, yCoord / 32) * 2;
    60.         //returnValue += (float)(Mathf.Pow(xCoord - scale/2, 4) / 6561 - Mathf.Pow(xCoord - scale/2, 2) / 9 + Mathf.Pow(yCoord - scale/2, 4) / 6561 - Mathf.Pow(yCoord - scale/2, 2) / 9) / test;
    61.         returnValue += (Mathf.Pow(fx - (float)width/2f, 4f) / 280000f - Mathf.Pow(fx - (float)width/2f, 2f) / 9f + Mathf.Pow(fy - (float)height/2f, 4f) / 280000f - Mathf.Pow(fy - (float)height/2f, 2f) / 9f) / test;
    62.  
    63.         if(Input.GetKey("r")) {
    64.             print((y - height/2).ToString() + ", " + (x - width/2).ToString() + ", " + returnValue.ToString());
    65.         }
    66.  
    67.         return returnValue;
    68.     }
    69. }
    70.  
    The values are correct until the point where I actually run the SetHeights command, as in I can print out the values of of the "heights" array, and they look correct. But after running SetHeights, the terrain is totally flat, being the same height as the depth variable. What am I doing wrong?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,697
    Are your height values in the array all between 0 and 1? They are automatically clamped to that range if they go outside it. I don't know what values might come out of line 61 above.
     
    AndreasHHH likes this.
  3. ensiferum888

    ensiferum888

    Joined:
    May 11, 2013
    Posts:
    317
    Kurt is right here, check to see that your heights are between 0 and 1. They will be used to interpolate between 0 and whatever your terrain height value is set to in the inspector.

    For example if you set your terrain height to be 100 a value of 0.5 in the heightmap will give 50 on the actual terrain.
     
    AndreasHHH likes this.
  4. seejayjames

    seejayjames

    Joined:
    Jan 28, 2013
    Posts:
    691
    A couple things:

    --Cache your terrain by getting the component in Start, so it's only done once. Never do this in Update, it's unnecessary. Also you're declaring a new Terrain every frame...this is unnecessary and very wasteful, as terrains are typically large chunks of data. Just use one and change the heightmap, which essentially makes a "fresh" one. Only if you need an additional terrain should you declare a new one.

    Code (CSharp):
    1. Terrain terrain;
    2.  
    3. void Start() {
    4.      terrain = GetComponent<Terrain>();
    5. }
    6.  
    --Try returning a random value between 0 and 1 for all your heights (instead of your function) and see if the terrain updates properly:

    Code (CSharp):
    1. float CalculateHeights(int x, int y) {
    2.      return(Random.Range(0f,1f));
    3. }
    4.  
    --Curious to see how well it keeps up when generating complex terrains every frame. You might need to dial it back so it's every N frames, but give it a go. Also if you prefer to have your functions spit out values in a bigger range than (0, 1), just scale them to (0, 1) before setting the heights.

    Looks like some cool ideas brewing there...I've been working through a udemy course on procedural terrains and it's amazing what you can do with some noise and trig functions!
     
  5. AndreasHHH

    AndreasHHH

    Joined:
    Dec 10, 2016
    Posts:
    4
    Wow, thank you guys so much, I really don't know how I missed that it had to be between 0 and 1 :)
     
  6. AndreasHHH

    AndreasHHH

    Joined:
    Dec 10, 2016
    Posts:
    4
    Yep, I know, only doing it while I'm testing the shape of the terrain
     
    seejayjames likes this.
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,697