using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using UnityEngine; using UnityEngine.Rendering; namespace CTS { [Serializable] [RequireComponent(typeof(Terrain))] [AddComponentMenu("CTS/Add CTS To Terrain")] [ExecuteInEditMode] public class CompleteTerrainShader : MonoBehaviour { [Flags] internal enum TerrainChangedFlags { NoChange = 0, Heightmap = 1, TreeInstances = 2, DelayedHeightmapUpdate = 4, FlushEverythingImmediately = 8, RemoveDirtyDetailsImmediately = 0x10, WillBeDestroyed = 0x100 } [SerializeField] private CTSProfile m_profile; [SerializeField] private Texture2D m_normalMap; [SerializeField] private bool m_isProfileConnected = true; [SerializeField] private bool m_materialNeedsReapply; [SerializeField] private string m_lastUsedCTSProfileID = ""; [SerializeField] private string m_persistentSplatGUID1 = ""; [SerializeField] private string m_persistentSplatGUID2 = ""; [SerializeField] private string m_persistentSplatGUID3 = ""; [SerializeField] private string m_persistentSplatGUID4 = ""; [SerializeField] private string m_persistentNormalMapGUID = ""; [SerializeField] private string m_persistentColorMapGUID = ""; [SerializeField] private string m_persistentCutoutMaskGUID = ""; [SerializeField] private bool m_bakeNormalMap = true; [SerializeField] private Texture2D m_colorMap; [SerializeField] private bool m_bakeColorMap; [SerializeField] private bool m_bakeGrassTextures; [SerializeField] private float m_bakeGrassMixStrength = 0.2f; [SerializeField] private float m_bakeGrassDarkenAmount = 0.2f; [SerializeField] private bool m_useCutout; [SerializeField] private Texture2D m_cutoutMask; [SerializeField] private float m_cutoutHeight = 50f; [SerializeField] private Texture2D m_splat1; [SerializeField] private Texture2D m_splat2; [SerializeField] private Texture2D m_splat3; [SerializeField] private Texture2D m_splat4; [SerializeField] public bool m_stripTexturesAtRuntime = true; [NonSerialized] private float[,,] m_splatBackupArray; [SerializeField] private CTSConstants.ShaderType m_activeShaderType; [NonSerialized] private Terrain m_terrain; [NonSerialized] private Material m_material; [NonSerialized] private MaterialPropertyBlock m_materialPropertyBlock; private static string s_ctsDirectory; public CTSProfile Profile { get { return m_profile; } set { if (!m_isProfileConnected) { return; } if (m_terrain == null) { m_terrain = base.transform.GetComponent(); } if (m_profile == null) { m_profile = value; if (m_profile != null) { if (m_profile.TerrainTextures.Count == 0) { UpdateProfileFromTerrainForced(); } else if (TerrainNeedsTextureUpdate()) { ReplaceTerrainTexturesFromProfile(ignoreStripTextures: false); } } } else if (value == null) { m_profile = value; } else { if (m_profile.name != value.name) { m_profile = value; } if (m_profile.TerrainTextures.Count == 0) { UpdateProfileFromTerrainForced(); } else if (TerrainNeedsTextureUpdate()) { ReplaceTerrainTexturesFromProfile(ignoreStripTextures: false); } } if (m_profile != null) { ApplyMaterialAndUpdateShader(); } } } public Texture2D NormalMap { get { return m_normalMap; } set { if (value == null) { if (m_normalMap != null) { m_normalMap = value; SetDirty(this, recordUndo: false, isPlayingAllowed: false); } } else if (m_normalMap == null || m_normalMap.GetInstanceID() != value.GetInstanceID()) { m_normalMap = value; SetDirty(this, recordUndo: false, isPlayingAllowed: false); } } } public bool IsProfileConnected { get { return m_isProfileConnected; } set { m_isProfileConnected = value; } } public bool MaterialNeedsReapply { get { return m_materialNeedsReapply; } set { m_materialNeedsReapply = value; } } public string LastUsedCTSProfileID { get { return m_lastUsedCTSProfileID; } set { m_lastUsedCTSProfileID = value; } } public string PersistentSplatGUID1 { get { return m_persistentSplatGUID1; } set { m_persistentSplatGUID1 = value; } } public string PersistentSplatGUID2 { get { return m_persistentSplatGUID2; } set { m_persistentSplatGUID2 = value; } } public string PersistentSplatGUID3 { get { return m_persistentSplatGUID3; } set { m_persistentSplatGUID3 = value; } } public string PersistentSplatGUID4 { get { return m_persistentSplatGUID4; } set { m_persistentSplatGUID4 = value; } } public string PersistentNormalMapGUID { get { return m_persistentNormalMapGUID; } set { m_persistentNormalMapGUID = value; } } public string PersistentColorMapGUID { get { return m_persistentColorMapGUID; } set { m_persistentColorMapGUID = value; } } public string PersistentCutoutMaskGUID { get { return m_persistentCutoutMaskGUID; } set { m_persistentCutoutMaskGUID = value; } } public bool AutoBakeNormalMap { get { return m_bakeNormalMap; } set { m_bakeNormalMap = value; } } public Texture2D ColorMap { get { return m_colorMap; } set { if (value == null) { if (m_colorMap != null) { m_colorMap = value; SetDirty(this, recordUndo: false, isPlayingAllowed: false); } } else if (m_colorMap == null || m_colorMap.GetInstanceID() != value.GetInstanceID()) { m_colorMap = value; SetDirty(this, recordUndo: false, isPlayingAllowed: false); } } } public bool AutoBakeColorMap { get { return m_bakeColorMap; } set { m_bakeColorMap = value; } } public bool AutoBakeGrassIntoColorMap { get { return m_bakeGrassTextures; } set { m_bakeGrassTextures = value; } } public float AutoBakeGrassMixStrength { get { return m_bakeGrassMixStrength; } set { m_bakeGrassMixStrength = value; } } public float AutoBakeGrassDarkenAmount { get { return m_bakeGrassDarkenAmount; } set { m_bakeGrassDarkenAmount = value; } } public bool UseCutout { get { return m_useCutout; } set { if (m_useCutout != value) { m_useCutout = value; SetDirty(this, recordUndo: false, isPlayingAllowed: false); } } } public Texture2D CutoutMask { get { return m_cutoutMask; } set { if (value == null) { if (m_cutoutMask != null) { m_cutoutMask = value; SetDirty(this, recordUndo: false, isPlayingAllowed: false); } } else if (m_cutoutMask == null || m_cutoutMask.GetInstanceID() != value.GetInstanceID()) { m_cutoutMask = value; SetDirty(this, recordUndo: false, isPlayingAllowed: false); } } } public float CutoutHeight { get { return m_cutoutHeight; } set { if (m_cutoutHeight != value) { m_cutoutHeight = value; SetDirty(this, recordUndo: false, isPlayingAllowed: false); } } } public Texture2D Splat1 { get { return m_splat1; } set { if (value == null) { if (m_splat1 != null) { m_splat1 = value; SetDirty(this, recordUndo: false, isPlayingAllowed: false); } } else if (m_splat1 == null || m_splat1.GetInstanceID() != value.GetInstanceID()) { m_splat1 = value; SetDirty(this, recordUndo: false, isPlayingAllowed: false); } } } public Texture2D Splat2 { get { return m_splat2; } set { if (value == null) { if (m_splat2 != null) { m_splat2 = value; SetDirty(this, recordUndo: false, isPlayingAllowed: false); } } else if (m_splat2 == null || m_splat2.GetInstanceID() != value.GetInstanceID()) { m_splat2 = value; SetDirty(this, recordUndo: false, isPlayingAllowed: false); } } } public Texture2D Splat3 { get { return m_splat3; } set { if (value == null) { if (m_splat3 != null) { m_splat3 = value; SetDirty(this, recordUndo: false, isPlayingAllowed: false); } } else if (m_splat3 == null || m_splat3.GetInstanceID() != value.GetInstanceID()) { m_splat3 = value; SetDirty(this, recordUndo: false, isPlayingAllowed: false); } } } public Texture2D Splat4 { get { return m_splat4; } set { if (value == null) { if (m_splat4 != null) { m_splat4 = value; SetDirty(this, recordUndo: false, isPlayingAllowed: false); } } else if (m_splat4 == null || m_splat4.GetInstanceID() != value.GetInstanceID()) { m_splat4 = value; SetDirty(this, recordUndo: false, isPlayingAllowed: false); } } } private void Awake() { if (m_terrain == null) { m_terrain = base.transform.GetComponent(); if (m_terrain == null) { UnityEngine.Debug.LogWarning("CTS needs a terrain to work!"); } } } private void Start() { } private void OnEnable() { ApplyMaterialAndUpdateShader(); CTSSingleton.Instance.RegisterShader(this); } private void OnDisable() { CTSSingleton.Instance.UnregisterShader(this); } public static UnityEngine.Object GetAsset(string fileNameOrPath, Type assetType) { return null; } public static string GetAssetPath(string fileName) { return ""; } public static Type GetType(string TypeName) { Type type = Type.GetType(TypeName); if (type != null) { return type; } if (TypeName.Contains(".")) { string assemblyString = TypeName.Substring(0, TypeName.IndexOf('.')); try { Assembly assembly = Assembly.Load(assemblyString); if (assembly == null) { return null; } type = assembly.GetType(TypeName); if (type != null) { return type; } } catch (Exception) { } } Assembly callingAssembly = Assembly.GetCallingAssembly(); if (callingAssembly != null) { type = callingAssembly.GetType(TypeName); if (type != null) { return type; } } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.GetLength(0); i++) { type = assemblies[i].GetType(TypeName); if (type != null) { return type; } } AssemblyName[] referencedAssemblies = callingAssembly.GetReferencedAssemblies(); for (int j = 0; j < referencedAssemblies.Length; j++) { Assembly assembly2 = Assembly.Load(referencedAssemblies[j]); if (assembly2 != null) { type = assembly2.GetType(TypeName); if (type != null) { return type; } } } return null; } private void ApplyUnityShader() { if (m_terrain == null) { m_terrain = base.transform.GetComponent(); if (m_terrain == null) { UnityEngine.Debug.LogError("Unable to locate Terrain, apply unity shader cancelled."); return; } } if (Application.isPlaying && m_profile != null && m_splatBackupArray != null && m_splatBackupArray.GetLength(0) > 0) { ReplaceTerrainTexturesFromProfile(ignoreStripTextures: true); m_terrain.terrainData.SetAlphamaps(0, 0, m_splatBackupArray); m_terrain.Flush(); } m_terrain.basemapDistance = 2000f; m_activeShaderType = CTSConstants.ShaderType.Unity; if (GraphicsSettings.renderPipelineAsset == null) { m_terrain.materialType = Terrain.MaterialType.BuiltInStandard; m_terrain.materialTemplate = null; } else { Material defaultTerrainMaterial = GraphicsSettings.renderPipelineAsset.defaultTerrainMaterial; if (defaultTerrainMaterial != null) { m_terrain.materialType = Terrain.MaterialType.Custom; m_terrain.materialTemplate = defaultTerrainMaterial; } else { UnityEngine.Debug.LogWarning("CTS could not find a default terrain material in your current rendering pipeline configuration. Reverting to built-in rendering terrain material."); m_terrain.materialType = Terrain.MaterialType.BuiltInStandard; m_terrain.materialTemplate = null; } } m_material = null; m_materialPropertyBlock = null; } private void ApplyMaterial() { if (m_terrain == null) { m_terrain = base.transform.GetComponent(); if (m_terrain == null) { UnityEngine.Debug.LogWarning("CTS needs terrain to function - exiting!"); return; } } if (m_profile == null) { UnityEngine.Debug.LogWarning("CTS needs a profile to function - applying unity shader and exiting!"); ApplyUnityShader(); return; } if (m_profile.AlbedosTextureArray == null) { UnityEngine.Debug.LogWarning("CTS profile needs albedos texture array to function - applying unity shader and exiting!"); m_profile.m_needsAlbedosArrayUpdate = true; ApplyUnityShader(); return; } if (m_profile.NormalsTextureArray == null) { UnityEngine.Debug.LogWarning("CTS profile needs normals texture array to function - applying unity shader and exiting!"); m_profile.m_needsNormalsArrayUpdate = true; ApplyUnityShader(); return; } if (m_splat1 == null && m_terrain.terrainData.alphamapTextures.Length != 0) { m_splat1 = m_terrain.terrainData.alphamapTextures[0]; } if (m_splat2 == null && m_terrain.terrainData.alphamapTextures.Length > 1) { m_splat2 = m_terrain.terrainData.alphamapTextures[1]; } if (m_splat3 == null && m_terrain.terrainData.alphamapTextures.Length > 2) { m_splat3 = m_terrain.terrainData.alphamapTextures[2]; } if (m_splat4 == null && m_terrain.terrainData.alphamapTextures.Length > 3) { m_splat4 = m_terrain.terrainData.alphamapTextures[3]; } m_materialPropertyBlock = null; m_activeShaderType = m_profile.ShaderType; if (m_activeShaderType == CTSConstants.ShaderType.Unity) { ApplyUnityShader(); return; } CTSConstants.EnvironmentRenderer renderPipeline = GetRenderPipeline(); CTSConstants.ShaderFeatureSet shaderFeatureSet = GetShaderFeatureSet(); CTSShaderCriteria key = new CTSShaderCriteria(renderPipeline, m_profile.ShaderType, shaderFeatureSet); if (CTSConstants.shaderNames.TryGetValue(key, out var value)) { m_material = CTSMaterials.GetMaterial(value, m_profile); if (m_material == null) { UnityEngine.Debug.LogErrorFormat("CTS could not locate shader {0} - exiting!", m_activeShaderType); } else { m_terrain.materialType = Terrain.MaterialType.Custom; m_terrain.materialTemplate = m_material; UpdateTerrainSplatsAtRuntime(); } } else { UnityEngine.Debug.LogErrorFormat("CTS could not find a valid shader for this configuration: -- Render Pipeline: {0} - Shader Type: {1} - Shader Feature Set: {2}", renderPipeline, m_profile.ShaderType, shaderFeatureSet); } } public void ApplyMaterialAndUpdateShader() { if (IsProfileConnected) { if (m_profile == null) { ApplyMaterial(); } else if (m_activeShaderType != m_profile.ShaderType || m_profile.m_currentRenderPipelineType != GetRenderPipeline() || m_materialNeedsReapply) { ApplyMaterial(); m_materialNeedsReapply = false; } if (m_activeShaderType != CTSConstants.ShaderType.Unity) { UpdateShader(); } } } public void UpdateShader() { if (m_terrain == null) { m_terrain = base.transform.GetComponent(); if (m_terrain == null) { UnityEngine.Debug.LogWarning("CTS missing terrain, cannot operate without terrain!"); return; } } if (m_activeShaderType == CTSConstants.ShaderType.Unity) { return; } if (m_profile == null) { UnityEngine.Debug.LogWarning("Missing CTS profile!"); return; } if (m_profile.AlbedosTextureArray == null) { UnityEngine.Debug.LogError("Missing CTS texture array - rebake textures"); return; } if (m_profile.NormalsTextureArray == null) { UnityEngine.Debug.LogError("Missing CTS texture array - rebake textures"); return; } if (CTSSplatPrototype.GetNumberOfTerrainTextures(m_terrain.terrainData) > 16) { UnityEngine.Debug.LogError("Found more than 16 textures on the terrain. CTS supports up to 16 textures, please reduce the texture count on the terrain."); return; } if (m_splat1 == null) { if (m_splat1 == null && m_terrain.terrainData.alphamapTextures.Length != 0) { m_splat1 = m_terrain.terrainData.alphamapTextures[0]; } if (m_splat2 == null && m_terrain.terrainData.alphamapTextures.Length > 1) { m_splat2 = m_terrain.terrainData.alphamapTextures[1]; } if (m_splat3 == null && m_terrain.terrainData.alphamapTextures.Length > 2) { m_splat3 = m_terrain.terrainData.alphamapTextures[2]; } if (m_splat4 == null && m_terrain.terrainData.alphamapTextures.Length > 3) { m_splat4 = m_terrain.terrainData.alphamapTextures[3]; } if (m_splat1 == null) { UnityEngine.Debug.LogError("Missing splat textures - add some textures to your terrain"); return; } } Stopwatch stopwatch = Stopwatch.StartNew(); if (m_activeShaderType != m_profile.ShaderType || m_material == null) { ApplyMaterial(); } if (m_activeShaderType == CTSConstants.ShaderType.Unity) { return; } if (m_activeShaderType != CTSConstants.ShaderType.Unity && m_material == null) { UnityEngine.Debug.LogError("Could not create a valid material for the CTS shader, shader properties can not be updated."); return; } if (m_stripTexturesAtRuntime != m_profile.m_globalStripTexturesAtRuntime) { m_stripTexturesAtRuntime = m_profile.m_globalStripTexturesAtRuntime; SetDirty(this, recordUndo: false, isPlayingAllowed: false); } m_terrain.drawInstanced = false; if (m_terrain.basemapDistance != m_profile.m_globalBasemapDistance) { m_terrain.basemapDistance = m_profile.m_globalBasemapDistance; } m_material.SetTexture(CTSShaderID.Texture_Array_Albedo, m_profile.AlbedosTextureArray); m_material.SetTexture(CTSShaderID.Texture_Array_Normal, m_profile.NormalsTextureArray); m_material.SetFloat(CTSShaderID.UV_Mix_Power, m_profile.m_globalUvMixPower); m_material.SetFloat(CTSShaderID.UV_Mix_Start_Distance, m_profile.m_globalUvMixStartDistance + UnityEngine.Random.Range(0.001f, 0.003f)); m_material.SetFloat(CTSShaderID.Perlin_Normal_Tiling_Close, m_profile.m_globalDetailNormalCloseTiling); m_material.SetFloat(CTSShaderID.Perlin_Normal_Tiling_Far, m_profile.m_globalDetailNormalFarTiling); m_material.SetFloat(CTSShaderID.Perlin_Normal_Power, m_profile.m_globalDetailNormalFarPower); m_material.SetFloat(CTSShaderID.Perlin_Normal_Power_Close, m_profile.m_globalDetailNormalClosePower); m_material.SetFloat(CTSShaderID.Terrain_Smoothness, m_profile.m_globalTerrainSmoothness); m_material.SetFloat(CTSShaderID.Terrain_Specular, m_profile.m_globalTerrainSpecular); m_material.SetFloat(CTSShaderID.TessValue, m_profile.m_globalTesselationPower); m_material.SetFloat(CTSShaderID.TessMin, m_profile.m_globalTesselationMinDistance); m_material.SetFloat(CTSShaderID.TessMax, m_profile.m_globalTesselationMaxDistance); m_material.SetFloat(CTSShaderID.TessPhongStrength, m_profile.m_globalTesselationPhongStrength); m_material.SetFloat(CTSShaderID.TessDistance, m_profile.m_globalTesselationMaxDistance); m_material.SetInt(CTSShaderID.Ambient_Occlusion_Type, (int)m_profile.m_globalAOType); if (m_profile.m_globalAOType == CTSConstants.AOType.None) { m_material.DisableKeyword("_Use_AO_ON"); m_material.DisableKeyword("_USE_AO_TEXTURE_ON"); m_material.SetInt(CTSShaderID.Use_AO, 0); m_material.SetInt(CTSShaderID.Use_AO_Texture, 0); m_material.SetFloat(CTSShaderID.Ambient_Occlusion_Power, 0f); } else if (m_profile.m_globalAOType == CTSConstants.AOType.NormalMapBased) { m_material.DisableKeyword("_USE_AO_TEXTURE_ON"); m_material.SetInt(CTSShaderID.Use_AO_Texture, 0); if (m_profile.m_globalAOPower > 0f) { m_material.EnableKeyword("_USE_AO_ON"); m_material.SetInt(CTSShaderID.Use_AO, 1); m_material.SetFloat(CTSShaderID.Ambient_Occlusion_Power, m_profile.m_globalAOPower); } else { m_material.DisableKeyword("_USE_AO_ON"); m_material.SetInt(CTSShaderID.Use_AO, 0); m_material.SetFloat(CTSShaderID.Ambient_Occlusion_Power, 0f); } } else if (m_profile.m_globalAOPower > 0f) { m_material.EnableKeyword("_USE_AO_ON"); m_material.EnableKeyword("_USE_AO_TEXTURE_ON"); m_material.SetInt(CTSShaderID.Use_AO, 1); m_material.SetInt(CTSShaderID.Use_AO_Texture, 1); m_material.SetFloat(CTSShaderID.Ambient_Occlusion_Power, m_profile.m_globalAOPower); } else { m_material.DisableKeyword("_USE_AO_ON"); m_material.DisableKeyword("_USE_AO_TEXTURE_ON"); m_material.SetInt(CTSShaderID.Use_AO, 0); m_material.SetInt(CTSShaderID.Use_AO_Texture, 0); m_material.SetFloat(CTSShaderID.Ambient_Occlusion_Power, 0f); } if (m_profile.m_globalDetailNormalClosePower > 0f || m_profile.m_globalDetailNormalFarPower > 0f) { m_material.SetInt(CTSShaderID.Texture_Perlin_Normal_Index, m_profile.m_globalDetailNormalMapIdx); } else { m_material.SetInt(CTSShaderID.Texture_Perlin_Normal_Index, -1); } if (m_profile.GeoAlbedo != null) { if (m_profile.m_geoMapClosePower > 0f || m_profile.m_geoMapFarPower > 0f) { m_material.SetFloat(CTSShaderID.Geological_Map_Offset_Close, m_profile.m_geoMapCloseOffset); m_material.SetFloat(CTSShaderID.Geological_Map_Close_Power, m_profile.m_geoMapClosePower); m_material.SetFloat(CTSShaderID.Geological_Tiling_Close, m_profile.m_geoMapTilingClose); m_material.SetFloat(CTSShaderID.Geological_Map_Offset_Far, m_profile.m_geoMapFarOffset); m_material.SetFloat(CTSShaderID.Geological_Map_Far_Power, m_profile.m_geoMapFarPower); m_material.SetFloat(CTSShaderID.Geological_Tiling_Far, m_profile.m_geoMapTilingFar); m_material.SetTexture(CTSShaderID.Texture_Geological_Map, m_profile.GeoAlbedo); } else { m_material.SetFloat(CTSShaderID.Geological_Map_Close_Power, 0f); m_material.SetFloat(CTSShaderID.Geological_Map_Far_Power, 0f); m_material.SetTexture(CTSShaderID.Texture_Geological_Map, null); } } else { m_material.SetFloat(CTSShaderID.Geological_Map_Close_Power, 0f); m_material.SetFloat(CTSShaderID.Geological_Map_Far_Power, 0f); m_material.SetTexture(CTSShaderID.Texture_Geological_Map, null); } m_material.SetFloat(CTSShaderID.Snow_Amount, m_profile.m_snowAmount); m_material.SetInt(CTSShaderID.Texture_Snow_Index, m_profile.m_snowAlbedoTextureIdx); m_material.SetInt(CTSShaderID.Texture_Snow_Normal_Index, m_profile.m_snowNormalTextureIdx); m_material.SetInt(CTSShaderID.Texture_Snow_H_AO_Index, (m_profile.m_snowHeightTextureIdx != -1) ? m_profile.m_snowHeightTextureIdx : m_profile.m_snowAOTextureIdx); m_material.SetTexture(CTSShaderID.Texture_Glitter, m_profile.SnowGlitter); m_material.SetFloat(CTSShaderID.Snow_Maximum_Angle, m_profile.m_snowMaxAngle); m_material.SetFloat(CTSShaderID.Snow_Maximum_Angle_Hardness, m_profile.m_snowMaxAngleHardness); m_material.SetFloat(CTSShaderID.Snow_Min_Height, m_profile.m_snowMinHeight); m_material.SetFloat(CTSShaderID.Snow_Min_Height_Blending, m_profile.m_snowMinHeightBlending); m_material.SetFloat(CTSShaderID.Snow_Noise_Power, m_profile.m_snowNoisePower); m_material.SetFloat(CTSShaderID.Snow_Noise_Tiling, m_profile.m_snowNoiseTiling); m_material.SetFloat(CTSShaderID.Snow_Normal_Scale, m_profile.m_snowNormalScale); m_material.SetFloat(CTSShaderID.Snow_Perlin_Power, m_profile.m_snowDetailPower); m_material.SetFloat(CTSShaderID.Snow_Tiling, m_profile.m_snowTilingClose); m_material.SetFloat(CTSShaderID.Snow_Tiling_Far_Multiplier, m_profile.m_snowTilingFar); m_material.SetFloat(CTSShaderID.Snow_Brightness, m_profile.m_snowBrightness); m_material.SetFloat(CTSShaderID.Snow_Blend_Normal, m_profile.m_snowBlendNormal); m_material.SetFloat(CTSShaderID.Snow_Smoothness, m_profile.m_snowSmoothness); m_material.SetFloat(CTSShaderID.Snow_Specular, m_profile.m_snowSpecular); m_material.SetFloat(CTSShaderID.Snow_Heightblend_Close, m_profile.m_snowHeightmapBlendClose); m_material.SetFloat(CTSShaderID.Snow_Heightblend_Far, m_profile.m_snowHeightmapBlendFar); m_material.SetFloat(CTSShaderID.Snow_Height_Contrast, m_profile.m_snowHeightmapContrast); m_material.SetFloat(CTSShaderID.Snow_Heightmap_Depth, m_profile.m_snowHeightmapDepth); m_material.SetFloat(CTSShaderID.Snow_Heightmap_MinHeight, m_profile.m_snowHeightmapMinValue); m_material.SetFloat(CTSShaderID.Snow_Heightmap_MaxHeight, m_profile.m_snowHeightmapMaxValue); m_material.SetFloat(CTSShaderID.Snow_Ambient_Occlusion_Power, m_profile.m_snowAOStrength); m_material.SetFloat(CTSShaderID.Snow_Tesselation_Depth, m_profile.m_snowTesselationDepth); m_material.SetVector(CTSShaderID.Snow_Color, new Vector4(m_profile.m_snowTint.r * m_profile.m_snowBrightness, m_profile.m_snowTint.g * m_profile.m_snowBrightness, m_profile.m_snowTint.b * m_profile.m_snowBrightness, m_profile.m_snowSmoothness)); m_material.SetVector(CTSShaderID.Texture_Snow_Average, m_profile.m_snowAverage); m_material.SetFloat(CTSShaderID.Glitter_Color_Power, m_profile.m_snowGlitterColorPower); m_material.SetFloat(CTSShaderID.Glitter_Noise_Threshold, m_profile.m_snowGlitterNoiseThreshold); m_material.SetFloat(CTSShaderID.Glitter_Specular, m_profile.m_snowGlitterSpecularPower); m_material.SetFloat(CTSShaderID.Glitter_Smoothness, m_profile.m_snowGlitterSmoothness); m_material.SetFloat(CTSShaderID.Glitter_Refreshing_Speed, m_profile.m_snowGlitterRefreshSpeed); m_material.SetFloat(CTSShaderID.Glitter_Tiling, m_profile.m_snowGlitterTiling); for (int i = 0; i < m_profile.TerrainTextures.Count; i++) { CTSTerrainTextureDetails cTSTerrainTextureDetails = m_profile.TerrainTextures[i]; m_material.SetInt(CTSShaderID.Texture_X_Albedo_Index[i], cTSTerrainTextureDetails.m_albedoIdx); m_material.SetInt(CTSShaderID.Texture_X_Normal_Index[i], cTSTerrainTextureDetails.m_normalIdx); m_material.SetInt(CTSShaderID.Texture_X_H_AO_Index[i], (cTSTerrainTextureDetails.m_heightIdx != -1) ? cTSTerrainTextureDetails.m_heightIdx : cTSTerrainTextureDetails.m_aoIdx); m_material.SetFloat(CTSShaderID.Texture_X_Tiling[i], cTSTerrainTextureDetails.m_albedoTilingClose); m_material.SetFloat(CTSShaderID.Texture_X_Far_Multiplier[i], cTSTerrainTextureDetails.m_albedoTilingFar); m_material.SetFloat(CTSShaderID.Texture_X_Perlin_Power[i], cTSTerrainTextureDetails.m_detailPower); m_material.SetFloat(CTSShaderID.Texture_X_Snow_Reduction[i], cTSTerrainTextureDetails.m_snowReductionPower); m_material.SetFloat(CTSShaderID.Texture_X_Geological_Power[i], cTSTerrainTextureDetails.m_geologicalPower); m_material.SetFloat(CTSShaderID.Texture_X_Heightmap_Depth[i], cTSTerrainTextureDetails.m_heightDepth); m_material.SetFloat(CTSShaderID.Texture_X_Height_Contrast[i], cTSTerrainTextureDetails.m_heightContrast); m_material.SetFloat(CTSShaderID.Texture_X_Heightblend_Close[i], cTSTerrainTextureDetails.m_heightBlendClose); m_material.SetFloat(CTSShaderID.Texture_X_Heightblend_Far[i], cTSTerrainTextureDetails.m_heightBlendFar); m_material.SetFloat(CTSShaderID.Texture_X_Tesselation_Depth[i], cTSTerrainTextureDetails.m_heightTesselationDepth); m_material.SetFloat(CTSShaderID.Texture_X_Heightmap_MinHeight[i], cTSTerrainTextureDetails.m_heightMin); m_material.SetFloat(CTSShaderID.Texture_X_Heightmap_MaxHeight[i], cTSTerrainTextureDetails.m_heightMax); m_material.SetFloat(CTSShaderID.Texture_X_AO_Power[i], cTSTerrainTextureDetails.m_aoPower); m_material.SetFloat(CTSShaderID.Texture_X_Normal_Power[i], cTSTerrainTextureDetails.m_normalStrength); m_material.SetFloat(CTSShaderID.Texture_X_Triplanar[i], cTSTerrainTextureDetails.m_triplanar ? 1f : 0f); m_material.SetVector(CTSShaderID.Texture_X_Average[i], cTSTerrainTextureDetails.m_albedoAverage); m_material.SetVector(CTSShaderID.Texture_X_Color[i], 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)); } for (int j = m_profile.TerrainTextures.Count; j < 16; j++) { m_material.SetInt(CTSShaderID.Texture_X_Albedo_Index[j], -1); m_material.SetInt(CTSShaderID.Texture_X_Normal_Index[j], -1); m_material.SetInt(CTSShaderID.Texture_X_H_AO_Index[j], -1); } if (m_profile.m_useMaterialControlBlock) { if (m_materialPropertyBlock == null) { m_materialPropertyBlock = new MaterialPropertyBlock(); } m_terrain.GetSplatMaterialPropertyBlock(m_materialPropertyBlock); m_materialPropertyBlock.SetTexture(CTSShaderID.Texture_Splat_1, m_splat1); if (m_splat2 != null) { m_materialPropertyBlock.SetTexture(CTSShaderID.Texture_Splat_2, m_splat2); } if (m_splat3 != null) { m_materialPropertyBlock.SetTexture(CTSShaderID.Texture_Splat_3, m_splat3); } if (m_splat4 != null) { m_materialPropertyBlock.SetTexture(CTSShaderID.Texture_Splat_4, m_splat4); } m_materialPropertyBlock.SetFloat(CTSShaderID.Remove_Vert_Height, m_cutoutHeight); if (m_cutoutMask != null) { m_materialPropertyBlock.SetTexture(CTSShaderID.Texture_Additional_Masks, m_cutoutMask); } if (NormalMap != null) { m_materialPropertyBlock.SetFloat(CTSShaderID.Global_Normalmap_Power, m_profile.m_globalNormalPower); if (m_profile.m_globalNormalPower > 0f && NormalMap != null) { m_materialPropertyBlock.SetTexture(CTSShaderID.Global_Normal_Map, NormalMap); } } else { m_materialPropertyBlock.SetFloat(CTSShaderID.Global_Normalmap_Power, 0f); } if (ColorMap != null) { m_materialPropertyBlock.SetFloat(CTSShaderID.Global_Color_Map_Far_Power, m_profile.m_colorMapFarPower); m_materialPropertyBlock.SetFloat(CTSShaderID.Global_Color_Map_Close_Power, m_profile.m_colorMapClosePower); m_materialPropertyBlock.SetFloat(CTSShaderID.Global_Color_Opacity_Power, m_profile.m_colorMapOpacity); if (m_profile.m_colorMapFarPower > 0f || m_profile.m_colorMapClosePower > 0f) { m_materialPropertyBlock.SetTexture(CTSShaderID.Global_Color_Map, ColorMap); } } else { m_materialPropertyBlock.SetFloat(CTSShaderID.Global_Color_Map_Far_Power, 0f); m_materialPropertyBlock.SetFloat(CTSShaderID.Global_Color_Map_Close_Power, 0f); m_materialPropertyBlock.SetFloat(CTSShaderID.Global_Color_Opacity_Power, 0f); } m_terrain.SetSplatMaterialPropertyBlock(m_materialPropertyBlock); } else { m_material.SetTexture(CTSShaderID.Texture_Splat_1, m_splat1); if (m_splat2 != null) { m_material.SetTexture(CTSShaderID.Texture_Splat_2, m_splat2); } if (m_splat3 != null) { m_material.SetTexture(CTSShaderID.Texture_Splat_3, m_splat3); } if (m_splat4 != null) { m_material.SetTexture(CTSShaderID.Texture_Splat_4, m_splat4); } m_material.SetFloat(CTSShaderID.Remove_Vert_Height, m_cutoutHeight); if (m_cutoutMask != null) { m_material.SetTexture(CTSShaderID.Texture_Additional_Masks, m_cutoutMask); } if (NormalMap != null) { m_material.SetFloat(CTSShaderID.Global_Normalmap_Power, m_profile.m_globalNormalPower); if (m_profile.m_globalNormalPower > 0f && NormalMap != null) { m_material.SetTexture(CTSShaderID.Global_Normal_Map, NormalMap); } } else { m_material.SetFloat(CTSShaderID.Global_Normalmap_Power, 0f); } if (ColorMap != null) { m_material.SetFloat(CTSShaderID.Global_Color_Map_Far_Power, m_profile.m_colorMapFarPower); m_material.SetFloat(CTSShaderID.Global_Color_Map_Close_Power, m_profile.m_colorMapClosePower); m_material.SetFloat(CTSShaderID.Global_Color_Opacity_Power, m_profile.m_colorMapOpacity); if (m_profile.m_colorMapFarPower > 0f || m_profile.m_colorMapClosePower > 0f) { m_material.SetTexture(CTSShaderID.Global_Color_Map, ColorMap); } } else { m_material.SetFloat(CTSShaderID.Global_Color_Map_Far_Power, 0f); m_material.SetFloat(CTSShaderID.Global_Color_Map_Close_Power, 0f); m_material.SetFloat(CTSShaderID.Global_Color_Opacity_Power, 0f); } } _ = stopwatch.ElapsedMilliseconds; _ = 5; } public void UpdateProfileFromTerrainForced() { if (m_terrain == null) { m_terrain = base.transform.GetComponent(); if (m_terrain == null) { UnityEngine.Debug.LogError("CTS is missing terrain, cannot update."); return; } } if (CTSSplatPrototype.GetNumberOfTerrainTextures(m_terrain.terrainData) > 16) { UnityEngine.Debug.LogError("Found more than 16 textures on the terrain. CTS supports up to 16 textures, please reduce the texture count on the terrain."); return; } m_profile.UpdateSettingsFromTerrain(m_terrain, forceUpdate: true); ApplyMaterialAndUpdateShader(); } private bool ProfileNeedsTextureUpdate() { if (m_terrain == null) { m_terrain = base.transform.GetComponent(); } if (m_terrain == null) { UnityEngine.Debug.LogWarning("No terrain , unable to check if needs texture update"); return false; } if (m_profile == null) { UnityEngine.Debug.LogWarning("No profile, unable to check if needs texture update"); return false; } if (m_profile.TerrainTextures.Count == 0) { return false; } CTSSplatPrototype[] cTSSplatPrototypes = CTSSplatPrototype.GetCTSSplatPrototypes(m_terrain); if (m_profile.TerrainTextures.Count != cTSSplatPrototypes.Length) { return true; } for (int i = 0; i < cTSSplatPrototypes.Length; i++) { CTSTerrainTextureDetails cTSTerrainTextureDetails = m_profile.TerrainTextures[i]; CTSSplatPrototype cTSSplatPrototype = cTSSplatPrototypes[i]; if (cTSTerrainTextureDetails.Albedo == null) { if (cTSSplatPrototype.texture != null) { return true; } } else { if (cTSSplatPrototype.texture == null) { return true; } if (cTSTerrainTextureDetails.Albedo.name != cTSSplatPrototype.texture.name) { return true; } } if (cTSTerrainTextureDetails.Normal == null) { if (cTSSplatPrototype.normalMap != null) { return true; } continue; } if (cTSSplatPrototype.normalMap == null) { return true; } if (cTSTerrainTextureDetails.Normal.name != cTSSplatPrototype.normalMap.name) { return true; } } return false; } private bool TerrainNeedsTextureUpdate() { if (m_terrain == null) { m_terrain = base.transform.GetComponent(); } if (m_terrain == null) { UnityEngine.Debug.LogWarning("No terrain , unable to check if needs texture update"); return false; } if (m_profile == null) { UnityEngine.Debug.LogWarning("No profile, unable to check if needs texture update"); return false; } if (m_profile.TerrainTextures.Count == 0) { return false; } CTSSplatPrototype[] cTSSplatPrototypes = CTSSplatPrototype.GetCTSSplatPrototypes(m_terrain); if (m_profile.TerrainTextures.Count != cTSSplatPrototypes.Length) { return true; } for (int i = 0; i < cTSSplatPrototypes.Length; i++) { CTSTerrainTextureDetails cTSTerrainTextureDetails = m_profile.TerrainTextures[i]; CTSSplatPrototype cTSSplatPrototype = cTSSplatPrototypes[i]; if (cTSTerrainTextureDetails.Albedo == null) { if (cTSSplatPrototype.texture != null) { return true; } } else { if (cTSSplatPrototype.texture == null) { return true; } if (cTSTerrainTextureDetails.Albedo.name != cTSSplatPrototype.texture.name) { return true; } if (cTSTerrainTextureDetails.m_albedoTilingClose != cTSSplatPrototype.tileSize.x) { return true; } } if (cTSTerrainTextureDetails.Normal == null) { if (cTSSplatPrototype.normalMap != null) { return true; } continue; } if (cTSSplatPrototype.normalMap == null) { return true; } if (cTSTerrainTextureDetails.Normal.name != cTSSplatPrototype.normalMap.name) { return true; } } return false; } public void ReplaceAlbedoInTerrain(Texture2D texture, int textureIdx, float tiling) { if (m_terrain == null) { m_terrain = base.transform.GetComponent(); } if (m_terrain != null) { CTSSplatPrototype[] cTSSplatPrototypes = CTSSplatPrototype.GetCTSSplatPrototypes(m_terrain); if (textureIdx >= 0 && textureIdx < cTSSplatPrototypes.Length) { cTSSplatPrototypes[textureIdx].texture = texture; cTSSplatPrototypes[textureIdx].tileSize = new Vector2(tiling, tiling); CTSSplatPrototype.SetCTSSplatPrototypes(m_terrain, cTSSplatPrototypes, ref m_profile); m_terrain.Flush(); SetDirty(m_terrain, recordUndo: false, isPlayingAllowed: false); } else { UnityEngine.Debug.LogWarning("Invalid texture index in replace albedo"); } } } public void ReplaceNormalInTerrain(Texture2D texture, int textureIdx, float tiling) { if (m_terrain == null) { m_terrain = base.transform.GetComponent(); } if (m_terrain != null) { CTSSplatPrototype[] cTSSplatPrototypes = CTSSplatPrototype.GetCTSSplatPrototypes(m_terrain); if (textureIdx >= 0 && textureIdx < cTSSplatPrototypes.Length) { cTSSplatPrototypes[textureIdx].normalMap = texture; cTSSplatPrototypes[textureIdx].tileSize = new Vector2(tiling, tiling); CTSSplatPrototype.SetCTSSplatPrototypes(m_terrain, cTSSplatPrototypes, ref m_profile); m_terrain.Flush(); SetDirty(m_terrain, recordUndo: false, isPlayingAllowed: false); } else { UnityEngine.Debug.LogWarning("Invalid texture index in replace normal!"); } } } public void BakeTerrainNormals() { if (m_terrain == null) { m_terrain = base.transform.GetComponent(); } if (m_terrain == null) { UnityEngine.Debug.LogWarning("Could not make terrain normal, as terrain object not set."); return; } Texture2D texture2D = CalculateNormals(m_terrain); texture2D.name = m_terrain.name + " Nrm"; NormalMap = texture2D; } public Texture2D CalculateNormals(Terrain terrain) { int heightmapResolution = terrain.terrainData.heightmapResolution; int heightmapResolution2 = terrain.terrainData.heightmapResolution; float num = 1f / ((float)heightmapResolution - 1f); float num2 = 1f / ((float)heightmapResolution2 - 1f); float num3 = (float)heightmapResolution / 2f; float num4 = num3 / (float)heightmapResolution; float num5 = num3 / (float)heightmapResolution2; float[] array = new float[heightmapResolution * heightmapResolution2]; Buffer.BlockCopy(terrain.terrainData.GetHeights(0, 0, heightmapResolution, heightmapResolution2), 0, array, 0, array.Length * 4); Texture2D texture2D = new Texture2D(heightmapResolution, heightmapResolution2, TextureFormat.RGBAFloat, mipChain: false, linear: true); Vector3 vector = default(Vector3); Color color = default(Color); for (int i = 0; i < heightmapResolution2; i++) { for (int j = 0; j < heightmapResolution; j++) { int num6 = ((j == heightmapResolution - 1) ? j : (j + 1)); int num7 = ((j == 0) ? j : (j - 1)); int num8 = ((i == heightmapResolution2 - 1) ? i : (i + 1)); int num9 = ((i == 0) ? i : (i - 1)); float num10 = array[num7 + i * heightmapResolution] * num4; float num11 = array[num6 + i * heightmapResolution] * num4; float num12 = array[j + num9 * heightmapResolution] * num5; float num13 = array[j + num8 * heightmapResolution] * num5; float num14 = (num11 - num10) / (2f * num); float num15 = (num13 - num12) / (2f * num2); vector.x = 0f - num14; vector.y = 0f - num15; vector.z = 1f; vector.Normalize(); color.r = vector.x * 0.5f + 0.5f; color.g = vector.y * 0.5f + 0.5f; color.b = vector.z; color.a = 1f; texture2D.SetPixel(j, i, color); } } texture2D.Apply(); return texture2D; } public void BakeTerrainBaseMap() { if (m_terrain == null) { m_terrain = base.transform.GetComponent(); } if (m_terrain == null) { UnityEngine.Debug.LogWarning("Could not make terrain base map, as terrain object not set."); return; } int num = 2048; int num2 = 2048; Texture2D[] alphamapTextures = m_terrain.terrainData.alphamapTextures; CTSSplatPrototype[] cTSSplatPrototypes = CTSSplatPrototype.GetCTSSplatPrototypes(m_terrain); if (alphamapTextures.Length != 0) { num = alphamapTextures[0].width; num2 = alphamapTextures[0].height; } Color[] array = new Color[cTSSplatPrototypes.Length]; for (int i = 0; i < cTSSplatPrototypes.Length; i++) { Texture2D texture2D = CTSProfile.ResizeTexture(cTSSplatPrototypes[i].texture, TextureFormat.ARGB32, 8, num, num2, mipmap: true, linear: false, compress: false); Color[] pixels = texture2D.GetPixels(texture2D.mipmapCount - 1); array[i] = new Color(pixels[0].r, pixels[0].g, pixels[0].b, pixels[0].a); } Texture2D texture2D2 = new Texture2D(num, num2, TextureFormat.RGBA32, mipChain: false); texture2D2.name = m_terrain.name + "_BaseMap"; texture2D2.wrapMode = TextureWrapMode.Repeat; texture2D2.filterMode = FilterMode.Bilinear; texture2D2.anisoLevel = 8; for (int j = 0; j < num; j++) { for (int k = 0; k < num2; k++) { int num3 = 0; Color color = Color.black; for (int l = 0; l < alphamapTextures.Length; l++) { Color pixel = alphamapTextures[l].GetPixel(j, k); if (num3 < array.Length) { color = Color.Lerp(color, array[num3++], pixel.r); } if (num3 < array.Length) { color = Color.Lerp(color, array[num3++], pixel.g); } if (num3 < array.Length) { color = Color.Lerp(color, array[num3++], pixel.b); } if (num3 < array.Length) { color = Color.Lerp(color, array[num3++], pixel.a); } color.a = 1f; } texture2D2.SetPixel(j, k, color); } } texture2D2.Apply(); ColorMap = texture2D2; } public void BakeTerrainBaseMapWithGrass() { if (m_terrain == null) { m_terrain = base.transform.GetComponent(); } if (m_terrain == null) { UnityEngine.Debug.LogWarning("Could not make terrain base map, as terrain object not set."); return; } int num = 2048; int num2 = 2048; Texture2D[] alphamapTextures = m_terrain.terrainData.alphamapTextures; CTSSplatPrototype[] cTSSplatPrototypes = CTSSplatPrototype.GetCTSSplatPrototypes(m_terrain); if (alphamapTextures.Length != 0) { num = alphamapTextures[0].width; num2 = alphamapTextures[0].height; } Color[] array = new Color[cTSSplatPrototypes.Length]; for (int i = 0; i < cTSSplatPrototypes.Length; i++) { Texture2D texture2D = CTSProfile.ResizeTexture(cTSSplatPrototypes[i].texture, TextureFormat.ARGB32, 8, num, num2, mipmap: true, linear: false, compress: false); Color[] pixels = texture2D.GetPixels(texture2D.mipmapCount - 1); array[i] = new Color(pixels[0].r, pixels[0].g, pixels[0].b, pixels[0].a); } List list = new List(); DetailPrototype[] detailPrototypes = m_terrain.terrainData.detailPrototypes; List list2 = new List(); int detailWidth = m_terrain.terrainData.detailWidth; int detailHeight = m_terrain.terrainData.detailHeight; for (int j = 0; j < detailPrototypes.Length; j++) { DetailPrototype detailPrototype = detailPrototypes[j]; if (!detailPrototype.usePrototypeMesh && detailPrototype.prototypeTexture != null) { list2.Add(new CTSHeightMap(m_terrain.terrainData.GetDetailLayer(0, 0, detailWidth, detailHeight, j))); Texture2D texture2D2 = CTSProfile.ResizeTexture(detailPrototype.prototypeTexture, TextureFormat.ARGB32, 8, detailWidth, detailHeight, mipmap: true, linear: false, compress: false); Color[] pixels2 = texture2D2.GetPixels(texture2D2.mipmapCount - 1); Color a = new Color(pixels2[0].r, pixels2[0].g, pixels2[0].b, 1f); Color b = Color.Lerp(detailPrototype.healthyColor, detailPrototype.dryColor, 0.2f); a = Color.Lerp(a, b, 0.3f); list.Add(a); } } Texture2D texture2D3 = new Texture2D(num, num2, TextureFormat.RGBA32, mipChain: false); texture2D3.name = m_terrain.name + "_BaseMap"; texture2D3.wrapMode = TextureWrapMode.Repeat; texture2D3.filterMode = FilterMode.Bilinear; texture2D3.anisoLevel = 8; for (int k = 0; k < num; k++) { for (int l = 0; l < num2; l++) { int num3 = 0; Color color = Color.black; for (int m = 0; m < alphamapTextures.Length; m++) { Color pixel = alphamapTextures[m].GetPixel(k, l); if (num3 < array.Length) { color = Color.Lerp(color, array[num3++], pixel.r); } if (num3 < array.Length) { color = Color.Lerp(color, array[num3++], pixel.g); } if (num3 < array.Length) { color = Color.Lerp(color, array[num3++], pixel.b); } if (num3 < array.Length) { color = Color.Lerp(color, array[num3++], pixel.a); } } for (int n = 0; n < list.Count; n++) { float t = list2[n][(float)l / (float)num2, (float)k / (float)num] * m_bakeGrassMixStrength; color = Color.Lerp(color, Color.Lerp(list[n], Color.black, m_bakeGrassDarkenAmount), t); } color.a = 1f; texture2D3.SetPixel(k, l, color); } } texture2D3.Apply(); ColorMap = texture2D3; } private void UpdateTerrainSplatsAtRuntime() { if (!Application.isPlaying || m_terrain == null) { return; } m_terrain.drawInstanced = false; if (m_profile != null) { m_stripTexturesAtRuntime = m_profile.m_globalStripTexturesAtRuntime; } if (!m_stripTexturesAtRuntime) { return; } if (m_splatBackupArray == null || m_splatBackupArray.GetLength(0) == 0) { m_splatBackupArray = m_terrain.terrainData.GetAlphamaps(0, 0, m_terrain.terrainData.alphamapWidth, m_terrain.terrainData.alphamapHeight); } if (m_terrain.materialType == Terrain.MaterialType.Custom && !m_terrain.terrainData.name.EndsWith("_copy")) { TerrainData terrainData = new TerrainData(); terrainData.name = m_terrain.terrainData.name + "_copy"; terrainData.thickness = m_terrain.terrainData.thickness; terrainData.alphamapResolution = m_terrain.terrainData.alphamapResolution; terrainData.baseMapResolution = m_terrain.terrainData.baseMapResolution; terrainData.SetDetailResolution(m_terrain.terrainData.detailResolution, m_terrain.terrainData.detailResolutionPerPatch); terrainData.detailPrototypes = m_terrain.terrainData.detailPrototypes; for (int i = 0; i < terrainData.detailPrototypes.Length; i++) { terrainData.SetDetailLayer(0, 0, i, m_terrain.terrainData.GetDetailLayer(0, 0, terrainData.detailResolution, terrainData.detailResolution, i)); } terrainData.wavingGrassAmount = m_terrain.terrainData.wavingGrassAmount; terrainData.wavingGrassSpeed = m_terrain.terrainData.wavingGrassSpeed; terrainData.wavingGrassStrength = m_terrain.terrainData.wavingGrassStrength; terrainData.wavingGrassTint = m_terrain.terrainData.wavingGrassTint; terrainData.treePrototypes = m_terrain.terrainData.treePrototypes; terrainData.treeInstances = m_terrain.terrainData.treeInstances; terrainData.heightmapResolution = m_terrain.terrainData.heightmapResolution; terrainData.SetHeights(0, 0, m_terrain.terrainData.GetHeights(0, 0, terrainData.heightmapResolution, terrainData.heightmapResolution)); terrainData.size = m_terrain.terrainData.size; m_terrain.terrainData = terrainData; m_terrain.Flush(); TerrainCollider component = m_terrain.gameObject.GetComponent(); if (component != null) { component.terrainData = terrainData; } } } private void ReplaceTerrainTexturesFromProfile(bool ignoreStripTextures) { if (m_terrain == null) { m_terrain = base.transform.GetComponent(); if (m_terrain == null) { return; } } if (m_profile == null) { UnityEngine.Debug.LogWarning("No profile, unable to replace terrain textures"); return; } if (m_profile.TerrainTextures.Count == 0) { UnityEngine.Debug.LogWarning("No profile textures, unable to replace terrain textures"); return; } m_stripTexturesAtRuntime = m_profile.m_globalStripTexturesAtRuntime; if (!Application.isPlaying || ignoreStripTextures || !m_stripTexturesAtRuntime) { CTSSplatPrototype[] array = new CTSSplatPrototype[m_profile.TerrainTextures.Count]; for (int i = 0; i < array.Length; i++) { array[i] = default(CTSSplatPrototype); array[i].texture = m_profile.TerrainTextures[i].Albedo; array[i].normalMap = m_profile.TerrainTextures[i].Normal; array[i].tileSize = new Vector2(m_profile.TerrainTextures[i].m_albedoTilingClose, m_profile.TerrainTextures[i].m_albedoTilingClose); } CTSSplatPrototype.SetCTSSplatPrototypes(m_terrain, array, ref m_profile); m_terrain.Flush(); SetDirty(m_terrain, recordUndo: false, isPlayingAllowed: false); } } public static string GetCTSDirectory() { if (string.IsNullOrEmpty(s_ctsDirectory)) { s_ctsDirectory = "Assets/CTS/"; } return s_ctsDirectory; } public static void SetDirty(UnityEngine.Object obj, bool recordUndo, bool isPlayingAllowed) { } public void RemoveWorldSeams() { Terrain[] activeTerrains = Terrain.activeTerrains; if (activeTerrains.Length == 0) { return; } float x = activeTerrains[0].terrainData.size.x; float z = activeTerrains[0].terrainData.size.z; float num = float.MaxValue; float num2 = float.MinValue; float num3 = float.MaxValue; float num4 = -2.1474836E+09f; Terrain[] array = activeTerrains; for (int i = 0; i < array.Length; i++) { Vector3 position = array[i].GetPosition(); if (position.x < num) { num = position.x; } if (position.z < num3) { num3 = position.z; } if (position.x > num2) { num2 = position.x; } if (position.z > num4) { num4 = position.z; } } int num5 = (int)((num2 - num) / x) + 1; int num6 = (int)((num4 - num3) / z) + 1; Terrain[,] array2 = new Terrain[num5, num6]; array = activeTerrains; foreach (Terrain terrain in array) { Vector3 position2 = terrain.GetPosition(); int num7 = num5 - (int)((num2 - position2.x) / x) - 1; int num8 = num6 - (int)((num4 - position2.z) / z) - 1; array2[num7, num8] = terrain; } for (int j = 0; j < num5; j++) { for (int k = 0; k < num6; k++) { Terrain right = null; Terrain left = null; Terrain bottom = null; Terrain top = null; if (j > 0) { left = array2[j - 1, k]; } if (j < num5 - 1) { right = array2[j + 1, k]; } if (k > 0) { bottom = array2[j, k - 1]; } if (k < num6 - 1) { top = array2[j, k + 1]; } array2[j, k].allowAutoConnect = true; array2[j, k].SetNeighbors(left, top, right, bottom); } } } public CTSConstants.ShaderFeatureSet GetShaderFeatureSet() { if (m_useCutout) { return CTSConstants.ShaderFeatureSet.Cutout; } return CTSConstants.ShaderFeatureSet.None; } public static CTSConstants.EnvironmentRenderer GetRenderPipeline() { if (GraphicsSettings.renderPipelineAsset == null) { return CTSConstants.EnvironmentRenderer.BuiltIn; } string text = GraphicsSettings.renderPipelineAsset.GetType().Name; if (!(text == "LightweightRenderPipelineAsset")) { if (text == "HDRenderPipelineAsset") { return CTSConstants.EnvironmentRenderer.HighDefinition2018x; } return CTSConstants.EnvironmentRenderer.BuiltIn; } return CTSConstants.EnvironmentRenderer.LightWeight2018x; } } }