TerrainSerialization.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System;
  5. using System.IO;
  6. public class TerrainSerialization : MonoBehaviour
  7. {
  8. public bool serialize;
  9. public bool deserialize;
  10. public Terrain[] terrains;
  11. void Update()
  12. {
  13. if (serialize)
  14. {
  15. serialize = false;
  16. SaveTerrains(Application.dataPath + "/MyTerrain.dat", terrains);
  17. }
  18. if (deserialize)
  19. {
  20. deserialize = false;
  21. LoadTerrain(Application.dataPath + "/MyTerrain.dat");
  22. }
  23. }
  24. public void SaveTerrains(string path, Terrain[] terrains)
  25. {
  26. List<byte> bytes = new List<byte>();
  27. R_SerializationHelper.SerializeInt(bytes, terrains.Length);
  28. for (int i = 0; i < terrains.Length; i++) SerializeTerrain(bytes, terrains[i]);
  29. if (bytes.Count > 0)
  30. {
  31. FileStream file = new FileStream(path, FileMode.Create);
  32. file.Write(bytes.ToArray(), 0, bytes.Count);
  33. file.Close();
  34. }
  35. }
  36. public void SaveTerrain(string path, Terrain terrain)
  37. {
  38. List<byte> bytes = new List<byte>();
  39. R_SerializationHelper.SerializeInt(bytes, 1);
  40. SerializeTerrain(bytes, terrain);
  41. if (bytes.Count > 0)
  42. {
  43. FileStream file = new FileStream(path, FileMode.Create);
  44. file.Write(bytes.ToArray(), 0, bytes.Count);
  45. file.Close();
  46. }
  47. }
  48. public Terrain[] LoadTerrain(string path)
  49. {
  50. FileStream file = new FileStream(path, FileMode.Open);
  51. if (file == null)
  52. {
  53. Debug.Log(path + " not found.");
  54. return null;
  55. }
  56. byte[] bytes = new byte[file.Length];
  57. file.Read(bytes, 0, bytes.Length);
  58. int index = 0;
  59. int terrainLength = R_SerializationHelper.DeserializeInt(bytes, ref index);
  60. Terrain[] terrains = new Terrain[terrainLength];
  61. for (int i = 0; i < terrainLength; i++)
  62. {
  63. terrains[i] = DeserializeTerrain(bytes, ref index);
  64. }
  65. return terrains;
  66. }
  67. public void SerializeTerrain(List<byte> bytes, Terrain terrain)
  68. {
  69. if (terrain == null) return;
  70. if (terrain.terrainData == null) return;
  71. R_SerializationHelper.SerializeString(bytes, terrain.name);
  72. R_SerializationHelper.SerializeVector3(bytes, terrain.transform.position);
  73. R_SerializationHelper.SerializeFloat(bytes, terrain.basemapDistance);
  74. R_SerializationHelper.SerializeBool(bytes, terrain.castShadows);
  75. R_SerializationHelper.SerializeBool(bytes, terrain.collectDetailPatches);
  76. R_SerializationHelper.SerializeFloat(bytes, terrain.detailObjectDensity);
  77. R_SerializationHelper.SerializeFloat(bytes, terrain.detailObjectDistance);
  78. R_SerializationHelper.SerializeBool(bytes, terrain.drawHeightmap);
  79. R_SerializationHelper.SerializeBool(bytes, terrain.drawTreesAndFoliage);
  80. R_SerializationHelper.SerializeInt(bytes, terrain.heightmapMaximumLOD);
  81. R_SerializationHelper.SerializeFloat(bytes, terrain.heightmapPixelError);
  82. R_SerializationHelper.SerializeFloat(bytes, terrain.legacyShininess);
  83. R_SerializationHelper.SerializeColor(bytes, terrain.legacySpecular);
  84. R_SerializationHelper.SerializeInt(bytes, terrain.lightmapIndex);
  85. #if !UNITY_5_1
  86. R_SerializationHelper.SerializeVector4(bytes, terrain.lightmapScaleOffset);
  87. #endif
  88. if (terrain.materialTemplate != null)
  89. {
  90. bytes.Add(1);
  91. R_SerializationHelper.SerializeString(bytes, terrain.materialTemplate.name);
  92. }
  93. else bytes.Add(0);
  94. R_SerializationHelper.SerializeInt(bytes, (int)terrain.materialType);
  95. #if !UNITY_5_1
  96. R_SerializationHelper.SerializeInt(bytes, terrain.realtimeLightmapIndex);
  97. R_SerializationHelper.SerializeVector4(bytes, terrain.realtimeLightmapScaleOffset);
  98. #endif
  99. R_SerializationHelper.SerializeInt(bytes, (int)terrain.reflectionProbeUsage);
  100. R_SerializationHelper.SerializeFloat(bytes, terrain.treeBillboardDistance);
  101. R_SerializationHelper.SerializeFloat(bytes, terrain.treeCrossFadeLength);
  102. R_SerializationHelper.SerializeFloat(bytes, terrain.treeDistance);
  103. R_SerializationHelper.SerializeInt(bytes, terrain.treeMaximumFullLODCount);
  104. SerializeTerrainData(bytes, terrain.terrainData);
  105. // Debug.Log(bytes.Count);
  106. }
  107. public Terrain DeserializeTerrain(byte[] bytes, ref int index)
  108. {
  109. GameObject go = Terrain.CreateTerrainGameObject(null);
  110. Terrain terrain = go.GetComponent<Terrain>();
  111. TerrainCollider terrainCollider = go.GetComponent<TerrainCollider>();
  112. terrain.name = R_SerializationHelper.DeserializeString(bytes, ref index);
  113. terrain.transform.position = R_SerializationHelper.DeserializeVector3(bytes, ref index);
  114. terrain.basemapDistance = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  115. terrain.castShadows = R_SerializationHelper.DeserializeBool(bytes, ref index);
  116. terrain.collectDetailPatches = R_SerializationHelper.DeserializeBool(bytes, ref index);
  117. terrain.detailObjectDensity = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  118. terrain.detailObjectDistance = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  119. terrain.drawHeightmap = R_SerializationHelper.DeserializeBool(bytes, ref index);
  120. terrain.drawTreesAndFoliage = R_SerializationHelper.DeserializeBool(bytes, ref index);
  121. terrain.heightmapMaximumLOD = R_SerializationHelper.DeserializeInt(bytes, ref index);
  122. terrain.heightmapPixelError = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  123. terrain.legacyShininess = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  124. terrain.legacySpecular = R_SerializationHelper.DeserializeColor(bytes, ref index);
  125. terrain.lightmapIndex = R_SerializationHelper.DeserializeInt(bytes, ref index);
  126. #if !UNITY_5_1
  127. terrain.lightmapScaleOffset = R_SerializationHelper.DeserializeVector4(bytes, ref index);
  128. #endif
  129. if (bytes[index++] == 1)
  130. {
  131. R_SerializationHelper.DeserializeString(bytes, ref index);
  132. }
  133. terrain.materialType = (Terrain.MaterialType)R_SerializationHelper.DeserializeInt(bytes, ref index);
  134. #if !UNITY_5_1
  135. terrain.realtimeLightmapIndex = R_SerializationHelper.DeserializeInt(bytes, ref index);
  136. terrain.realtimeLightmapScaleOffset = R_SerializationHelper.DeserializeVector4(bytes, ref index);
  137. #endif
  138. terrain.reflectionProbeUsage = (UnityEngine.Rendering.ReflectionProbeUsage)R_SerializationHelper.DeserializeInt(bytes, ref index);
  139. terrain.treeBillboardDistance = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  140. terrain.treeCrossFadeLength = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  141. terrain.treeDistance = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  142. terrain.treeMaximumFullLODCount = R_SerializationHelper.DeserializeInt(bytes, ref index);
  143. terrain.terrainData = DeserializeTerrainData(bytes, ref index);
  144. terrainCollider.terrainData = terrain.terrainData;
  145. return terrain;
  146. }
  147. public void SerializeTerrainData(List<byte> bytes, TerrainData terrainData)
  148. {
  149. R_SerializationHelper.SerializeString(bytes, terrainData.name);
  150. int heightmapResolution = terrainData.heightmapResolution;
  151. int detailResolution = terrainData.detailResolution;
  152. R_SerializationHelper.SerializeInt(bytes, heightmapResolution);
  153. R_SerializationHelper.SerializeInt(bytes, terrainData.baseMapResolution);
  154. R_SerializationHelper.SerializeInt(bytes, terrainData.alphamapResolution);
  155. R_SerializationHelper.SerializeInt(bytes, detailResolution);
  156. R_SerializationHelper.SerializeVector3(bytes, terrainData.size);
  157. R_SerializationHelper.SerializeFloat(bytes, terrainData.thickness);
  158. R_SerializationHelper.SerializeFloat(bytes, terrainData.wavingGrassAmount);
  159. R_SerializationHelper.SerializeFloat(bytes, terrainData.wavingGrassSpeed);
  160. R_SerializationHelper.SerializeFloat(bytes, terrainData.wavingGrassStrength);
  161. R_SerializationHelper.SerializeColor(bytes, terrainData.wavingGrassTint);
  162. // Splat textures
  163. SplatPrototype[] splatPrototypes = terrainData.splatPrototypes;
  164. R_SerializationHelper.SerializeInt(bytes, splatPrototypes.Length);
  165. for (int i = 0; i < splatPrototypes.Length; i++)
  166. {
  167. SplatPrototype splat = splatPrototypes[i];
  168. R_SerializationHelper.SerializeFloat(bytes, splat.metallic);
  169. if (splat.normalMap != null)
  170. {
  171. bytes.Add(1);
  172. R_SerializationHelper.SerializeString(bytes, splat.normalMap.name);
  173. }
  174. else bytes.Add(0);
  175. R_SerializationHelper.SerializeFloat(bytes, splat.smoothness);
  176. R_SerializationHelper.SerializeString(bytes, splat.texture.name);
  177. R_SerializationHelper.SerializeVector2(bytes, splat.tileOffset);
  178. R_SerializationHelper.SerializeVector2(bytes, splat.tileSize);
  179. }
  180. // Tree Prototypes
  181. TreePrototype[] treePrototypes = terrainData.treePrototypes;
  182. R_SerializationHelper.SerializeInt(bytes, treePrototypes.Length);
  183. for (int i = 0; i < treePrototypes.Length; i++)
  184. {
  185. TreePrototype tree = treePrototypes[i];
  186. R_SerializationHelper.SerializeFloat(bytes, tree.bendFactor);
  187. R_SerializationHelper.SerializeString(bytes, tree.prefab.name);
  188. }
  189. // Grass
  190. DetailPrototype[] detailPrototypes = terrainData.detailPrototypes;
  191. int detailPrototypesLength = detailPrototypes.Length;
  192. R_SerializationHelper.SerializeInt(bytes, detailPrototypes.Length);
  193. for (int i = 0; i < detailPrototypes.Length; i++)
  194. {
  195. DetailPrototype detail = detailPrototypes[i];
  196. R_SerializationHelper.SerializeFloat(bytes, detail.bendFactor);
  197. R_SerializationHelper.SerializeColor(bytes, detail.dryColor);
  198. R_SerializationHelper.SerializeColor(bytes, detail.healthyColor);
  199. R_SerializationHelper.SerializeFloat(bytes, detail.maxHeight);
  200. R_SerializationHelper.SerializeFloat(bytes, detail.maxWidth);
  201. R_SerializationHelper.SerializeFloat(bytes, detail.minHeight);
  202. R_SerializationHelper.SerializeFloat(bytes, detail.minWidth);
  203. R_SerializationHelper.SerializeFloat(bytes, detail.noiseSpread);
  204. if (detail.prototype != null)
  205. {
  206. bytes.Add(1);
  207. R_SerializationHelper.SerializeString(bytes, detail.prototype.name);
  208. }
  209. else bytes.Add(0);
  210. if (detail.prototypeTexture != null)
  211. {
  212. bytes.Add(1);
  213. R_SerializationHelper.SerializeString(bytes, detail.prototypeTexture.name);
  214. }
  215. else bytes.Add(0);
  216. R_SerializationHelper.SerializeInt(bytes, (int)detail.renderMode);
  217. }
  218. // Heights
  219. float[,] heights = terrainData.GetHeights(0, 0, heightmapResolution, heightmapResolution);
  220. R_SerializationHelper.Serialize2DFloatArray(bytes, heights);
  221. // Splat maps
  222. R_SerializationHelper.SerializeInt(bytes, terrainData.alphamapTextures.Length);
  223. for (int i = 0; i < terrainData.alphamapTextures.Length; i++)
  224. {
  225. Texture2D tex = terrainData.alphamapTextures[i];
  226. byte[] texBytes = tex.EncodeToPNG();
  227. R_SerializationHelper.SerializeInt(bytes, texBytes.Length);
  228. bytes.AddRange(texBytes);
  229. }
  230. // Trees
  231. TreeInstance[] treeInstances = terrainData.treeInstances;
  232. R_SerializationHelper.SerializeInt(bytes, treeInstances.Length);
  233. for (int i = 0; i < treeInstances.Length; i++)
  234. {
  235. TreeInstance tree = treeInstances[i];
  236. R_SerializationHelper.SerializeColor(bytes, tree.color);
  237. R_SerializationHelper.SerializeFloat(bytes, tree.heightScale);
  238. R_SerializationHelper.SerializeColor(bytes, tree.lightmapColor);
  239. R_SerializationHelper.SerializeVector3(bytes, tree.position);
  240. R_SerializationHelper.SerializeInt(bytes, tree.prototypeIndex);
  241. R_SerializationHelper.SerializeFloat(bytes, tree.rotation);
  242. R_SerializationHelper.SerializeFloat(bytes, tree.widthScale);
  243. }
  244. // Grass
  245. for (int i = 0; i < detailPrototypesLength; i++)
  246. {
  247. int[,] detailMap = terrainData.GetDetailLayer(0, 0, detailResolution, detailResolution, i);
  248. R_SerializationHelper.Serialize2DIntArrayToBytes(bytes, detailMap);
  249. }
  250. }
  251. public TerrainData DeserializeTerrainData(byte[] bytes, ref int index)
  252. {
  253. TerrainData terrainData = new TerrainData();
  254. terrainData.name = R_SerializationHelper.DeserializeString(bytes, ref index);
  255. // Debug.Log(terrainData.name);
  256. int heightmapResolution = R_SerializationHelper.DeserializeInt(bytes, ref index);
  257. terrainData.heightmapResolution = heightmapResolution;
  258. terrainData.baseMapResolution = R_SerializationHelper.DeserializeInt(bytes, ref index);
  259. terrainData.alphamapResolution = R_SerializationHelper.DeserializeInt(bytes, ref index);
  260. int detailResolution = R_SerializationHelper.DeserializeInt(bytes, ref index);
  261. terrainData.SetDetailResolution(detailResolution, 16);
  262. terrainData.size = R_SerializationHelper.DeserializeVector3(bytes, ref index);
  263. terrainData.thickness = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  264. terrainData.wavingGrassAmount = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  265. terrainData.wavingGrassSpeed = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  266. terrainData.wavingGrassStrength = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  267. terrainData.wavingGrassTint = R_SerializationHelper.DeserializeColor(bytes, ref index);
  268. // Splat Textures
  269. int splatLength = R_SerializationHelper.DeserializeInt(bytes, ref index);
  270. SplatPrototype[] splatPrototypes = new SplatPrototype[splatLength];
  271. for (int i = 0; i < splatLength; i++)
  272. {
  273. SplatPrototype splat = new SplatPrototype();
  274. splat.metallic = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  275. if (bytes[index++] == 1)
  276. {
  277. string normalName = R_SerializationHelper.DeserializeString(bytes, ref index);
  278. splat.normalMap = (Texture2D)Resources.Load(normalName);
  279. }
  280. splat.smoothness = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  281. string splatName = R_SerializationHelper.DeserializeString(bytes, ref index);
  282. splat.texture = (Texture2D)Resources.Load(splatName);
  283. splat.tileOffset = R_SerializationHelper.DeserializeVector2(bytes, ref index);
  284. splat.tileSize = R_SerializationHelper.DeserializeVector2(bytes, ref index);
  285. splatPrototypes[i] = splat;
  286. }
  287. terrainData.splatPrototypes = splatPrototypes;
  288. // Tree Prototypes
  289. int treeLength = R_SerializationHelper.DeserializeInt(bytes, ref index);
  290. TreePrototype[] treePrototypes = new TreePrototype[treeLength];
  291. for (int i = 0; i < treeLength; i++)
  292. {
  293. TreePrototype tree = new TreePrototype();
  294. tree.bendFactor = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  295. string prefabName = R_SerializationHelper.DeserializeString(bytes, ref index);
  296. tree.prefab = (GameObject)Resources.Load(prefabName);
  297. treePrototypes[i] = tree;
  298. }
  299. terrainData.treePrototypes = treePrototypes;
  300. // Grass Prototypes
  301. int grassLength = R_SerializationHelper.DeserializeInt(bytes, ref index);
  302. DetailPrototype[] detailPrototypes = new DetailPrototype[grassLength];
  303. for (int i = 0; i < grassLength; i++)
  304. {
  305. DetailPrototype grass = new DetailPrototype();
  306. grass.bendFactor = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  307. grass.dryColor = R_SerializationHelper.DeserializeColor(bytes, ref index);
  308. grass.healthyColor = R_SerializationHelper.DeserializeColor(bytes, ref index);
  309. grass.maxHeight = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  310. grass.maxWidth = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  311. grass.minHeight = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  312. grass.minWidth = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  313. grass.noiseSpread = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  314. if (bytes[index++] == 1)
  315. {
  316. R_SerializationHelper.DeserializeString(bytes, ref index);
  317. }
  318. if (bytes[index++] == 1)
  319. {
  320. string textureName = R_SerializationHelper.DeserializeString(bytes, ref index);
  321. grass.prototypeTexture = (Texture2D)Resources.Load(textureName);
  322. }
  323. grass.renderMode = (DetailRenderMode)R_SerializationHelper.DeserializeInt(bytes, ref index);
  324. detailPrototypes[i] = grass;
  325. }
  326. terrainData.detailPrototypes = detailPrototypes;
  327. float[,] heights = R_SerializationHelper.Deserialize2DFloatArray(bytes, ref index);
  328. terrainData.SetHeights(0, 0, heights);
  329. int splatmapLength = R_SerializationHelper.DeserializeInt(bytes, ref index);
  330. Texture2D[] alphamapTextures = terrainData.alphamapTextures;
  331. for (int i = 0; i < splatmapLength; i++)
  332. {
  333. int length = R_SerializationHelper.DeserializeInt(bytes, ref index);
  334. byte[] texBytes = new byte[length];
  335. Array.Copy(bytes, index, texBytes, 0, length);
  336. index += length;
  337. alphamapTextures[i].LoadImage(texBytes);
  338. alphamapTextures[i].Apply();
  339. }
  340. int treeInstancesLength = R_SerializationHelper.DeserializeInt(bytes, ref index);
  341. TreeInstance[] trees = new TreeInstance[treeInstancesLength];
  342. for (int i = 0; i < trees.Length; i++)
  343. {
  344. TreeInstance tree = new TreeInstance();
  345. tree.color = R_SerializationHelper.DeserializeColor(bytes, ref index);
  346. tree.heightScale = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  347. tree.lightmapColor = R_SerializationHelper.DeserializeColor(bytes, ref index);
  348. tree.position = R_SerializationHelper.DeserializeVector3(bytes, ref index);
  349. tree.prototypeIndex = R_SerializationHelper.DeserializeInt(bytes, ref index);
  350. tree.rotation = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  351. tree.widthScale = R_SerializationHelper.DeserializeFloat(bytes, ref index);
  352. trees[i] = tree;
  353. }
  354. terrainData.treeInstances = trees;
  355. for (int i = 0; i < grassLength; i++)
  356. {
  357. int[,] grassMap = R_SerializationHelper.Deserialize2DByteArrayToInt(bytes, ref index);
  358. terrainData.SetDetailLayer(0, 0, i, grassMap);
  359. }
  360. return terrainData;
  361. }
  362. }