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. Dismiss Notice

How to change Terrain Detail Mesh Material at Runtime

Discussion in 'Scripting' started by Kivak, Aug 13, 2014.

  1. Kivak

    Kivak

    Joined:
    Jul 13, 2013
    Posts:
    140
    Hi all,

    I am looking to change the terrain of my game to correspond to the current season and weather. The example I am working with is snow...

    When it is sunny, I want the grass to use the "NormalGrassMaterial" and when it is snowing, I want my grass to use the "SnowyGrassMaterial". How would this be done?

    I looked into the terrain's detailPrototypes and changed the "prototype.renderer.material", but that only changed the source's material in my assets, not anything on the terrain itself.

    Any ideas? :)

    Thanks so much!
    -Mark
     
  2. iamthel0rax

    iamthel0rax

    Joined:
    Apr 19, 2014
    Posts:
    15
    It should basically be as simple as that.. if you have your terrain object "foo" with a current grassy texture you should be able to easily change it with something like
    Code (csharp):
    1.  
    2. Material foo = *snowy material*;
    3. bar.renderer.material = foo;
    4.  
    You might have to provide some more information on what exactly you're doing but I've certainly done that before and had it work. The only thing I can think of off hand is that perhaps you have multiple submeshes on your terrain in which case you need to be editing the Material[] materials array. If that's the case you should be reconsidering how you're assigning materials because that could get quite GPU/CPU expensive quite fast
     
  3. Kivak

    Kivak

    Joined:
    Jul 13, 2013
    Posts:
    140
    @iamthel0rax
    Thanks for responding! Here's my actual code:

    Code (csharp):
    1.  
    2. Terrain[] allTerrains = GameObject.FindObjectsOfType<Terrain>();
    3. Material snowyMaterial = Resources.Load("grass_snow_mat") as Material;
    4. DetailPrototype[] dps = ((Terrain)allTerrains[0]).terrainData.detailPrototypes;
    5. ((DetailPrototype)dps[5]).prototype.renderer.material = snowyMaterial;
    6.  
    The mesh object which corresponds to the 6th detail mesh on the terrain has its material changed to the snowy material. But the detail mesh on the terrain itself are unchanged. :(

    I actually would like the original mesh object not to be changed if possible - only the terrain mesh instances. But I could live with it if that wasn't the case. :)
     
  4. IsGreen

    IsGreen

    Joined:
    Jan 17, 2014
    Posts:
    206
    Usually, to change terrain textures, change splatprototypes, no material.

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class changeTerrainMaterial : MonoBehaviour {
    4.  
    5.     public Terrain terrain;
    6.     public Texture2D texture;
    7.  
    8.     void Start(){
    9.  
    10.         //Take terrain splats array of two elements
    11.         SplatPrototype[] splatPrototype  = terrain.terrainData.splatPrototypes;
    12.  
    13.         //Create new splat, with new texture and same tileOffset and tileSize that second splat
    14.         SplatPrototype newSplatPrototype = new SplatPrototype();
    15.         newSplatPrototype.texture = texture;
    16.         newSplatPrototype.tileOffset = splatPrototype[1].tileOffset;
    17.         newSplatPrototype.tileSize = splatPrototype[1].tileSize;
    18.         //newSplatPrototype.normalMap
    19.  
    20.         //Create new terrain splats array of two elements
    21.         SplatPrototype[] newTerrainSplats = new SplatPrototype[2];
    22.  
    23.         //Change second splat
    24.         newTerrainSplats[0]=splatPrototype[0];
    25.         newTerrainSplats[1]=newSplatPrototype;
    26.  
    27.         //Assign new terrain splats array
    28.         terrain.terrainData.splatPrototypes = newTerrainSplats;
    29.  
    30.     }
    31.  
    32. }
    _______________________________________________

    EDIT: Sorry, you refer to detail textures.

    I tested this script. To change detail textures, is necessary assign new terrainData:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class changeTerrainMaterial : MonoBehaviour {
    4.  
    5.     public Terrain terrain;
    6.     public Terrain secondTerrain;
    7.  
    8.     void Start(){
    9.  
    10.         //Don't work, assign new detailPrototype
    11.         //terrain.terrainData.detailPrototypes = secondTerrain.terrainData.detailPrototypes;
    12.  
    13.         //Do work, assign new terrainData
    14.         terrain.terrainData = secondTerrain.terrainData;
    15.  
    16.     }
    17.  
    18. }
    19.  
     
    Last edited: Aug 13, 2014
  5. Kivak

    Kivak

    Joined:
    Jul 13, 2013
    Posts:
    140

    Assigning a whole new terrainData seems a bit extreme for changing the material of a single detail mesh. Is that the only way??
     
  6. IsGreen

    IsGreen

    Joined:
    Jan 17, 2014
    Posts:
    206
    I don't know. Less is nothing. Luck.