Last active
January 4, 2024 17:57
-
-
Save zsoi/c965ff38938cd126f00d to your computer and use it in GitHub Desktop.
Helper to deep-copy a TerrainData object in Unity3D
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using UnityEngine; | |
namespace ZS.Tools | |
{ | |
/// <summary> | |
/// Provides means to deep-copy a TerrainData object because Unitys' built-in "Instantiate" method | |
/// will miss some things and the resulting copy still shares data with the original. | |
/// </summary> | |
public class TerrainDataCloner | |
{ | |
/// <summary> | |
/// Creates a real deep-copy of a TerrainData | |
/// </summary> | |
/// <param name="original">TerrainData to duplicate</param> | |
/// <returns>New terrain data instance</returns> | |
public static TerrainData Clone(TerrainData original) | |
{ | |
TerrainData dup = new TerrainData(); | |
dup.alphamapResolution = original.alphamapResolution; | |
dup.baseMapResolution = original.baseMapResolution; | |
dup.detailPrototypes = CloneDetailPrototypes(original.detailPrototypes); | |
// The resolutionPerPatch is not publicly accessible so | |
// it can not be cloned properly, thus the recommendet default | |
// number of 16 | |
dup.SetDetailResolution(original.detailResolution, 16); | |
dup.heightmapResolution = original.heightmapResolution; | |
dup.size = original.size; | |
dup.splatPrototypes = CloneSplatPrototypes(original.splatPrototypes); | |
dup.thickness = original.thickness; | |
dup.wavingGrassAmount = original.wavingGrassAmount; | |
dup.wavingGrassSpeed = original.wavingGrassSpeed; | |
dup.wavingGrassStrength = original.wavingGrassStrength; | |
dup.wavingGrassTint = original.wavingGrassTint; | |
dup.SetAlphamaps(0, 0, original.GetAlphamaps(0, 0, original.alphamapWidth, original.alphamapHeight)); | |
dup.SetHeights(0, 0, original.GetHeights(0, 0, original.heightmapWidth, original.heightmapHeight)); | |
for (int n = 0; n < original.detailPrototypes.Length; n++) | |
{ | |
dup.SetDetailLayer(0, 0, n, original.GetDetailLayer(0, 0, original.detailWidth, original.detailHeight, n)); | |
} | |
dup.treePrototypes = CloneTreePrototypes(original.treePrototypes); | |
dup.treeInstances = CloneTreeInstances(original.treeInstances); | |
return dup; | |
} | |
/// <summary> | |
/// Deep-copies an array of splat prototype instances | |
/// </summary> | |
/// <param name="original">Prototypes to clone</param> | |
/// <returns>Cloned array</returns> | |
static SplatPrototype[] CloneSplatPrototypes(SplatPrototype[] original) | |
{ | |
SplatPrototype[] splatDup = new SplatPrototype[original.Length]; | |
for (int n = 0; n < splatDup.Length; n++) | |
{ | |
splatDup[n] = new SplatPrototype | |
{ | |
metallic = original[n].metallic, | |
normalMap = original[n].normalMap, | |
smoothness = original[n].smoothness, | |
specular = original[n].specular, | |
texture = original[n].texture, | |
tileOffset = original[n].tileOffset, | |
tileSize = original[n].tileSize | |
}; | |
} | |
return splatDup; | |
} | |
/// <summary> | |
/// Deep-copies an array of detail prototype instances | |
/// </summary> | |
/// <param name="original">Prototypes to clone</param> | |
/// <returns>Cloned array</returns> | |
static DetailPrototype[] CloneDetailPrototypes(DetailPrototype[] original) | |
{ | |
DetailPrototype[] protoDuplicate = new DetailPrototype[original.Length]; | |
for (int n = 0; n < original.Length; n++) | |
{ | |
protoDuplicate[n] = new DetailPrototype | |
{ | |
bendFactor = original[n].bendFactor, | |
dryColor = original[n].dryColor, | |
healthyColor = original[n].healthyColor, | |
maxHeight = original[n].maxHeight, | |
maxWidth = original[n].maxWidth, | |
minHeight = original[n].minHeight, | |
minWidth = original[n].minWidth, | |
noiseSpread = original[n].noiseSpread, | |
prototype = original[n].prototype, | |
prototypeTexture = original[n].prototypeTexture, | |
renderMode = original[n].renderMode, | |
usePrototypeMesh = original[n].usePrototypeMesh, | |
useInstancing = original[n].useInstancing, | |
}; | |
} | |
return protoDuplicate; | |
} | |
/// <summary> | |
/// Deep-copies an array of tree prototype instances | |
/// </summary> | |
/// <param name="original">Prototypes to clone</param> | |
/// <returns>Cloned array</returns> | |
static TreePrototype[] CloneTreePrototypes(TreePrototype[] original) | |
{ | |
TreePrototype[] protoDuplicate = new TreePrototype[original.Length]; | |
for (int n = 0; n < original.Length; n++) | |
{ | |
protoDuplicate[n] = new TreePrototype | |
{ | |
bendFactor = original[n].bendFactor, | |
prefab = original[n].prefab, | |
}; | |
} | |
return protoDuplicate; | |
} | |
/// <summary> | |
/// Deep-copies an array of tree instances | |
/// </summary> | |
/// <param name="original">Trees to clone</param> | |
/// <returns>Cloned array</returns> | |
static TreeInstance[] CloneTreeInstances(TreeInstance[] original) | |
{ | |
TreeInstance[] treeInst = new TreeInstance[original.Length]; | |
System.Array.Copy(original, treeInst, original.Length); | |
return treeInst; | |
} | |
} | |
} |
Great script.
In unity 2018.3 you no longer need to clone the splatmaps. Instead, terrains can share terrainlayers.
dup.terrainLayers= original.terrainLayers;
This script worked for me for sloped procedural infinite terrain stuff. Do fix the bug on line 53, though.
Just as a note for absolute beginners like me trying to use this: you have to create a script in the Unity GUI, then paste all this into it, and then add using ZS.Tools;
to the top of whatever script you want to use it in in order to be able to access TerrainDataCloner.Clone
One property is missing while cloning the detail prototypes.
You can add it pretty easily in the line 110.
useInstancing = original[n].useInstancing
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This script is a truly lifesaver!!
Allowed me to fully rotate a terrain in runtime.
There is just a bug in line 53, about treePrototypes : it should clone original.treePrototypes and NOT dup.treePrototypes.