using System; using System.Collections.Generic; using System.IO; using UnityEngine; namespace CTS { [Serializable] public class CTSProfile : ScriptableObject { [SerializeField] private int m_ctsMajorVersion = CTSConstants.MajorVersion; [SerializeField] private int m_ctsMinorVersion = CTSConstants.MinorVersion; [SerializeField] private int m_ctsPatchVersion = CTSConstants.PatchVersion; public bool m_useMaterialControlBlock; public bool m_showGlobalSettings = true; public bool m_showSnowSettings; public bool m_showTextureSettings; public bool m_showGeoSettings; public bool m_showDetailSettings; public bool m_showColorMapSettings; public bool m_showOptimisationSettings; public string m_ctsDirectory = "Assets/CTS/"; [SerializeField] private CTSConstants.ShaderType m_shaderType = CTSConstants.ShaderType.Basic; [HideInInspector] [SerializeField] public CTSConstants.EnvironmentRenderer m_currentRenderPipelineType; public float m_globalUvMixPower = 3f; public float m_globalUvMixStartDistance = 400f; public float m_globalNormalPower = 0.1f; public float m_globalDetailNormalClosePower; public float m_globalDetailNormalCloseTiling = 60f; public float m_globalDetailNormalFarPower; public float m_globalDetailNormalFarTiling = 300f; public float m_globalTerrainSmoothness = 1f; public float m_globalTerrainSpecular = 1f; public float m_globalTesselationPower = 7f; public float m_globalTesselationMinDistance; public float m_globalTesselationMaxDistance = 50f; public float m_globalTesselationPhongStrength = 1f; public CTSConstants.AOType m_globalAOType = CTSConstants.AOType.NormalMapBased; public float m_globalAOPower = 1f; public float m_globalBasemapDistance = 1000f; public bool m_globalStripTexturesAtRuntime = true; public string m_terrainLayerPath = ""; public float m_colorMapClosePower; public float m_colorMapFarPower; public float m_colorMapOpacity = 1f; public float m_geoMapCloseOffset; public float m_geoMapClosePower; public float m_geoMapTilingClose = 100f; public float m_geoMapFarOffset; public float m_geoMapFarPower; public float m_geoMapTilingFar = 100f; public float m_snowAmount; public float m_snowMaxAngle = 40f; public float m_snowMaxAngleHardness = 1f; public float m_snowMinHeight = -1000f; public float m_snowMinHeightBlending = 57f; public float m_snowNoisePower = 0.8f; public float m_snowNoiseTiling = 0.02f; public float m_snowNormalScale = 1f; public float m_snowDetailPower = 1f; public float m_snowTilingClose = 6.9f; public float m_snowTilingFar = 3f; public float m_snowBrightness = 1f; public float m_snowBlendNormal = 0.9f; public float m_snowSmoothness = 1f; public Color m_snowTint = new Color(1f, 1f, 1f); public float m_snowSpecular = 1f; public float m_snowHeightmapBlendClose = 1f; public float m_snowHeightmapBlendFar = 1f; public float m_snowHeightmapDepth = 8f; public float m_snowHeightmapContrast = 1f; public float m_snowHeightmapMinValue; public float m_snowHeightmapMaxValue = 1f; public float m_snowTesselationDepth; public float m_snowAOStrength = 1f; public Vector4 m_snowAverage; private static TextureFormat m_workTextureFormat = TextureFormat.RGBA32; public bool terrainLayerAssetRebuild; public TextureFormat m_albedoFormat = TextureFormat.DXT5; public int m_albedoAniso = 8; public FilterMode m_albedoFilterMode = FilterMode.Bilinear; [SerializeField] private CTSConstants.TextureSize m_albedoTextureSize = CTSConstants.TextureSize.Texture_1024; public int m_albedoTextureSizePx = 1024; [SerializeField] private bool m_albedoCompress = true; public TextureFormat m_normalFormat = TextureFormat.DXT5; public int m_normalAniso = 8; public FilterMode m_normalFilterMode = FilterMode.Bilinear; [SerializeField] private CTSConstants.TextureSize m_normalTextureSize = CTSConstants.TextureSize.Texture_1024; public int m_normalTextureSizePx = 1024; [SerializeField] private bool m_normalCompress = true; public int m_globalDetailNormalMapIdx = -1; [SerializeField] private Texture2D m_globalDetailNormalMap; public int m_snowAlbedoTextureIdx = -1; [SerializeField] private Texture2D m_snowAlbedoTexture; public int m_snowNormalTextureIdx = -1; [SerializeField] private Texture2D m_snowNormalTexture; public int m_snowHeightTextureIdx = -1; [SerializeField] private Texture2D m_snowHeightTexture; public int m_snowAOTextureIdx = -1; [SerializeField] private Texture2D m_snowAOTexture; public int m_snowEmissionTextureIdx = -1; [SerializeField] private Texture2D m_snowEmissionTexture; [SerializeField] private Texture2D m_snowGlitterTexture; public float m_snowGlitterColorPower = 0.2f; public float m_snowGlitterNoiseThreshold = 0.991f; public float m_snowGlitterSpecularPower = 0.2f; public float m_snowGlitterSmoothness = 0.9f; public float m_snowGlitterRefreshSpeed = 4f; public float m_snowGlitterTiling = 2.5f; [SerializeField] private Texture2D m_geoAlbedoTexture; [SerializeField] private List m_terrainTextures = new List(); [SerializeField] private List m_replacementTerrainAlbedos = new List(); [SerializeField] private List m_replacementTerrainNormals = new List(); [SerializeField] private Texture2DArray m_albedosTextureArray; public bool m_needsAlbedosArrayUpdate; [SerializeField] private Texture2DArray m_normalsTextureArray; public bool m_needsNormalsArrayUpdate; [SerializeField] public TerrainLayer[] cachedTerrainLayers; public int MajorVersion { get { return m_ctsMajorVersion; } set { if (!m_ctsMajorVersion.Equals(value)) { m_ctsMajorVersion = value; m_needsAlbedosArrayUpdate = true; m_needsNormalsArrayUpdate = true; } } } public int MinorVersion { get { return m_ctsMinorVersion; } set { if (!m_ctsMinorVersion.Equals(value)) { m_ctsMinorVersion = value; m_needsAlbedosArrayUpdate = true; m_needsNormalsArrayUpdate = true; } } } public int PatchVersion { get { return m_ctsPatchVersion; } set { if (!m_ctsPatchVersion.Equals(value)) { m_ctsPatchVersion = value; m_needsAlbedosArrayUpdate = true; m_needsNormalsArrayUpdate = true; } } } public CTSConstants.ShaderType ShaderType { get { return m_shaderType; } set { if (m_shaderType != value) { m_shaderType = value; } } } public CTSConstants.TextureSize AlbedoTextureSize { get { return m_albedoTextureSize; } set { if (m_albedoTextureSize != value) { CompleteTerrainShader.SetDirty(this, recordUndo: false, isPlayingAllowed: true); m_albedoTextureSize = value; m_albedoTextureSizePx = CTSConstants.GetTextureSize(m_albedoTextureSize); m_needsAlbedosArrayUpdate = true; } } } public bool AlbedoCompressionEnabled { get { return m_albedoCompress; } set { if (m_albedoCompress != value) { CompleteTerrainShader.SetDirty(this, recordUndo: false, isPlayingAllowed: true); m_albedoCompress = value; m_needsAlbedosArrayUpdate = true; } } } public CTSConstants.TextureSize NormalTextureSize { get { return m_normalTextureSize; } set { if (m_normalTextureSize != value) { CompleteTerrainShader.SetDirty(this, recordUndo: false, isPlayingAllowed: true); m_normalTextureSize = value; m_normalTextureSizePx = CTSConstants.GetTextureSize(m_normalTextureSize); m_needsNormalsArrayUpdate = true; } } } public bool NormalCompressionEnabled { get { return m_normalCompress; } set { if (m_normalCompress != value) { CompleteTerrainShader.SetDirty(this, recordUndo: false, isPlayingAllowed: true); m_normalCompress = value; m_needsNormalsArrayUpdate = true; } } } public Texture2D GlobalDetailNormalMap { get { return m_globalDetailNormalMap; } set { if (IsDifferentTexture(m_globalDetailNormalMap, value)) { CompleteTerrainShader.SetDirty(this, recordUndo: false, isPlayingAllowed: true); m_globalDetailNormalMap = value; m_needsNormalsArrayUpdate = true; } } } public Texture2D SnowAlbedo { get { return m_snowAlbedoTexture; } set { if (IsDifferentTexture(m_snowAlbedoTexture, value)) { CompleteTerrainShader.SetDirty(this, recordUndo: false, isPlayingAllowed: true); m_snowAlbedoTexture = value; m_needsAlbedosArrayUpdate = true; } } } public Texture2D SnowNormal { get { return m_snowNormalTexture; } set { if (IsDifferentTexture(m_snowNormalTexture, value)) { CompleteTerrainShader.SetDirty(this, recordUndo: false, isPlayingAllowed: true); m_snowNormalTexture = value; m_needsNormalsArrayUpdate = true; } } } public Texture2D SnowHeight { get { return m_snowHeightTexture; } set { if (IsDifferentTexture(m_snowHeightTexture, value)) { CompleteTerrainShader.SetDirty(this, recordUndo: false, isPlayingAllowed: true); m_snowHeightTexture = value; m_needsAlbedosArrayUpdate = true; } } } public Texture2D SnowAmbientOcclusion { get { return m_snowAOTexture; } set { if (IsDifferentTexture(m_snowAOTexture, value)) { CompleteTerrainShader.SetDirty(this, recordUndo: false, isPlayingAllowed: true); m_snowAOTexture = value; m_needsAlbedosArrayUpdate = true; } } } public Texture2D SnowEmission { get { return m_snowEmissionTexture; } set { if (IsDifferentTexture(m_snowEmissionTexture, value)) { CompleteTerrainShader.SetDirty(this, recordUndo: false, isPlayingAllowed: true); m_snowEmissionTexture = value; m_needsAlbedosArrayUpdate = true; } } } public Texture2D SnowGlitter { get { return m_snowGlitterTexture; } set { if (IsDifferentTexture(m_snowGlitterTexture, value)) { CompleteTerrainShader.SetDirty(this, recordUndo: false, isPlayingAllowed: true); m_snowGlitterTexture = value; } } } public Texture2D GeoAlbedo { get { return m_geoAlbedoTexture; } set { if (IsDifferentTexture(m_geoAlbedoTexture, value)) { CompleteTerrainShader.SetDirty(this, recordUndo: false, isPlayingAllowed: true); m_geoAlbedoTexture = value; } } } public List TerrainTextures { get { return m_terrainTextures; } set { m_terrainTextures = value; } } public List ReplacementTerrainAlbedos => m_replacementTerrainAlbedos; public List ReplacementTerrainNormals => m_replacementTerrainNormals; public Texture2DArray AlbedosTextureArray { get { return m_albedosTextureArray; } set { CompleteTerrainShader.SetDirty(this, recordUndo: false, isPlayingAllowed: false); m_albedosTextureArray = value; m_needsAlbedosArrayUpdate = false; } } public Texture2DArray NormalsTextureArray { get { return m_normalsTextureArray; } set { CompleteTerrainShader.SetDirty(this, recordUndo: false, isPlayingAllowed: false); m_normalsTextureArray = value; m_needsNormalsArrayUpdate = false; } } public bool NeedsArrayUpdate() { if (m_needsAlbedosArrayUpdate) { return true; } if (m_needsNormalsArrayUpdate) { return true; } for (int i = 0; i < m_terrainTextures.Count; i++) { if (m_terrainTextures[i].TextureHasChanged()) { return true; } } return false; } public void RegenerateArraysIfNecessary() { for (int i = 0; i < m_terrainTextures.Count; i++) { } if (m_needsAlbedosArrayUpdate) { ConstructAlbedosTextureArray(); } if (m_needsNormalsArrayUpdate) { ConstructNormalsTextureArray(); } for (int j = 0; j < m_terrainTextures.Count; j++) { m_terrainTextures[j].ResetChangedFlags(); } } private void ConstructAlbedosTextureArray() { m_needsAlbedosArrayUpdate = false; List list = new List(); int num = 0; CTSTerrainTextureDetails cTSTerrainTextureDetails = null; byte minHeight; byte maxHeight; for (int i = 0; i < m_terrainTextures.Count; i++) { cTSTerrainTextureDetails = m_terrainTextures[i]; if (cTSTerrainTextureDetails.Albedo != null) { Texture2D texture2D = ((!(cTSTerrainTextureDetails.Smoothness == null) || !(cTSTerrainTextureDetails.Roughness == null)) ? BakeAlbedo(cTSTerrainTextureDetails.Albedo, cTSTerrainTextureDetails.Smoothness, cTSTerrainTextureDetails.Roughness) : ((!m_albedoCompress) ? ResizeTexture(cTSTerrainTextureDetails.Albedo, m_albedoFormat, m_albedoAniso, m_albedoTextureSizePx, m_albedoTextureSizePx, mipmap: true, linear: false, compress: false) : ResizeTexture(cTSTerrainTextureDetails.Albedo, m_albedoFormat, m_albedoAniso, m_albedoTextureSizePx, m_albedoTextureSizePx, mipmap: true, linear: false, compress: true))); list.Add(texture2D); Color linear = texture2D.GetPixels(texture2D.mipmapCount - 1)[0].linear; cTSTerrainTextureDetails.m_albedoAverage = new Vector4(linear.r, linear.g, linear.b, linear.a); cTSTerrainTextureDetails.m_albedoIdx = num++; if ((m_shaderType == CTSConstants.ShaderType.Advanced || m_shaderType == CTSConstants.ShaderType.Tesselation) && (cTSTerrainTextureDetails.Height != null || cTSTerrainTextureDetails.AmbientOcclusion != null)) { list.Add(BakeHAOTexture(cTSTerrainTextureDetails.m_name, cTSTerrainTextureDetails.Height, cTSTerrainTextureDetails.AmbientOcclusion, out minHeight, out maxHeight)); if (cTSTerrainTextureDetails.Height != null) { cTSTerrainTextureDetails.m_heightIdx = num; cTSTerrainTextureDetails.m_heightMin = (float)(int)minHeight / 255f; cTSTerrainTextureDetails.m_heightMax = (float)(int)maxHeight / 255f; } else { cTSTerrainTextureDetails.m_heightIdx = -1; } if (cTSTerrainTextureDetails.AmbientOcclusion != null) { cTSTerrainTextureDetails.m_aoIdx = num; } else { cTSTerrainTextureDetails.m_aoIdx = -1; } num++; } else { cTSTerrainTextureDetails.m_aoIdx = -1; cTSTerrainTextureDetails.m_heightIdx = -1; } } else { cTSTerrainTextureDetails.m_albedoIdx = -1; } cTSTerrainTextureDetails.m_albedoWasChanged = false; } if (m_snowAlbedoTexture != null) { Texture2D texture2D2 = ((!m_albedoCompress) ? ResizeTexture(m_snowAlbedoTexture, m_albedoFormat, m_normalAniso, m_albedoTextureSizePx, m_albedoTextureSizePx, mipmap: true, linear: false, compress: false) : ResizeTexture(m_snowAlbedoTexture, m_albedoFormat, m_normalAniso, m_albedoTextureSizePx, m_albedoTextureSizePx, mipmap: true, linear: false, compress: true)); Color linear2 = texture2D2.GetPixels(texture2D2.mipmapCount - 1)[0].linear; m_snowAverage = new Vector4(linear2.r, linear2.g, linear2.b, linear2.a); list.Add(texture2D2); m_snowAlbedoTextureIdx = num++; } else { m_snowAlbedoTextureIdx = -1; } if (m_snowHeightTexture != null || m_snowAOTexture != null) { list.Add(BakeHAOTexture("CTS_SnowHAO", m_snowHeightTexture, m_snowAOTexture, out minHeight, out maxHeight)); if (m_snowHeightTexture != null) { m_snowHeightTextureIdx = num; m_snowHeightmapMinValue = (float)(int)minHeight / 255f; m_snowHeightmapMaxValue = (float)(int)maxHeight / 255f; } else { m_snowHeightTextureIdx = -1; m_snowHeightmapMinValue = 0f; m_snowHeightmapMaxValue = 1f; } if (m_snowAOTexture != null) { m_snowAOTextureIdx = num; } else { m_snowAOTextureIdx = -1; } num++; } else { m_snowAOTextureIdx = -1; m_snowHeightTextureIdx = -1; } Texture2DArray textureArray = GetTextureArray(list, CTSConstants.TextureType.Albedo, m_albedoAniso); AlbedosTextureArray = textureArray; } private void ConstructNormalsTextureArray() { m_needsNormalsArrayUpdate = false; List list = new List(); int num = 0; CTSTerrainTextureDetails cTSTerrainTextureDetails = null; for (int i = 0; i < m_terrainTextures.Count; i++) { cTSTerrainTextureDetails = m_terrainTextures[i]; if (cTSTerrainTextureDetails.Normal != null) { list.Add(BakeNormal(cTSTerrainTextureDetails.Normal)); cTSTerrainTextureDetails.m_normalIdx = num++; } else { cTSTerrainTextureDetails.m_normalIdx = -1; } cTSTerrainTextureDetails.m_normalWasChanged = false; } if (m_snowNormalTexture != null) { list.Add(BakeNormal(m_snowNormalTexture)); m_snowNormalTextureIdx = num++; } else { m_snowNormalTextureIdx = -1; } if ((bool)m_globalDetailNormalMap) { list.Add(BakeNormal(m_globalDetailNormalMap)); m_globalDetailNormalMapIdx = num++; } else { m_globalDetailNormalMapIdx = -1; } Texture2DArray textureArray = GetTextureArray(list, CTSConstants.TextureType.Normal, m_normalAniso); NormalsTextureArray = textureArray; } public void UpdateSettingsFromTerrain(Terrain terrain, bool forceUpdate) { if (terrain == null || terrain.terrainData == null) { return; } if (forceUpdate) { m_needsAlbedosArrayUpdate = true; m_needsNormalsArrayUpdate = true; } CTSSplatPrototype[] cTSSplatPrototypes = CTSSplatPrototype.GetCTSSplatPrototypes(terrain); while (m_terrainTextures.Count > cTSSplatPrototypes.Length) { m_terrainTextures.RemoveAt(m_terrainTextures.Count - 1); m_needsAlbedosArrayUpdate = true; m_needsNormalsArrayUpdate = true; } CTSTerrainTextureDetails cTSTerrainTextureDetails = null; for (int i = 0; i < cTSSplatPrototypes.Length; i++) { CTSSplatPrototype cTSSplatPrototype = cTSSplatPrototypes[i]; if (i < m_terrainTextures.Count) { cTSTerrainTextureDetails = m_terrainTextures[i]; cTSTerrainTextureDetails.Albedo = cTSSplatPrototype.texture; cTSTerrainTextureDetails.m_albedoTilingClose = cTSSplatPrototypes[i].tileSize.x; cTSTerrainTextureDetails.Normal = cTSSplatPrototype.normalMap; } else { cTSTerrainTextureDetails = new CTSTerrainTextureDetails(); cTSTerrainTextureDetails.m_textureIdx = i; cTSTerrainTextureDetails.Albedo = cTSSplatPrototypes[i].texture; cTSTerrainTextureDetails.m_albedoTilingClose = cTSSplatPrototypes[i].tileSize.x; cTSTerrainTextureDetails.Normal = cTSSplatPrototypes[i].normalMap; m_terrainTextures.Add(cTSTerrainTextureDetails); } } RegenerateArraysIfNecessary(); } private void ImportTexture(Texture2D texture, int textureSize, bool asNormal = false) { if (!(texture == null)) { Debug.Log("Importing " + texture.name + " " + textureSize); } } private Color32[] GetTextureColors(Texture2D source, TextureFormat format, int dimensions) { Texture2D texture2D = ResizeTexture(source, format, m_albedoAniso, dimensions, dimensions, mipmap: false, linear: false, compress: false); Color32[] pixels = texture2D.GetPixels32(); if (!Application.isPlaying) { UnityEngine.Object.DestroyImmediate(texture2D); return pixels; } UnityEngine.Object.Destroy(texture2D); return pixels; } public Texture2D BakeHAOTexture(string name, Texture2D hTexture, Texture2D aoTexture, out byte minHeight, out byte maxHeight) { minHeight = 0; maxHeight = byte.MaxValue; int num = m_albedoTextureSizePx * m_albedoTextureSizePx; if (num == 0) { return null; } Texture2D texture2D = new Texture2D(m_albedoTextureSizePx, m_albedoTextureSizePx, m_workTextureFormat, mipChain: true, linear: false); texture2D.name = "CTS_" + name + "_HAO"; texture2D.anisoLevel = m_albedoAniso; texture2D.filterMode = m_albedoFilterMode; Color32[] pixels = texture2D.GetPixels32(); if (hTexture != null) { minHeight = byte.MaxValue; maxHeight = 0; Texture2D texture2D2 = ResizeTexture(hTexture, m_workTextureFormat, m_albedoAniso, m_albedoTextureSizePx, m_albedoTextureSizePx, mipmap: false, linear: false, compress: false); Color32[] pixels2 = texture2D2.GetPixels32(); for (int i = 0; i < num; i++) { byte g = pixels2[i].g; if (g < minHeight) { minHeight = g; } if (g > maxHeight) { maxHeight = g; } pixels[i].r = (pixels[i].g = (pixels[i].b = g)); } if (Application.isPlaying) { UnityEngine.Object.Destroy(texture2D2); } else { UnityEngine.Object.DestroyImmediate(texture2D2); } } if (aoTexture != null) { Texture2D texture2D3 = ResizeTexture(aoTexture, m_workTextureFormat, m_albedoAniso, m_albedoTextureSizePx, m_albedoTextureSizePx, mipmap: false, linear: false, compress: false); Color32[] pixels3 = texture2D3.GetPixels32(); for (int j = 0; j < num; j++) { pixels[j].a = pixels3[j].g; } if (Application.isPlaying) { UnityEngine.Object.Destroy(texture2D3); } else { UnityEngine.Object.DestroyImmediate(texture2D3); } } else { for (int k = 0; k < num; k++) { pixels[k].a = byte.MaxValue; } } texture2D.SetPixels32(pixels); texture2D.Apply(updateMipmaps: true); if (m_albedoCompress) { texture2D = CompressTexture(texture2D, m_albedoFormat); } return texture2D; } private Texture2D BakeNormal(Texture2D normalTexture) { int num = m_normalTextureSizePx * m_normalTextureSizePx; if (num == 0 || normalTexture == null) { return null; } Texture2D texture2D = new Texture2D(m_normalTextureSizePx, m_normalTextureSizePx, m_workTextureFormat, mipChain: true, linear: true); texture2D.name = "CTS_" + base.name + "_Normal"; texture2D.anisoLevel = m_normalAniso; texture2D.filterMode = m_normalFilterMode; Color32[] pixels = texture2D.GetPixels32(); Texture2D texture2D2 = ResizeTexture(normalTexture, m_workTextureFormat, m_normalAniso, m_normalTextureSizePx, m_normalTextureSizePx, mipmap: false, linear: true, compress: false); Color32[] pixels2 = texture2D2.GetPixels32(); for (int i = 0; i < num; i++) { pixels[i].r = 128; pixels[i].g = pixels2[i].g; pixels[i].b = 128; pixels[i].a = pixels2[i].a; } if (Application.isPlaying) { UnityEngine.Object.Destroy(texture2D2); } else { UnityEngine.Object.DestroyImmediate(texture2D2); } texture2D.SetPixels32(pixels); texture2D.Apply(updateMipmaps: true); if (m_normalCompress) { texture2D = CompressTexture(texture2D, m_normalFormat); } return texture2D; } private Texture2D BakeAlbedo(Texture2D albedoTexture, Texture2D smoothnessTexture, Texture2D roughnessTexture) { int num = m_normalTextureSizePx * m_normalTextureSizePx; if (num == 0) { return null; } Texture2D texture2D = new Texture2D(m_albedoTextureSizePx, m_albedoTextureSizePx, m_workTextureFormat, mipChain: true, linear: false); texture2D.name = "CTS_" + base.name + "_ASm"; texture2D.anisoLevel = m_albedoAniso; texture2D.filterMode = m_albedoFilterMode; Color32[] pixels = texture2D.GetPixels32(); if (albedoTexture != null) { Texture2D texture2D2 = ResizeTexture(albedoTexture, m_workTextureFormat, m_albedoAniso, m_albedoTextureSizePx, m_albedoTextureSizePx, mipmap: false, linear: false, compress: false); Color32[] pixels2 = texture2D2.GetPixels32(); for (int i = 0; i < num; i++) { pixels[i].r = pixels2[i].r; pixels[i].g = pixels2[i].g; pixels[i].b = pixels2[i].b; } if (Application.isPlaying) { UnityEngine.Object.Destroy(texture2D2); } else { UnityEngine.Object.DestroyImmediate(texture2D2); } } if (roughnessTexture != null && smoothnessTexture == null) { Texture2D texture2D3 = ResizeTexture(roughnessTexture, m_workTextureFormat, m_albedoAniso, m_albedoTextureSizePx, m_albedoTextureSizePx, mipmap: false, linear: false, compress: false); Color32[] pixels3 = texture2D3.GetPixels32(); for (int j = 0; j < num; j++) { pixels[j].a = (byte)(255 - pixels3[j].g); } if (Application.isPlaying) { UnityEngine.Object.Destroy(texture2D3); } else { UnityEngine.Object.DestroyImmediate(texture2D3); } } if (smoothnessTexture != null) { Texture2D texture2D4 = ResizeTexture(smoothnessTexture, m_workTextureFormat, m_albedoAniso, m_albedoTextureSizePx, m_albedoTextureSizePx, mipmap: false, linear: false, compress: false); Color32[] pixels4 = texture2D4.GetPixels32(); for (int k = 0; k < num; k++) { pixels[k].a = pixels4[k].g; } if (Application.isPlaying) { UnityEngine.Object.Destroy(texture2D4); } else { UnityEngine.Object.DestroyImmediate(texture2D4); } } texture2D.SetPixels32(pixels); texture2D.Apply(updateMipmaps: true); if (m_albedoCompress) { texture2D = CompressTexture(texture2D, m_albedoFormat); } return texture2D; } private static Texture2D CompressTexture(Texture2D texture, TextureFormat textureFormat) { texture.Compress(highQuality: true); texture.Apply(updateMipmaps: true); return texture; } private void DebugTextureColorData(string name, Color32 color) { Debug.Log($"{name} - r{color.r} g{color.g} b{color.b} a{color.a}"); } private static void SaveTexture(string path, Texture2D texture) { byte[] bytes = texture.EncodeToPNG(); File.WriteAllBytes(path + ".png", bytes); } public static Texture2D ResizeTexture(Texture2D texture, TextureFormat format, int aniso, int width, int height, bool mipmap, bool linear, bool compress) { RenderTexture renderTexture = ((!linear) ? RenderTexture.GetTemporary(width, height, 0, RenderTextureFormat.Default, RenderTextureReadWrite.sRGB) : RenderTexture.GetTemporary(width, height, 0, RenderTextureFormat.Default, RenderTextureReadWrite.Linear)); bool sRGBWrite = GL.sRGBWrite; if (linear) { GL.sRGBWrite = false; } else { GL.sRGBWrite = true; } Graphics.Blit(texture, renderTexture); RenderTexture active = RenderTexture.active; RenderTexture.active = renderTexture; Texture2D texture2D = new Texture2D(width, height, m_workTextureFormat, mipmap, linear); texture2D.name = texture.name + " X"; texture2D.anisoLevel = aniso; texture2D.filterMode = texture.filterMode; texture2D.wrapMode = texture.wrapMode; texture2D.mipMapBias = texture.mipMapBias; texture2D.ReadPixels(new Rect(0f, 0f, renderTexture.width, renderTexture.height), 0, 0); texture2D.Apply(updateMipmaps: true); Texture2D result = CompressTexture(texture2D, format); RenderTexture.active = active; RenderTexture.ReleaseTemporary(renderTexture); GL.sRGBWrite = sRGBWrite; return result; } private Texture2DArray GetTextureArray(List sourceTextures, CTSConstants.TextureType textureType, int aniso) { if (sourceTextures == null) { return null; } if (sourceTextures.Count == 0) { return null; } Texture2D texture2D = sourceTextures[0]; TextureFormat format = texture2D.format; int width = texture2D.width; int height = texture2D.height; for (int i = 1; i < sourceTextures.Count; i++) { if (sourceTextures[i].width != width || sourceTextures[i].height != height) { Debug.Log($"GetTextureArray : {sourceTextures[i].name} width {sourceTextures[i].width} <> {width}, height {sourceTextures[i].height} <> {height}"); return null; } } Texture2DArray texture2DArray; switch (textureType) { case CTSConstants.TextureType.Albedo: case CTSConstants.TextureType.AmbientOcclusion: case CTSConstants.TextureType.Height: texture2DArray = new Texture2DArray(width, height, sourceTextures.Count, format, mipChain: true, linear: false); break; case CTSConstants.TextureType.Normal: texture2DArray = new Texture2DArray(width, height, sourceTextures.Count, format, mipChain: true, linear: true); break; default: throw new ArgumentOutOfRangeException("textureType", textureType, null); } texture2DArray.filterMode = texture2D.filterMode; texture2DArray.wrapMode = texture2D.wrapMode; texture2DArray.anisoLevel = aniso; texture2DArray.mipMapBias = texture2D.mipMapBias; for (int j = 0; j < sourceTextures.Count; j++) { if (sourceTextures[j] != null) { texture2D = sourceTextures[j]; for (int k = 0; k < texture2D.mipmapCount; k++) { Graphics.CopyTexture(texture2D, 0, k, texture2DArray, j, k); } } } texture2DArray.Apply(updateMipmaps: false); return texture2DArray; } public static bool IsDifferentTexture(Texture2D src, Texture2D target) { if (src == null) { if (target != null) { return true; } return false; } if (target == null) { return true; } if (src.GetInstanceID() != target.GetInstanceID()) { return true; } if (src.width != target.width) { return true; } if (src.height != target.height) { return true; } return false; } public void ConstructTerrainReplacementAlbedos() { if (Application.isPlaying) { return; } while (m_replacementTerrainAlbedos.Count > m_terrainTextures.Count) { m_replacementTerrainAlbedos.RemoveAt(m_replacementTerrainAlbedos.Count - 1); } while (m_replacementTerrainAlbedos.Count < m_terrainTextures.Count) { m_replacementTerrainAlbedos.Add(null); } string text = m_ctsDirectory + "Terrains/ReplacementTextures/"; Directory.CreateDirectory(text); CTSTerrainTextureDetails cTSTerrainTextureDetails = null; for (int i = 0; i < m_terrainTextures.Count; i++) { cTSTerrainTextureDetails = m_terrainTextures[i]; if (cTSTerrainTextureDetails.Albedo != null) { string path = text + cTSTerrainTextureDetails.Albedo.name + "_cts.png"; if (!File.Exists(path)) { Texture2D texture2D = ResizeTexture(cTSTerrainTextureDetails.Albedo, m_albedoFormat, m_albedoAniso, 64, 64, mipmap: false, linear: true, compress: false); texture2D.name = cTSTerrainTextureDetails.Albedo.name + "_cts"; m_replacementTerrainAlbedos[i] = texture2D; byte[] bytes = m_replacementTerrainAlbedos[i].EncodeToPNG(); File.WriteAllBytes(path, bytes); } } else { m_replacementTerrainAlbedos[i] = null; } } CompleteTerrainShader.SetDirty(this, recordUndo: false, isPlayingAllowed: true); } public void ConstructTerrainReplacementNormals() { if (Application.isPlaying) { return; } while (m_replacementTerrainNormals.Count > m_terrainTextures.Count) { m_replacementTerrainNormals.RemoveAt(m_replacementTerrainNormals.Count - 1); } while (m_replacementTerrainNormals.Count < m_terrainTextures.Count) { m_replacementTerrainNormals.Add(null); } string text = m_ctsDirectory + "Terrains/ReplacementTextures/"; Directory.CreateDirectory(text); CTSTerrainTextureDetails cTSTerrainTextureDetails = null; for (int i = 0; i < m_terrainTextures.Count; i++) { cTSTerrainTextureDetails = m_terrainTextures[i]; if (cTSTerrainTextureDetails.Normal != null) { string path = text + cTSTerrainTextureDetails.Normal.name + "_nrm_cts.png"; if (!File.Exists(path)) { Texture2D texture2D = ResizeTexture(cTSTerrainTextureDetails.Normal, m_normalFormat, m_normalAniso, 64, 64, mipmap: false, linear: true, compress: false); texture2D.name = cTSTerrainTextureDetails.Normal.name + "_nrm_cts"; m_replacementTerrainNormals[i] = texture2D; byte[] bytes = m_replacementTerrainNormals[i].EncodeToPNG(); File.WriteAllBytes(path, bytes); } } else { m_replacementTerrainNormals[i] = null; } } CompleteTerrainShader.SetDirty(this, recordUndo: false, isPlayingAllowed: true); } } }