// Amplify Shader Editor - Visual Shader Editing Tool // Copyright (c) Amplify Creations, Lda //#define NEW_TEXTURE_3D_METHOD using UnityEngine; using UnityEditor; using System.Collections.Generic; using UnityEditorInternal; using System; using System.IO; namespace AmplifyShaderEditor { [CustomEditor( typeof( TextureArrayCreatorAsset ) )] public class TextureArrayCreatorAssetEditor : Editor { private string[] m_sizesStr = { "32", "64", "128", "256", "512", "1024", "2048", "4096", "8192" }; private int[] m_sizes = { 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 }; private const string ArrayFilename = "NewTextureArray"; private const string Texture3DFilename = "NewTexture3D"; private GUIContent m_pathButtonContent = new GUIContent(); private GUIStyle m_pathButtonStyle = null; public TextureArrayCreatorAsset Instance; private DragAndDropTool m_dragAndDropTool; SerializedObject m_so; SerializedProperty m_selectedSize; SerializedProperty m_lockRatio; SerializedProperty m_sizeX; SerializedProperty m_sizeY; SerializedProperty m_tex3DMode; SerializedProperty m_linearMode; SerializedProperty m_mipMaps; SerializedProperty m_wrapMode; SerializedProperty m_filterMode; SerializedProperty m_anisoLevel; SerializedProperty m_selectedFormatEnum; SerializedProperty m_quality; SerializedProperty m_folderPath; SerializedProperty m_fileName; SerializedProperty m_filenameChanged; SerializedProperty m_allTextures; [SerializeField] private ReorderableList m_listTextures = null; [SerializeField] private int m_previewSize; public void OnEnable() { Instance = (TextureArrayCreatorAsset)target; m_so = serializedObject; m_selectedSize = m_so.FindProperty( "m_selectedSize" ); m_lockRatio = m_so.FindProperty( "m_lockRatio" ); m_sizeX = m_so.FindProperty( "m_sizeX" ); m_sizeY = m_so.FindProperty( "m_sizeY" ); m_tex3DMode = m_so.FindProperty( "m_tex3DMode" ); m_linearMode = m_so.FindProperty( "m_linearMode" ); m_mipMaps = m_so.FindProperty( "m_mipMaps" ); m_wrapMode = m_so.FindProperty( "m_wrapMode" ); m_filterMode = m_so.FindProperty( "m_filterMode" ); m_anisoLevel = m_so.FindProperty( "m_anisoLevel" ); m_selectedFormatEnum = m_so.FindProperty( "m_selectedFormatEnum" ); m_quality = m_so.FindProperty( "m_quality" ); m_folderPath = m_so.FindProperty( "m_folderPath" ); m_fileName = m_so.FindProperty( "m_fileName" ); m_filenameChanged = m_so.FindProperty( "m_filenameChanged" ); m_allTextures = m_so.FindProperty( "m_allTextures" ); if( m_listTextures == null ) { m_listTextures = new ReorderableList( m_so, m_allTextures, true, true, true, true ); m_listTextures.elementHeight = 16; m_listTextures.drawElementCallback = ( Rect rect, int index, bool isActive, bool isFocused ) => { m_allTextures.GetArrayElementAtIndex( index ).objectReferenceValue = (Texture2D)EditorGUI.ObjectField( rect, "Texture " + index, m_allTextures.GetArrayElementAtIndex( index ).objectReferenceValue, typeof( Texture2D ), false ); }; m_listTextures.drawHeaderCallback = ( Rect rect ) => { m_previewSize = EditorGUI.IntSlider( rect, "Texture List", m_previewSize, 16, 64 ); if( (float)m_previewSize != m_listTextures.elementHeight ) m_listTextures.elementHeight = m_previewSize; }; m_listTextures.onAddCallback = ( list ) => { m_allTextures.InsertArrayElementAtIndex( m_allTextures.arraySize ); m_allTextures.GetArrayElementAtIndex( m_allTextures.arraySize - 1 ).objectReferenceValue = null; }; m_listTextures.onRemoveCallback = ( list ) => { m_allTextures.GetArrayElementAtIndex( list.index ).objectReferenceValue = null; m_allTextures.DeleteArrayElementAtIndex( list.index ); }; } m_dragAndDropTool = new DragAndDropTool(); m_dragAndDropTool.OnValidDropObjectEvt += OnValidObjectsDropped; } public void OnValidObjectsDropped( UnityEngine.Object[] droppedObjs ) { for( int objIdx = 0; objIdx < droppedObjs.Length; objIdx++ ) { Texture2D tex = droppedObjs[ objIdx ] as Texture2D; if( tex != null ) { m_allTextures.InsertArrayElementAtIndex( m_allTextures.arraySize ); m_allTextures.GetArrayElementAtIndex( m_allTextures.arraySize - 1 ).objectReferenceValue = tex; m_so.ApplyModifiedProperties(); } else { DefaultAsset asset = droppedObjs[ objIdx ] as DefaultAsset; if( asset != null ) { string path = AssetDatabase.GetAssetPath( asset ); if( AssetDatabase.IsValidFolder( path ) ) { string[] pathArr = { path }; string[] texInDir = AssetDatabase.FindAssets( "t:Texture2D", pathArr ); for( int texIdx = 0; texIdx < texInDir.Length; texIdx++ ) { Texture2D internalTex = AssetDatabase.LoadAssetAtPath( AssetDatabase.GUIDToAssetPath( texInDir[ texIdx ] ) ); if( internalTex != null ) { m_allTextures.InsertArrayElementAtIndex( m_allTextures.arraySize ); m_allTextures.GetArrayElementAtIndex( m_allTextures.arraySize - 1 ).objectReferenceValue = internalTex; m_so.ApplyModifiedProperties(); } } } } } } Instance.AllTextures.Sort( ( x, y ) => string.Compare( x.name, y.name ) ); m_so.Update(); } private void OnDestroy() { m_dragAndDropTool.Destroy(); m_dragAndDropTool = null; } public override void OnInspectorGUI() { m_so.Update(); if( m_pathButtonStyle == null ) m_pathButtonStyle = "minibutton"; EditorGUILayout.BeginHorizontal(); var cache = EditorGUIUtility.labelWidth; EditorGUILayout.PrefixLabel( "Size" ); EditorGUIUtility.labelWidth = 16; if( m_lockRatio.boolValue ) { m_selectedSize.intValue = EditorGUILayout.Popup( "X", m_selectedSize.intValue, m_sizesStr ); EditorGUI.BeginDisabledGroup( m_lockRatio.boolValue ); EditorGUILayout.Popup( "Y", m_selectedSize.intValue, m_sizesStr ); EditorGUI.EndDisabledGroup(); } else { EditorGUILayout.PropertyField( m_sizeX, new GUIContent( "X" ) ); EditorGUILayout.PropertyField( m_sizeY, new GUIContent( "Y" ) ); } EditorGUIUtility.labelWidth = 100; #if UNITY_2017_1_OR_NEWER m_lockRatio.boolValue = GUILayout.Toggle( m_lockRatio.boolValue, "L", "minibutton", GUILayout.Width( 18 ) ); #else GUILayout.Toggle( m_lockRatio.boolValue, "L", "minibutton", GUILayout.Width( 18 ) ); m_lockRatio.boolValue = true; #endif if( m_lockRatio.boolValue ) { m_sizeX.intValue = m_sizes[ m_selectedSize.intValue ]; m_sizeY.intValue = m_sizes[ m_selectedSize.intValue ]; } EditorGUIUtility.labelWidth = cache; EditorGUILayout.EndHorizontal(); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField( m_tex3DMode, new GUIContent( "Texture 3D" ) ); if( EditorGUI.EndChangeCheck() ) { if( !m_filenameChanged.boolValue ) { m_fileName.stringValue = m_tex3DMode.boolValue ? Texture3DFilename : ArrayFilename; } } EditorGUILayout.PropertyField( m_linearMode, new GUIContent( "Linear" ) ); EditorGUILayout.PropertyField( m_mipMaps ); EditorGUILayout.PropertyField( m_wrapMode ); EditorGUILayout.PropertyField( m_filterMode ); m_anisoLevel.intValue = EditorGUILayout.IntSlider( "Aniso Level", m_anisoLevel.intValue, 0, 16 ); EditorGUILayout.PropertyField( m_selectedFormatEnum, new GUIContent( "Format" ) ); if( m_selectedFormatEnum.intValue == (int)TextureFormat.DXT1Crunched ) { m_selectedFormatEnum.intValue = (int)TextureFormat.DXT1; Debug.Log( "Texture Array does not support crunched DXT1 format. Changing to DXT1..." ); } else if( m_selectedFormatEnum.intValue == (int)TextureFormat.DXT5Crunched ) { m_selectedFormatEnum.intValue = (int)TextureFormat.DXT5; Debug.Log( "Texture Array does not support crunched DXT5 format. Changing to DXT5..." ); } m_quality.intValue = EditorGUILayout.IntSlider( "Format Quality", m_quality.intValue, 0, 100 ); EditorGUILayout.Separator(); EditorGUILayout.LabelField( "Path and Name" ); EditorGUILayout.BeginHorizontal(); m_pathButtonContent.text = m_folderPath.stringValue; Vector2 buttonSize = m_pathButtonStyle.CalcSize( m_pathButtonContent ); if( GUILayout.Button( m_pathButtonContent, m_pathButtonStyle, GUILayout.MaxWidth( Mathf.Min( Screen.width * 0.5f, buttonSize.x ) ) ) ) { string folderpath = EditorUtility.OpenFolderPanel( "Save Texture Array to folder", "Assets/", "" ); folderpath = FileUtil.GetProjectRelativePath( folderpath ); if( string.IsNullOrEmpty( folderpath ) ) m_folderPath.stringValue = "Assets/"; else m_folderPath.stringValue = folderpath + "/"; } EditorGUI.BeginChangeCheck(); m_fileName.stringValue = EditorGUILayout.TextField( m_fileName.stringValue, GUILayout.ExpandWidth( true ) ); if( EditorGUI.EndChangeCheck() ) { m_filenameChanged.boolValue = m_fileName.stringValue == ArrayFilename ? false : true; } EditorGUILayout.LabelField( ".asset", GUILayout.MaxWidth( 40 ) ); EditorGUILayout.EndHorizontal(); EditorGUILayout.Separator(); if( GUILayout.Button( "Clear" ) ) { m_allTextures.ClearArray(); } if( m_listTextures != null ) m_listTextures.DoLayoutList(); EditorGUILayout.Separator(); m_dragAndDropTool.TestDragAndDrop( new Rect( 0, 0, Screen.width, Screen.height ) ); m_so.ApplyModifiedProperties(); } } public class ASETextureArrayCreator : EditorWindow { [MenuItem( "Window/Amplify Shader Editor/Texture Array Creator", false, 1001 )] static void ShowWindow() { ASETextureArrayCreator window = EditorWindow.GetWindow(); window.titleContent.text = "Texture Array"; window.minSize = new Vector2( 302, 350 ); window.Show(); } private const string ClearButtonStr = "Clear"; private const string TextureFilter = "t:Texture2D"; private const string BuildArrayMessage = "Build Array"; private const string BuildTexture3DMessage = "Build Texture 3D"; private const string ArrayFilename = "NewTextureArray"; private const string Texture3DFilename = "NewTexture3D"; TextureArrayCreatorAssetEditor m_editor; [SerializeField] private TextureArrayCreatorAsset m_asset; [SerializeField] private TextureArrayCreatorAsset m_dummyAsset; private static List UncompressedFormats = new List() { TextureFormat.RGBAFloat, TextureFormat.RGBAHalf, TextureFormat.ARGB32, TextureFormat.RGBA32, TextureFormat.RGB24, TextureFormat.Alpha8 }; private GUIStyle m_contentStyle = null; private Vector2 m_scrollPos; private Texture m_lastSaved; private string m_message = string.Empty; private void OnEnable() { if( m_contentStyle == null ) { m_contentStyle = new GUIStyle( GUIStyle.none ); m_contentStyle.margin = new RectOffset( 6, 4, 5, 5 ); } } private void OnDestroy() { DestroyImmediate( m_editor ); if( m_dummyAsset != null && m_dummyAsset != m_asset ) DestroyImmediate( m_dummyAsset ); } void OnGUI() { TextureArrayCreatorAsset currentAsset = null; if( m_asset != null ) { currentAsset = m_asset; } else { if( m_dummyAsset == null ) { m_dummyAsset = ScriptableObject.CreateInstance(); m_dummyAsset.name = "Dummy"; } currentAsset = m_dummyAsset; } m_scrollPos = EditorGUILayout.BeginScrollView( m_scrollPos, GUILayout.Height( position.height ) ); float cachedWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth = 100; EditorGUILayout.BeginVertical( m_contentStyle ); string buildButtonStr = currentAsset.Tex3DMode ? BuildTexture3DMessage : BuildArrayMessage; // build button EditorGUILayout.BeginHorizontal(); EditorGUI.BeginDisabledGroup( currentAsset.AllTextures.Count <= 0 ); if( GUILayout.Button( buildButtonStr, "prebutton", GUILayout.Height( 20 ) ) ) { bool showWarning = false; for( int i = 0; i < currentAsset.AllTextures.Count; i++ ) { if( currentAsset.AllTextures[ i ].width != currentAsset.SizeX || currentAsset.AllTextures[ i ].height != currentAsset.SizeY ) { showWarning = true; } } if( !showWarning ) { m_message = string.Empty; if( currentAsset.Tex3DMode ) BuildTexture3D( currentAsset ); else BuildArray( currentAsset ); } else if( EditorUtility.DisplayDialog( "Warning!", "Some textures need to be resized to fit the selected size. Do you want to continue?", "Yes", "No" ) ) { m_message = string.Empty; if( currentAsset.Tex3DMode ) BuildTexture3D( currentAsset ); else BuildArray( currentAsset ); } } EditorGUI.EndDisabledGroup(); EditorGUI.BeginDisabledGroup( m_lastSaved == null ); GUIContent icon = EditorGUIUtility.IconContent( "icons/d_ViewToolZoom.png" ); if( GUILayout.Button( icon, "prebutton", GUILayout.Width( 28 ), GUILayout.Height( 20 ) ) ) { EditorGUIUtility.PingObject( m_lastSaved ); } EditorGUI.EndDisabledGroup(); EditorGUILayout.EndHorizontal(); // message if( !string.IsNullOrEmpty( m_message ) ) if( GUILayout.Button( "BUILD REPORT (click to hide):\n\n" + m_message, "helpbox" ) ) m_message = string.Empty; // asset EditorGUILayout.BeginHorizontal(); m_asset = EditorGUILayout.ObjectField( "Asset Preset", m_asset, typeof( TextureArrayCreatorAsset ), false ) as TextureArrayCreatorAsset; if( GUILayout.Button( m_asset != null ? "Save" : "Create", "minibutton", GUILayout.Width( 50 ) ) ) { string defaultName = "ArrayPreset"; if( m_asset != null ) defaultName = m_asset.name; string path = EditorUtility.SaveFilePanelInProject( "Save as", defaultName, "asset", string.Empty ); if( !string.IsNullOrEmpty( path ) ) { TextureArrayCreatorAsset outfile = AssetDatabase.LoadMainAssetAtPath( path ) as TextureArrayCreatorAsset; if( outfile != null ) { EditorUtility.CopySerialized( currentAsset, outfile ); AssetDatabase.SaveAssets(); Selection.activeObject = outfile; EditorGUIUtility.PingObject( outfile ); } else { if( m_asset != null ) { currentAsset = ScriptableObject.CreateInstance(); EditorUtility.CopySerialized( m_asset, currentAsset ); } AssetDatabase.CreateAsset( currentAsset, path ); Selection.activeObject = currentAsset; EditorGUIUtility.PingObject( currentAsset ); m_asset = currentAsset; } } } EditorGUILayout.EndHorizontal(); EditorGUILayout.Separator(); if( Event.current.type == EventType.Layout ) { if( m_editor == null ) { m_editor = Editor.CreateEditor( currentAsset, typeof( TextureArrayCreatorAssetEditor ) ) as TextureArrayCreatorAssetEditor; } else { if( m_editor.Instance != currentAsset ) { DestroyImmediate( m_editor ); m_editor = Editor.CreateEditor( currentAsset, typeof( TextureArrayCreatorAssetEditor ) ) as TextureArrayCreatorAssetEditor; } } } if( m_editor != null ) m_editor.OnInspectorGUI(); GUILayout.Space( 20 ); EditorGUILayout.EndVertical(); EditorGUIUtility.labelWidth = cachedWidth; EditorGUILayout.EndScrollView(); } private void CopyToArray( ref Texture2D from, ref Texture2DArray to, int arrayIndex, int mipLevel, bool compressed = true ) { if( compressed ) { Graphics.CopyTexture( from, 0, mipLevel, to, arrayIndex, mipLevel ); } else { to.SetPixels( from.GetPixels(), arrayIndex, mipLevel ); to.Apply(); } } #if NEW_TEXTURE_3D_METHOD private void BuildTexture3D( TextureArrayCreatorAsset asset ) { int sizeX = asset.SizeX; int sizeY = asset.SizeY; Texture3D texture3D = new Texture3D( sizeX, sizeY, asset.AllTextures.Count, asset.SelectedFormatEnum, asset.MipMaps ); texture3D.wrapMode = asset.WrapMode; texture3D.filterMode = asset.FilterMode; texture3D.anisoLevel = asset.AnisoLevel; //texture3D.Apply( false ); RenderTexture cache = RenderTexture.active; RenderTexture rt = new RenderTexture( sizeX, sizeY, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default ); rt.Create(); List textures = new List( asset.AllTextures.Count ); for( int i = 0; i < asset.AllTextures.Count; i++ ) { // build report int widthChanges = asset.AllTextures[ i ].width < sizeX ? -1 : asset.AllTextures[ i ].width > sizeX ? 1 : 0; int heightChanges = asset.AllTextures[ i ].height < sizeY ? -1 : asset.AllTextures[ i ].height > sizeY ? 1 : 0; if( ( widthChanges < 0 && heightChanges <= 0 ) || ( widthChanges <= 0 && heightChanges < 0 ) ) m_message += asset.AllTextures[ i ].name + " was upscaled\n"; else if( ( widthChanges > 0 && heightChanges >= 0 ) || ( widthChanges >= 0 && heightChanges > 0 ) ) m_message += asset.AllTextures[ i ].name + " was downscaled\n"; else if( ( widthChanges > 0 && heightChanges < 0 ) || ( widthChanges < 0 && heightChanges > 0 ) ) m_message += asset.AllTextures[ i ].name + " changed dimensions\n"; // blit image to upscale or downscale the image to any size RenderTexture.active = rt; bool cachedsrgb = GL.sRGBWrite; GL.sRGBWrite = !asset.LinearMode; Graphics.Blit( asset.AllTextures[ i ], rt ); GL.sRGBWrite = cachedsrgb; textures.Add( new Texture2D( sizeX, sizeY, TextureFormat.ARGB32, asset.MipMaps, asset.LinearMode ) ); textures[ i ].ReadPixels( new Rect( 0, 0, sizeX, sizeY ), 0, 0, asset.MipMaps ); RenderTexture.active = null; bool isCompressed = UncompressedFormats.FindIndex( x => x.Equals( asset.SelectedFormatEnum ) ) < 0; if( isCompressed ) { EditorUtility.CompressTexture( textures[ i ], asset.SelectedFormatEnum, asset.Quality ); // t2d.Apply( false ); } textures[ i ].Apply( false ); } rt.Release(); RenderTexture.active = cache; if( m_message.Length > 0 ) m_message = m_message.Substring( 0, m_message.Length - 1 ); int sizeZ = textures.Count; Color[] colors = new Color[ sizeX * sizeY * sizeZ ]; int idx = 0; for( int z = 0; z < sizeZ; z++ ) { for( int y = 0; y < sizeY; y++ ) { for( int x = 0; x < sizeX; x++, idx++ ) { colors[ idx ] = textures[ z ].GetPixel(x,y); } } } texture3D.SetPixels( colors ); texture3D.Apply(); string path = asset.FolderPath + asset.FileName + ".asset"; Texture3D outfile = AssetDatabase.LoadMainAssetAtPath( path ) as Texture3D; if( outfile != null ) { EditorUtility.CopySerialized( texture3D, outfile ); AssetDatabase.SaveAssets(); EditorGUIUtility.PingObject( outfile ); m_lastSaved = outfile; } else { AssetDatabase.CreateAsset( texture3D, path ); EditorGUIUtility.PingObject( texture3D ); m_lastSaved = texture3D; } } #else private void BuildTexture3D( TextureArrayCreatorAsset asset ) { int sizeX = asset.SizeX; int sizeY = asset.SizeY; int numLevels = 1 + (int)Mathf.Floor( Mathf.Log( Mathf.Max( sizeX, sizeY ), 2 ) ); int mipCount = asset.MipMaps ? numLevels : 1; Texture3D texture3D = new Texture3D( sizeX, sizeY, asset.AllTextures.Count, asset.SelectedFormatEnum, asset.MipMaps ); texture3D.wrapMode = asset.WrapMode; texture3D.filterMode = asset.FilterMode; texture3D.anisoLevel = asset.AnisoLevel; texture3D.Apply( false ); RenderTexture cache = RenderTexture.active; RenderTexture rt = new RenderTexture( sizeX, sizeY, 0, RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Default ); rt.Create(); List> mipColor = new List>(); if( asset.MipMaps ) { for( int i = 0; i < mipCount; i++ ) { mipColor.Add( new List() ); } } else { mipColor.Add( new List() ); } for( int i = 0; i < asset.AllTextures.Count; i++ ) { // build report int widthChanges = asset.AllTextures[ i ].width < sizeX ? -1 : asset.AllTextures[ i ].width > sizeX ? 1 : 0; int heightChanges = asset.AllTextures[ i ].height < sizeY ? -1 : asset.AllTextures[ i ].height > sizeY ? 1 : 0; if( ( widthChanges < 0 && heightChanges <= 0 ) || ( widthChanges <= 0 && heightChanges < 0 ) ) m_message += asset.AllTextures[ i ].name + " was upscaled\n"; else if( ( widthChanges > 0 && heightChanges >= 0 ) || ( widthChanges >= 0 && heightChanges > 0 ) ) m_message += asset.AllTextures[ i ].name + " was downscaled\n"; else if( ( widthChanges > 0 && heightChanges < 0 ) || ( widthChanges < 0 && heightChanges > 0 ) ) m_message += asset.AllTextures[ i ].name + " changed dimensions\n"; // blit image to upscale or downscale the image to any size RenderTexture.active = rt; bool cachedsrgb = GL.sRGBWrite; GL.sRGBWrite = !asset.LinearMode; Graphics.Blit( asset.AllTextures[ i ], rt ); GL.sRGBWrite = cachedsrgb; bool isCompressed = UncompressedFormats.FindIndex( x => x.Equals( asset.SelectedFormatEnum ) ) < 0; TextureFormat validReadPixelsFormat = isCompressed ? TextureFormat.RGBAFloat : asset.SelectedFormatEnum; Texture2D t2d = new Texture2D( sizeX, sizeY, validReadPixelsFormat, asset.MipMaps, asset.LinearMode ); t2d.ReadPixels( new Rect( 0, 0, sizeX, sizeY ), 0, 0, asset.MipMaps ); RenderTexture.active = null; if( isCompressed ) { EditorUtility.CompressTexture( t2d, asset.SelectedFormatEnum, asset.Quality ); // t2d.Apply( false ); } t2d.Apply( false ); if( asset.MipMaps ) { for( int mip = 0; mip < mipCount; mip++ ) { mipColor[ mip ].AddRange( t2d.GetPixels( mip ) ); } } else { mipColor[ 0 ].AddRange( t2d.GetPixels( 0 ) ); } } rt.Release(); RenderTexture.active = cache; if( m_message.Length > 0 ) m_message = m_message.Substring( 0, m_message.Length - 1 ); for( int i = 0; i < mipCount; i++ ) { texture3D.SetPixels( mipColor[ i ].ToArray(), i ); } texture3D.Apply( false ); string path = asset.FolderPath + asset.FileName + ".asset"; Texture3D outfile = AssetDatabase.LoadMainAssetAtPath( path ) as Texture3D; if( outfile != null ) { EditorUtility.CopySerialized( texture3D, outfile ); AssetDatabase.SaveAssets(); EditorGUIUtility.PingObject( outfile ); m_lastSaved = outfile; } else { AssetDatabase.CreateAsset( texture3D, path ); EditorGUIUtility.PingObject( texture3D ); m_lastSaved = texture3D; } } #endif private void BuildTexture3DAutoMips( TextureArrayCreatorAsset asset ) { int sizeX = asset.SizeX; int sizeY = asset.SizeY; Texture3D texture3D = new Texture3D( sizeX, sizeY, asset.AllTextures.Count, asset.SelectedFormatEnum, asset.MipMaps ); texture3D.wrapMode = asset.WrapMode; texture3D.filterMode = asset.FilterMode; texture3D.anisoLevel = asset.AnisoLevel; texture3D.Apply( false ); RenderTexture cache = RenderTexture.active; RenderTexture rt = new RenderTexture( sizeX, sizeY, 0, RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Default ); rt.Create(); List texColors = new List(); for( int i = 0; i < asset.AllTextures.Count; i++ ) { // build report int widthChanges = asset.AllTextures[ i ].width < sizeX ? -1 : asset.AllTextures[ i ].width > sizeX ? 1 : 0; int heightChanges = asset.AllTextures[ i ].height < sizeY ? -1 : asset.AllTextures[ i ].height > sizeY ? 1 : 0; if( ( widthChanges < 0 && heightChanges <= 0 ) || ( widthChanges <= 0 && heightChanges < 0 ) ) m_message += asset.AllTextures[ i ].name + " was upscaled\n"; else if( ( widthChanges > 0 && heightChanges >= 0 ) || ( widthChanges >= 0 && heightChanges > 0 ) ) m_message += asset.AllTextures[ i ].name + " was downscaled\n"; else if( ( widthChanges > 0 && heightChanges < 0 ) || ( widthChanges < 0 && heightChanges > 0 ) ) m_message += asset.AllTextures[ i ].name + " changed dimensions\n"; // blit image to upscale or downscale the image to any size RenderTexture.active = rt; bool cachedsrgb = GL.sRGBWrite; GL.sRGBWrite = !asset.LinearMode; Graphics.Blit( asset.AllTextures[ i ], rt ); GL.sRGBWrite = cachedsrgb; bool isCompressed = UncompressedFormats.FindIndex( x => x.Equals( asset.SelectedFormatEnum ) ) < 0; TextureFormat validReadPixelsFormat = isCompressed ? TextureFormat.RGBAFloat : asset.SelectedFormatEnum; Texture2D t2d = new Texture2D( sizeX, sizeY, validReadPixelsFormat, asset.MipMaps, asset.LinearMode ); t2d.ReadPixels( new Rect( 0, 0, sizeX, sizeY ), 0, 0, asset.MipMaps ); RenderTexture.active = null; if( isCompressed ) { EditorUtility.CompressTexture( t2d, asset.SelectedFormatEnum, asset.Quality ); t2d.Apply( false ); } texColors.AddRange( t2d.GetPixels() ); } rt.Release(); RenderTexture.active = cache; if( m_message.Length > 0 ) m_message = m_message.Substring( 0, m_message.Length - 1 ); texture3D.SetPixels( texColors.ToArray() ); texture3D.Apply(); string path = asset.FolderPath + asset.FileName + ".asset"; Texture3D outfile = AssetDatabase.LoadMainAssetAtPath( path ) as Texture3D; if( outfile != null ) { EditorUtility.CopySerialized( texture3D, outfile ); AssetDatabase.SaveAssets(); EditorGUIUtility.PingObject( outfile ); m_lastSaved = outfile; } else { AssetDatabase.CreateAsset( texture3D, path ); EditorGUIUtility.PingObject( texture3D ); m_lastSaved = texture3D; } } private void BuildArray( TextureArrayCreatorAsset asset ) { int sizeX = asset.SizeX; int sizeY = asset.SizeY; Texture2DArray textureArray = new Texture2DArray( sizeX, sizeY, asset.AllTextures.Count, asset.SelectedFormatEnum, asset.MipMaps, asset.LinearMode ); textureArray.wrapMode = asset.WrapMode; textureArray.filterMode = asset.FilterMode; textureArray.anisoLevel = asset.AnisoLevel; textureArray.Apply( false ); RenderTexture cache = RenderTexture.active; RenderTexture rt = new RenderTexture( sizeX, sizeY, 0, RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Default ); rt.Create(); for( int i = 0; i < asset.AllTextures.Count; i++ ) { // build report int widthChanges = asset.AllTextures[ i ].width < sizeX ? -1 : asset.AllTextures[ i ].width > sizeX ? 1 : 0; int heightChanges = asset.AllTextures[ i ].height < sizeY ? -1 : asset.AllTextures[ i ].height > sizeY ? 1 : 0; if( ( widthChanges < 0 && heightChanges <= 0 ) || ( widthChanges <= 0 && heightChanges < 0 ) ) m_message += asset.AllTextures[ i ].name + " was upscaled\n"; else if( ( widthChanges > 0 && heightChanges >= 0 ) || ( widthChanges >= 0 && heightChanges > 0 ) ) m_message += asset.AllTextures[ i ].name + " was downscaled\n"; else if( ( widthChanges > 0 && heightChanges < 0 ) || ( widthChanges < 0 && heightChanges > 0 ) ) m_message += asset.AllTextures[ i ].name + " changed dimensions\n"; // blit image to upscale or downscale the image to any size RenderTexture.active = rt; bool cachedsrgb = GL.sRGBWrite; GL.sRGBWrite = !asset.LinearMode; Graphics.Blit( asset.AllTextures[ i ], rt ); GL.sRGBWrite = cachedsrgb; bool isCompressed = UncompressedFormats.FindIndex( x => x.Equals( asset.SelectedFormatEnum ) ) < 0; TextureFormat validReadPixelsFormat = isCompressed ? TextureFormat.RGBAFloat : asset.SelectedFormatEnum; Texture2D t2d = new Texture2D( sizeX, sizeY, validReadPixelsFormat, asset.MipMaps, asset.LinearMode ); t2d.ReadPixels( new Rect( 0, 0, sizeX, sizeY ), 0, 0, asset.MipMaps ); RenderTexture.active = null; if( isCompressed ) { EditorUtility.CompressTexture( t2d, asset.SelectedFormatEnum, asset.Quality ); t2d.Apply( false ); } if( asset.MipMaps ) { int maxSize = Mathf.Max( sizeX, sizeY ); int numLevels = 1 + (int)Mathf.Floor( Mathf.Log( maxSize, 2 ) ); for( int mip = 0; mip < numLevels; mip++ ) { CopyToArray( ref t2d, ref textureArray, i, mip, isCompressed ); } } else { CopyToArray( ref t2d, ref textureArray, i, 0, isCompressed ); } } rt.Release(); RenderTexture.active = cache; if( m_message.Length > 0 ) m_message = m_message.Substring( 0, m_message.Length - 1 ); string path = asset.FolderPath + asset.FileName + ".asset"; Texture2DArray outfile = AssetDatabase.LoadMainAssetAtPath( path ) as Texture2DArray; if( outfile != null ) { EditorUtility.CopySerialized( textureArray, outfile ); AssetDatabase.SaveAssets(); EditorGUIUtility.PingObject( outfile ); m_lastSaved = outfile; } else { AssetDatabase.CreateAsset( textureArray, path ); EditorGUIUtility.PingObject( textureArray ); m_lastSaved = textureArray; } } } }