using System; using System.Collections.Generic; using System.Linq; using UnityEngine; namespace CTS { [Serializable] [ExecuteInEditMode] public class CTSMeshBlender : MonoBehaviour { [Serializable] public class TextureData { public int m_terrainIdx; public float m_terrainTextureStrength; public Texture2D m_albedo; public Texture2D m_normal; public Texture2D m_hao_in_GA; public float m_tiling; public Vector4 m_color; public float m_normalPower; public float m_aoPower; public float m_geoPower; public float m_heightContrast = 1f; public float m_heightDepth = 1f; public float m_heightBlendClose = 1f; } public float m_textureBlendOffset = -2f; public float m_textureBlendStart = 2f; public float m_textureBlendHeight = 1f; public float m_normalBlendOffset = -1f; public float m_normalBlendStart; public float m_normalBlendHeight = 2f; public float m_specular = 1f; public float m_smoothness = 1f; public bool m_useAO = true; public bool m_useAOTexture; public float m_geoMapClosePower; public float m_geoTilingClose = 1f; public float m_geoMapOffsetClose = 86f; public Texture2D m_geoMap; public Material m_sharedMaterial; public List m_textureList = new List(); private MaterialPropertyBlock m_materialProperties; [SerializeField] private MeshRenderer[] m_renderers; [SerializeField] private MeshFilter[] m_filters; [SerializeField] private Mesh[] m_originalMeshes; private static bool _ShadersIDsAreInitialized; private static int _Use_AO; private static int _Use_AO_Texture; private static int _Terrain_Specular; private static int _Terrain_Smoothness; private static int _Texture_Geological_Map; private static int _Geological_Tiling_Close; private static int _Geological_Map_Offset_Close; private static int _Geological_Map_Close_Power; private static int _Texture_Albedo_Sm_1; private static int _Texture_Color_1; private static int _Texture_Tiling_1; private static int _Texture_Normal_1; private static int _Texture_1_Normal_Power; private static int _Texture_GHeightAAO_1; private static int _Texture_1_AO_Power; private static int _Texture_1_Geological_Power; private static int _Texture_1_Height_Contrast; private static int _Texture_1_Heightmap_Depth; private static int _Texture_1_Heightblend_Close; private static int _Texture_Albedo_Sm_2; private static int _Texture_Color_2; private static int _Texture_Tiling_2; private static int _Texture_Normal_2; private static int _Texture_2_Normal_Power; private static int _Texture_GHeightAAO_2; private static int _Texture_2_AO_Power; private static int _Texture_2_Geological_Power; private static int _Texture_2_Height_Contrast; private static int _Texture_2_Heightmap_Depth; private static int _Texture_2_Heightblend_Close; private static int _Texture_Albedo_Sm_3; private static int _Texture_Color_3; private static int _Texture_Tiling_3; private static int _Texture_Normal_3; private static int _Texture_3_Normal_Power; private static int _Texture_GHeightAAO_3; private static int _Texture_3_AO_Power; private static int _Texture_3_Geological_Power; private static int _Texture_3_Height_Contrast; private static int _Texture_3_Heightmap_Depth; private static int _Texture_3_Heightblend_Close; private void Awake() { } public void ClearBlend() { if (m_filters != null) { for (int i = 0; i < m_filters.Length; i++) { m_filters[i].sharedMesh = m_originalMeshes[i]; } } if (m_renderers != null) { for (int j = 0; j < m_renderers.Length; j++) { MeshRenderer meshRenderer = m_renderers[j]; List list = new List(meshRenderer.sharedMaterials); int num = 0; while (num < list.Count) { Material material = list[num]; if (material == null || material.name == "CTS Model Blend Shader") { list.RemoveAt(num); m_sharedMaterial = material; } else { num++; } } meshRenderer.sharedMaterials = list.ToArray(); } } if (m_sharedMaterial != null) { UnityEngine.Object.DestroyImmediate(m_sharedMaterial); m_sharedMaterial = null; } m_renderers = null; m_filters = null; m_originalMeshes = null; m_textureList.Clear(); } public void CreateBlend() { ClearBlend(); m_renderers = base.gameObject.GetComponentsInChildren(); m_filters = base.gameObject.GetComponentsInChildren(); m_originalMeshes = new Mesh[m_filters.Length]; for (int i = 0; i < m_filters.Length; i++) { if (m_filters[i].sharedMesh == null) { m_originalMeshes[i] = null; continue; } m_originalMeshes[i] = m_filters[i].sharedMesh; m_filters[i].sharedMesh = UnityEngine.Object.Instantiate(m_originalMeshes[i]); } GetTexturesAndSettingsAtCurrentLocation(); Vector3 position = base.transform.position; Vector3 localScale = base.transform.localScale; Vector3 eulerAngles = base.transform.eulerAngles; for (int j = 0; j < m_filters.Length; j++) { Mesh sharedMesh = m_filters[j].sharedMesh; if (!(sharedMesh != null)) { continue; } int num = sharedMesh.vertices.Length; Vector3[] vertices = sharedMesh.vertices; Vector3[] normals = sharedMesh.normals; Color[] array = sharedMesh.colors; if (array.Length == 0) { array = new Color[num]; } for (int k = 0; k < num; k++) { Vector3 vector = position + Quaternion.Euler(eulerAngles) * Vector3.Scale(vertices[k], localScale); Terrain terrain = GetTerrain(vector); if (terrain != null) { Vector3 localPosition = GetLocalPosition(terrain, vector); float num2 = terrain.SampleHeight(vector); float num3 = num2 + m_textureBlendOffset; float num4 = num3 + m_textureBlendStart; float num5 = num4 + m_textureBlendHeight; float num6 = num2 + m_normalBlendOffset; float num7 = num6 + m_normalBlendStart; float num8 = num7 + m_normalBlendHeight; if (vector.y < num3) { array[k].a = 0f; } else if (vector.y <= num5) { Color color = default(Color); float a = 1f; if (vector.y > num4) { a = Mathf.Lerp(1f, 0f, (vector.y - num4) / m_textureBlendHeight); } color.a = a; float[,,] texturesAtLocation = GetTexturesAtLocation(terrain, localPosition); if (m_textureList.Count >= 1) { color.r = texturesAtLocation[0, 0, m_textureList[0].m_terrainIdx]; } if (m_textureList.Count >= 2) { color.g = texturesAtLocation[0, 0, m_textureList[1].m_terrainIdx]; } if (m_textureList.Count >= 3) { color.b = texturesAtLocation[0, 0, m_textureList[2].m_terrainIdx]; } array[k] = color; } else { array[k].a = 0f; } if (vector.y >= num6) { if (vector.y < num7) { normals[k] = GetNormalsAtLocation(terrain, localPosition); } else if (vector.y <= num8) { normals[k] = Vector3.Lerp(GetNormalsAtLocation(terrain, localPosition), normals[k], (num8 - vector.y) / m_normalBlendHeight); } } } else { array[k].a = 0f; } } sharedMesh.colors = array; sharedMesh.normals = normals; } InitializeMaterials(); UpdateShader(); } public Vector3 GetNearestVertice(Vector3 sourcePosition, GameObject targetObject) { float num = float.MaxValue; Vector3 vector = targetObject.transform.position; Vector3 vector2 = vector; Vector3 localScale = targetObject.transform.localScale; Vector3 eulerAngles = targetObject.transform.eulerAngles; MeshFilter[] componentsInChildren = targetObject.GetComponentsInChildren(); for (int i = 0; i < componentsInChildren.Length; i++) { Mesh sharedMesh = componentsInChildren[i].sharedMesh; if (!(sharedMesh != null)) { continue; } int num2 = sharedMesh.vertices.Length; Vector3[] vertices = sharedMesh.vertices; for (int j = 0; j < num2; j++) { Vector3 vector3 = vector2 + Quaternion.Euler(eulerAngles) * Vector3.Scale(vertices[j], localScale); float num3 = Vector3.Distance(sourcePosition, vector3); if (num3 < num) { num = num3; vector = vector3; } } } return vector; } private void InitializeShaderConstants() { if (!_ShadersIDsAreInitialized) { Debug.Log("Initialising shader IDs"); _ShadersIDsAreInitialized = true; _Use_AO = Shader.PropertyToID("_Use_AO"); _Use_AO_Texture = Shader.PropertyToID("_Use_AO_Texture"); _Terrain_Specular = Shader.PropertyToID("_Terrain_Specular"); _Terrain_Smoothness = Shader.PropertyToID("_Terrain_Smoothness"); _Texture_Geological_Map = Shader.PropertyToID("_Texture_Geological_Map"); _Geological_Tiling_Close = Shader.PropertyToID("_Geological_Tiling_Close"); _Geological_Map_Offset_Close = Shader.PropertyToID("_Geological_Map_Offset_Close"); _Geological_Map_Close_Power = Shader.PropertyToID("_Geological_Map_Close_Power"); _Texture_Albedo_Sm_1 = Shader.PropertyToID("_Texture_Albedo_Sm_1"); _Texture_Color_1 = Shader.PropertyToID("_Texture_Color_1"); _Texture_Tiling_1 = Shader.PropertyToID("_Texture_Tiling_1"); _Texture_Normal_1 = Shader.PropertyToID("_Texture_Normal_1"); _Texture_1_Normal_Power = Shader.PropertyToID("_Texture_1_Normal_Power"); _Texture_GHeightAAO_1 = Shader.PropertyToID("_Texture_GHeightAAO_1"); _Texture_1_AO_Power = Shader.PropertyToID("_Texture_1_AO_Power"); _Texture_1_Geological_Power = Shader.PropertyToID("_Texture_1_Geological_Power"); _Texture_1_Height_Contrast = Shader.PropertyToID("_Texture_1_Height_Contrast"); _Texture_1_Heightmap_Depth = Shader.PropertyToID("_Texture_1_Heightmap_Depth"); _Texture_1_Heightblend_Close = Shader.PropertyToID("_Texture_1_Heightblend_Close"); _Texture_Albedo_Sm_2 = Shader.PropertyToID("_Texture_Albedo_Sm_2"); _Texture_Color_2 = Shader.PropertyToID("_Texture_Color_2"); _Texture_Tiling_2 = Shader.PropertyToID("_Texture_Tiling_2"); _Texture_Normal_2 = Shader.PropertyToID("_Texture_Normal_2"); _Texture_2_Normal_Power = Shader.PropertyToID("_Texture_2_Normal_Power"); _Texture_GHeightAAO_2 = Shader.PropertyToID("_Texture_GHeightAAO_2"); _Texture_2_AO_Power = Shader.PropertyToID("_Texture_2_AO_Power"); _Texture_2_Geological_Power = Shader.PropertyToID("_Texture_2_Geological_Power"); _Texture_2_Height_Contrast = Shader.PropertyToID("_Texture_2_Height_Contrast"); _Texture_2_Heightmap_Depth = Shader.PropertyToID("_Texture_2_Heightmap_Depth"); _Texture_2_Heightblend_Close = Shader.PropertyToID("_Texture_2_Heightblend_Close"); _Texture_Albedo_Sm_3 = Shader.PropertyToID("_Texture_Albedo_Sm_3"); _Texture_Color_3 = Shader.PropertyToID("_Texture_Color_3"); _Texture_Tiling_3 = Shader.PropertyToID("_Texture_Tiling_3"); _Texture_Normal_3 = Shader.PropertyToID("_Texture_Normal_3"); _Texture_3_Normal_Power = Shader.PropertyToID("_Texture_3_Normal_Power"); _Texture_GHeightAAO_3 = Shader.PropertyToID("_Texture_GHeightAAO_3"); _Texture_3_AO_Power = Shader.PropertyToID("_Texture_3_AO_Power"); _Texture_3_Geological_Power = Shader.PropertyToID("_Texture_3_Geological_Power"); _Texture_3_Height_Contrast = Shader.PropertyToID("_Texture_3_Height_Contrast"); _Texture_3_Heightmap_Depth = Shader.PropertyToID("_Texture_3_Heightmap_Depth"); _Texture_3_Heightblend_Close = Shader.PropertyToID("_Texture_3_Heightblend_Close"); } } private void InitializeMaterials() { for (int i = 0; i < m_renderers.Length; i++) { MeshRenderer meshRenderer = m_renderers[i]; if (meshRenderer != null) { bool flag = false; List list = new List(m_renderers[i].sharedMaterials); for (int j = 0; j < list.Count; j++) { if (list[j].name == "CTS Model Blend Shader") { flag = true; m_sharedMaterial = list[j]; break; } } if (!flag) { if (m_sharedMaterial == null) { m_sharedMaterial = new Material(Shader.Find("CTS/CTS_Model_Blend")) { name = "CTS Model Blend Shader" }; } list.Add(m_sharedMaterial); meshRenderer.sharedMaterials = list.ToArray(); } } else { Debug.LogWarning("Got nulll renderer!"); } } } private void UpdateShader() { InitializeShaderConstants(); if (m_sharedMaterial == null) { Debug.LogWarning("CTS Blender Missing Material. Exiting without updating."); return; } if (m_renderers == null || m_renderers.Length == 0) { Debug.LogWarning("CTS Blender Missing Renderer. Exiting without updating."); return; } if (m_textureList.Count == 0) { Debug.LogWarning("CTS Blender has no textures. Exiting without updating."); return; } if (m_materialProperties == null) { m_materialProperties = new MaterialPropertyBlock(); } for (int i = 0; i < m_renderers.Length; i++) { m_sharedMaterial.SetInt(_Use_AO, m_useAO ? 1 : 0); m_sharedMaterial.SetInt(_Use_AO_Texture, m_useAOTexture ? 1 : 0); m_sharedMaterial.SetFloat(_Terrain_Specular, m_specular); m_sharedMaterial.SetFloat(_Terrain_Smoothness, m_smoothness); m_sharedMaterial.SetTexture(_Texture_Geological_Map, m_geoMap); m_sharedMaterial.SetFloat(_Geological_Tiling_Close, m_geoTilingClose); m_sharedMaterial.SetFloat(_Geological_Map_Offset_Close, m_geoMapOffsetClose); m_sharedMaterial.SetFloat(_Geological_Map_Close_Power, m_geoMapClosePower); if (m_textureList.Count >= 1) { TextureData textureData = m_textureList[0]; m_sharedMaterial.SetTexture(_Texture_Albedo_Sm_1, textureData.m_albedo); m_sharedMaterial.SetTexture(_Texture_Normal_1, textureData.m_normal); m_sharedMaterial.SetTexture(_Texture_GHeightAAO_1, textureData.m_hao_in_GA); m_sharedMaterial.SetVector(_Texture_Color_1, textureData.m_color); m_sharedMaterial.SetFloat(_Texture_Tiling_1, textureData.m_tiling); m_sharedMaterial.SetFloat(_Texture_1_Normal_Power, textureData.m_normalPower); m_sharedMaterial.SetFloat(_Texture_1_AO_Power, textureData.m_aoPower); m_sharedMaterial.SetFloat(_Texture_1_Geological_Power, textureData.m_geoPower); m_sharedMaterial.SetFloat(_Texture_1_Height_Contrast, textureData.m_heightContrast); m_sharedMaterial.SetFloat(_Texture_1_Heightmap_Depth, textureData.m_heightDepth); m_sharedMaterial.SetFloat(_Texture_1_Heightblend_Close, textureData.m_heightBlendClose); } if (m_textureList.Count >= 2) { TextureData textureData2 = m_textureList[1]; m_sharedMaterial.SetTexture(_Texture_Albedo_Sm_2, textureData2.m_albedo); m_sharedMaterial.SetTexture(_Texture_Normal_2, textureData2.m_normal); m_sharedMaterial.SetTexture(_Texture_GHeightAAO_2, textureData2.m_hao_in_GA); m_sharedMaterial.SetVector(_Texture_Color_2, textureData2.m_color); m_sharedMaterial.SetFloat(_Texture_Tiling_2, textureData2.m_tiling); m_sharedMaterial.SetFloat(_Texture_2_Normal_Power, textureData2.m_normalPower); m_sharedMaterial.SetFloat(_Texture_2_AO_Power, textureData2.m_aoPower); m_sharedMaterial.SetFloat(_Texture_2_Geological_Power, textureData2.m_geoPower); m_sharedMaterial.SetFloat(_Texture_2_Height_Contrast, textureData2.m_heightContrast); m_sharedMaterial.SetFloat(_Texture_2_Heightmap_Depth, textureData2.m_heightDepth); m_sharedMaterial.SetFloat(_Texture_2_Heightblend_Close, textureData2.m_heightBlendClose); } if (m_textureList.Count >= 3) { TextureData textureData3 = m_textureList[2]; m_sharedMaterial.SetTexture(_Texture_Albedo_Sm_3, textureData3.m_albedo); m_sharedMaterial.SetTexture(_Texture_Normal_3, textureData3.m_normal); m_sharedMaterial.SetTexture(_Texture_GHeightAAO_3, textureData3.m_hao_in_GA); m_sharedMaterial.SetVector(_Texture_Color_3, textureData3.m_color); m_sharedMaterial.SetFloat(_Texture_Tiling_3, textureData3.m_tiling); m_sharedMaterial.SetFloat(_Texture_3_Normal_Power, textureData3.m_normalPower); m_sharedMaterial.SetFloat(_Texture_3_AO_Power, textureData3.m_aoPower); m_sharedMaterial.SetFloat(_Texture_3_Geological_Power, textureData3.m_geoPower); m_sharedMaterial.SetFloat(_Texture_3_Height_Contrast, textureData3.m_heightContrast); m_sharedMaterial.SetFloat(_Texture_3_Heightmap_Depth, textureData3.m_heightDepth); m_sharedMaterial.SetFloat(_Texture_3_Heightblend_Close, textureData3.m_heightBlendClose); } } } private void GetTexturesAndSettingsAtCurrentLocation() { m_textureList.Clear(); CTSProfile cTSProfile = null; CTSSplatPrototype[] array = new CTSSplatPrototype[0]; Vector3 position = base.transform.position; Vector3 localScale = base.transform.localScale; Vector3 eulerAngles = base.transform.eulerAngles; for (int num = m_filters.Length - 1; num >= 0; num--) { Mesh sharedMesh = m_filters[num].sharedMesh; if (sharedMesh != null) { Vector3[] vertices = sharedMesh.vertices; for (int num2 = vertices.Length - 1; num2 >= 0; num2--) { Vector3 locationWU = position + Quaternion.Euler(eulerAngles) * Vector3.Scale(vertices[num2], localScale); Terrain terrain = GetTerrain(locationWU); if (terrain != null) { if (cTSProfile == null) { CompleteTerrainShader component = terrain.gameObject.GetComponent(); if (component != null) { cTSProfile = component.Profile; } } if (array.Length == 0) { array = CTSSplatPrototype.GetCTSSplatPrototypes(terrain); } Vector3 localPosition = GetLocalPosition(terrain, locationWU); float[,,] texturesAtLocation = GetTexturesAtLocation(terrain, localPosition); for (int i = 0; i < texturesAtLocation.GetLength(2); i++) { if (i == m_textureList.Count) { TextureData textureData = new TextureData(); textureData.m_terrainIdx = i; textureData.m_terrainTextureStrength = texturesAtLocation[0, 0, i]; m_textureList.Add(textureData); } else { m_textureList[i].m_terrainTextureStrength += texturesAtLocation[0, 0, i]; } } } } } } List list = m_textureList.OrderByDescending((TextureData x) => x.m_terrainTextureStrength).ToList(); while (list.Count > 3) { list.RemoveAt(list.Count - 1); } m_textureList = list.OrderBy((TextureData x) => x.m_terrainIdx).ToList(); if (cTSProfile != null) { m_geoMap = cTSProfile.GeoAlbedo; m_geoMapClosePower = cTSProfile.m_geoMapClosePower; m_geoMapOffsetClose = cTSProfile.m_geoMapCloseOffset; m_geoTilingClose = cTSProfile.m_geoMapTilingClose; m_smoothness = cTSProfile.m_globalTerrainSmoothness; m_specular = cTSProfile.m_globalTerrainSpecular; switch (cTSProfile.m_globalAOType) { case CTSConstants.AOType.None: m_useAO = false; m_useAOTexture = false; break; case CTSConstants.AOType.NormalMapBased: m_useAO = true; m_useAOTexture = false; break; case CTSConstants.AOType.TextureBased: m_useAO = true; m_useAOTexture = true; break; } } else { m_geoMap = null; m_geoMapClosePower = 0f; m_geoMapOffsetClose = 0f; m_geoTilingClose = 0f; m_smoothness = 1f; m_specular = 1f; m_useAO = true; m_useAOTexture = false; } byte minHeight = 0; byte maxHeight = 0; for (int num3 = 0; num3 < m_textureList.Count; num3++) { TextureData textureData2 = m_textureList[num3]; if (cTSProfile != null && textureData2.m_terrainIdx < cTSProfile.TerrainTextures.Count) { CTSTerrainTextureDetails cTSTerrainTextureDetails = cTSProfile.TerrainTextures[textureData2.m_terrainIdx]; textureData2.m_albedo = cTSTerrainTextureDetails.Albedo; textureData2.m_normal = cTSTerrainTextureDetails.Normal; textureData2.m_hao_in_GA = cTSProfile.BakeHAOTexture(cTSTerrainTextureDetails.Albedo.name, cTSTerrainTextureDetails.Height, cTSTerrainTextureDetails.AmbientOcclusion, out minHeight, out maxHeight); textureData2.m_aoPower = cTSTerrainTextureDetails.m_aoPower; textureData2.m_color = new Vector4(cTSTerrainTextureDetails.m_tint.r * cTSTerrainTextureDetails.m_tintBrightness, cTSTerrainTextureDetails.m_tint.g * cTSTerrainTextureDetails.m_tintBrightness, cTSTerrainTextureDetails.m_tint.b * cTSTerrainTextureDetails.m_tintBrightness, cTSTerrainTextureDetails.m_smoothness); textureData2.m_geoPower = cTSTerrainTextureDetails.m_geologicalPower; textureData2.m_normalPower = cTSTerrainTextureDetails.m_normalStrength; textureData2.m_tiling = cTSTerrainTextureDetails.m_albedoTilingClose; textureData2.m_heightContrast = cTSTerrainTextureDetails.m_heightContrast; textureData2.m_heightDepth = cTSTerrainTextureDetails.m_heightDepth; textureData2.m_heightBlendClose = cTSTerrainTextureDetails.m_heightBlendClose; } else if (textureData2.m_terrainIdx < array.Length) { CTSSplatPrototype cTSSplatPrototype = array[textureData2.m_terrainIdx]; textureData2.m_albedo = cTSSplatPrototype.texture; textureData2.m_normal = cTSSplatPrototype.normalMap; textureData2.m_hao_in_GA = null; textureData2.m_aoPower = 0f; textureData2.m_color = Vector4.one; textureData2.m_geoPower = 0f; textureData2.m_normalPower = 1f; textureData2.m_tiling = cTSSplatPrototype.tileSize.x; textureData2.m_heightContrast = 1f; textureData2.m_heightDepth = 1f; textureData2.m_heightBlendClose = 1f; } } } private Terrain GetTerrain(Vector3 locationWU) { Terrain activeTerrain = Terrain.activeTerrain; if (activeTerrain != null) { Vector3 position = activeTerrain.GetPosition(); Vector3 vector = position + activeTerrain.terrainData.size; if (locationWU.x >= position.x && locationWU.x <= vector.x && locationWU.z >= position.z && locationWU.z <= vector.z) { return activeTerrain; } } for (int i = 0; i < Terrain.activeTerrains.Length; i++) { activeTerrain = Terrain.activeTerrains[i]; Vector3 position2 = activeTerrain.GetPosition(); Vector3 vector2 = position2 + activeTerrain.terrainData.size; if (locationWU.x >= position2.x && locationWU.x <= vector2.x && locationWU.z >= position2.z && locationWU.z <= vector2.z) { return activeTerrain; } } return null; } private Vector3 GetLocalPosition(Terrain terrain, Vector3 locationWU) { Vector3 vector = terrain.transform.InverseTransformPoint(locationWU); return new Vector3(Mathf.InverseLerp(0f, terrain.terrainData.size.x, vector.x), Mathf.InverseLerp(0f, terrain.terrainData.size.y, vector.y), Mathf.InverseLerp(0f, terrain.terrainData.size.z, vector.z)); } private float[,,] GetTexturesAtLocation(Terrain terrain, Vector3 locationTU) { return terrain.terrainData.GetAlphamaps((int)(locationTU.x * (float)(terrain.terrainData.alphamapWidth - 1)), (int)(locationTU.z * (float)(terrain.terrainData.alphamapHeight - 1)), 1, 1); } private Vector3 GetNormalsAtLocation(Terrain terrain, Vector3 locationTU) { return terrain.terrainData.GetInterpolatedNormal(locationTU.x, locationTU.z); } } }