// Fantasy Adventure Environment // Copyright Staggart Creations // staggart.xyz using UnityEngine; using System.Collections; namespace FAE { #if UNITY_EDITOR [ExecuteInEditMode] #endif public class TerrainUVUtil : ScriptableObject { //Dev public static readonly bool debug = false; //Public public enum Workflow { None, Terrain, Mesh } public Workflow workflow = Workflow.None; public Bounds meshBounds; public Vector3 pivotPos; public float height; public float bottom; public Vector3 size; public Vector3 centerPostion; public Vector3 originPosition; public Terrain[] terrains; public MeshRenderer[] meshes; public Vector4 terrainScaleOffset; public void GetObjectPlanarUV(GameObject[] gameObjects) { //No objects given if (gameObjects.Length == 0) { Debug.LogError("No objects given to render!"); return; } //Determine workflow if (gameObjects[0].GetComponent()) { workflow = Workflow.Terrain; GetTerrainInfo(gameObjects); } else if (gameObjects[0].GetComponent()) { workflow = Workflow.Mesh; GetMeshInfo(gameObjects); } //Safeguard else { workflow = Workflow.None; Debug.LogError("Terrain UV Utility: Current object is neither a terrain nor a mesh!"); return; } #if UNITY_EDITOR if (debug) { Debug.Log("Summed size: " + size); Debug.Log("Center position: " + centerPostion); Debug.Log("Origin position:" + originPosition); } #endif } private void GetMeshInfo(GameObject[] meshObjects) { height = 0; size = Vector3.zero; MeshRenderer mesh; //Init mesh terrain array meshes = new MeshRenderer[meshObjects.Length]; Bounds cornerMeshBounds = new Bounds(); for (int i = 0; i < meshObjects.Length; i++) { mesh = meshObjects[i].GetComponent(); meshBounds = mesh.bounds; //Store the bounds of the first, corner, mesh if (i == 0) cornerMeshBounds = meshBounds; //Mesh size has to be uniform if (!IsApproximatelyEqual(meshBounds.extents.x, meshBounds.extents.z)) { 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); } //Set height to highest terrain if (meshBounds.size.y > height) { height = meshBounds.size.y; } //With every terrain, size is increased size.x += meshBounds.size.x; size.z += meshBounds.size.z; } size.y = height; //Multi-terrain if (meshObjects.Length > 1) { size.x /= Mathf.Sqrt(meshObjects.Length); size.z /= Mathf.Sqrt(meshObjects.Length); originPosition = cornerMeshBounds.min; originPosition.y = meshObjects[0].transform.position.y; centerPostion = new Vector3(cornerMeshBounds.min.x + (size.x / 2), height / 2f, cornerMeshBounds.min.z + (size.z / 2)); } //Single terrain else { originPosition = cornerMeshBounds.min; originPosition.y = meshObjects[0].transform.position.y; centerPostion = cornerMeshBounds.center; } terrainScaleOffset = new Vector4(size.x, size.z, originPosition.x, originPosition.z); Shader.SetGlobalVector("_TerrainUV", terrainScaleOffset); } private void GetTerrainInfo(GameObject[] terrainObjects) { height = 0; size = Vector3.zero; Terrain terrain; //Init terrain array terrains = new Terrain[terrainObjects.Length]; for (int i = 0; i < terrainObjects.Length; i++) { terrain = terrainObjects[i].GetComponent(); terrains[i] = terrain; //Terrain size has to be uniform if (!IsApproximatelyEqual(terrain.terrainData.size.x, terrain.terrainData.size.z)) { Debug.LogErrorFormat(this.name + ": size of \"{0}\" is not uniform at {1}!", terrain.name, terrain.terrainData.size.x + "x" + terrain.terrainData.size.z); return; } //Set height to highest terrain if (terrain.terrainData.size.y > height) { height = terrain.terrainData.size.y; } if (terrains[i].transform.position.y < bottom) { bottom = terrain.transform.position.y; } //With every terrain, size is increased size += terrain.terrainData.size; } //For multi terrains, divide by square root of num tiles to get total size if (terrainObjects.Length > 1) { size /= Mathf.Sqrt(terrainObjects.Length); } //First terrain is considered the corner and origin originPosition = terrains[0].transform.position; //Offset origin point by half the size to get center centerPostion = new Vector3(originPosition.x + (size.x / 2f), originPosition.y + (height / 2f), originPosition.z + (size.z / 2f)); } //Check if values are equal, has error margin for floating point precision private bool IsApproximatelyEqual(float a, float b) { return Mathf.Abs(a - b) < 0.02f; } } }