TerrainUVUtil.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // Fantasy Adventure Environment
  2. // Copyright Staggart Creations
  3. // staggart.xyz
  4. using UnityEngine;
  5. using System.Collections;
  6. namespace FAE
  7. {
  8. #if UNITY_EDITOR
  9. [ExecuteInEditMode]
  10. #endif
  11. public class TerrainUVUtil : ScriptableObject
  12. {
  13. //Dev
  14. public static readonly bool debug = false;
  15. //Public
  16. public enum Workflow
  17. {
  18. None,
  19. Terrain,
  20. Mesh
  21. }
  22. public Workflow workflow = Workflow.None;
  23. public Bounds meshBounds;
  24. public Vector3 pivotPos;
  25. public float height;
  26. public float bottom;
  27. public Vector3 size;
  28. public Vector3 centerPostion;
  29. public Vector3 originPosition;
  30. public Terrain[] terrains;
  31. public MeshRenderer[] meshes;
  32. public Vector4 terrainScaleOffset;
  33. public void GetObjectPlanarUV(GameObject[] gameObjects)
  34. {
  35. //No objects given
  36. if (gameObjects.Length == 0)
  37. {
  38. Debug.LogError("No objects given to render!");
  39. return;
  40. }
  41. //Determine workflow
  42. if (gameObjects[0].GetComponent<Terrain>())
  43. {
  44. workflow = Workflow.Terrain;
  45. GetTerrainInfo(gameObjects);
  46. }
  47. else if (gameObjects[0].GetComponent<MeshRenderer>())
  48. {
  49. workflow = Workflow.Mesh;
  50. GetMeshInfo(gameObjects);
  51. }
  52. //Safeguard
  53. else
  54. {
  55. workflow = Workflow.None;
  56. Debug.LogError("Terrain UV Utility: Current object is neither a terrain nor a mesh!");
  57. return;
  58. }
  59. #if UNITY_EDITOR
  60. if (debug)
  61. {
  62. Debug.Log("Summed size: " + size);
  63. Debug.Log("Center position: " + centerPostion);
  64. Debug.Log("Origin position:" + originPosition);
  65. }
  66. #endif
  67. }
  68. private void GetMeshInfo(GameObject[] meshObjects)
  69. {
  70. height = 0;
  71. size = Vector3.zero;
  72. MeshRenderer mesh;
  73. //Init mesh terrain array
  74. meshes = new MeshRenderer[meshObjects.Length];
  75. Bounds cornerMeshBounds = new Bounds();
  76. for (int i = 0; i < meshObjects.Length; i++)
  77. {
  78. mesh = meshObjects[i].GetComponent<MeshRenderer>();
  79. meshBounds = mesh.bounds;
  80. //Store the bounds of the first, corner, mesh
  81. if (i == 0) cornerMeshBounds = meshBounds;
  82. //Mesh size has to be uniform
  83. if (!IsApproximatelyEqual(meshBounds.extents.x, meshBounds.extents.z))
  84. {
  85. Debug.LogWarningFormat("[PigmentMapGenerator] size of \"{0}\" is not uniform at {1}! This is required for correct results.", mesh.name, meshBounds.extents.x + "x" + meshBounds.extents.z);
  86. }
  87. //Set height to highest terrain
  88. if (meshBounds.size.y > height)
  89. {
  90. height = meshBounds.size.y;
  91. }
  92. //With every terrain, size is increased
  93. size.x += meshBounds.size.x;
  94. size.z += meshBounds.size.z;
  95. }
  96. size.y = height;
  97. //Multi-terrain
  98. if (meshObjects.Length > 1)
  99. {
  100. size.x /= Mathf.Sqrt(meshObjects.Length);
  101. size.z /= Mathf.Sqrt(meshObjects.Length);
  102. originPosition = cornerMeshBounds.min;
  103. originPosition.y = meshObjects[0].transform.position.y;
  104. centerPostion = new Vector3(cornerMeshBounds.min.x + (size.x / 2), height / 2f, cornerMeshBounds.min.z + (size.z / 2));
  105. }
  106. //Single terrain
  107. else
  108. {
  109. originPosition = cornerMeshBounds.min;
  110. originPosition.y = meshObjects[0].transform.position.y;
  111. centerPostion = cornerMeshBounds.center;
  112. }
  113. terrainScaleOffset = new Vector4(size.x, size.z, originPosition.x, originPosition.z);
  114. Shader.SetGlobalVector("_TerrainUV", terrainScaleOffset);
  115. }
  116. private void GetTerrainInfo(GameObject[] terrainObjects)
  117. {
  118. height = 0;
  119. size = Vector3.zero;
  120. Terrain terrain;
  121. //Init terrain array
  122. terrains = new Terrain[terrainObjects.Length];
  123. for (int i = 0; i < terrainObjects.Length; i++)
  124. {
  125. terrain = terrainObjects[i].GetComponent<Terrain>();
  126. terrains[i] = terrain;
  127. //Terrain size has to be uniform
  128. if (!IsApproximatelyEqual(terrain.terrainData.size.x, terrain.terrainData.size.z))
  129. {
  130. Debug.LogErrorFormat(this.name + ": size of \"{0}\" is not uniform at {1}!", terrain.name, terrain.terrainData.size.x + "x" + terrain.terrainData.size.z);
  131. return;
  132. }
  133. //Set height to highest terrain
  134. if (terrain.terrainData.size.y > height)
  135. {
  136. height = terrain.terrainData.size.y;
  137. }
  138. if (terrains[i].transform.position.y < bottom)
  139. {
  140. bottom = terrain.transform.position.y;
  141. }
  142. //With every terrain, size is increased
  143. size += terrain.terrainData.size;
  144. }
  145. //For multi terrains, divide by square root of num tiles to get total size
  146. if (terrainObjects.Length > 1)
  147. {
  148. size /= Mathf.Sqrt(terrainObjects.Length);
  149. }
  150. //First terrain is considered the corner and origin
  151. originPosition = terrains[0].transform.position;
  152. //Offset origin point by half the size to get center
  153. centerPostion = new Vector3(originPosition.x + (size.x / 2f), originPosition.y + (height / 2f), originPosition.z + (size.z / 2f));
  154. }
  155. //Check if values are equal, has error margin for floating point precision
  156. private bool IsApproximatelyEqual(float a, float b)
  157. {
  158. return Mathf.Abs(a - b) < 0.02f;
  159. }
  160. }
  161. }