How to change Terrain Detail Mesh Material at Runtime

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? :slight_smile:

Thanks so much!
-Mark

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

Material foo = *snowy material*;
bar.renderer.material = foo;

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

@iamthel0rax
Thanks for responding! Here’s my actual code:

Terrain[] allTerrains = GameObject.FindObjectsOfType<Terrain>();
Material snowyMaterial = Resources.Load("grass_snow_mat") as Material;
DetailPrototype[] dps = ((Terrain)allTerrains[0]).terrainData.detailPrototypes;
((DetailPrototype)dps[5]).prototype.renderer.material = snowyMaterial;

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. :frowning:

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. :slight_smile:

Usually, to change terrain textures, change splatprototypes, no material.

using UnityEngine;

public class changeTerrainMaterial : MonoBehaviour {

    public Terrain terrain;
    public Texture2D texture;

    void Start(){

        //Take terrain splats array of two elements
        SplatPrototype[] splatPrototype  = terrain.terrainData.splatPrototypes;

        //Create new splat, with new texture and same tileOffset and tileSize that second splat
        SplatPrototype newSplatPrototype = new SplatPrototype();
        newSplatPrototype.texture = texture;
        newSplatPrototype.tileOffset = splatPrototype[1].tileOffset;
        newSplatPrototype.tileSize = splatPrototype[1].tileSize;
        //newSplatPrototype.normalMap

        //Create new terrain splats array of two elements
        SplatPrototype[] newTerrainSplats = new SplatPrototype[2];

        //Change second splat
        newTerrainSplats[0]=splatPrototype[0];
        newTerrainSplats[1]=newSplatPrototype;

        //Assign new terrain splats array
        terrain.terrainData.splatPrototypes = newTerrainSplats;

    }

}

EDIT: Sorry, you refer to detail textures.

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

using UnityEngine;

public class changeTerrainMaterial : MonoBehaviour {

    public Terrain terrain;
    public Terrain secondTerrain;

    void Start(){

        //Don't work, assign new detailPrototype
        //terrain.terrainData.detailPrototypes = secondTerrain.terrainData.detailPrototypes;

        //Do work, assign new terrainData
        terrain.terrainData = secondTerrain.terrainData;

    }

}

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

I don’t know. Less is nothing. Luck.