├── .gitignore ├── CHANGELOG.md ├── CHANGELOG.md.meta ├── Editor.meta ├── Editor ├── Philira.SmartTexture.Editor.asmdef ├── Philira.SmartTexture.Editor.asmdef.meta ├── SmartTextureImporter.cs ├── SmartTextureImporter.cs.meta ├── SmartTextureImporterEditor.cs └── SmartTextureImporterEditor.cs.meta ├── LICENSE ├── LICENSE.meta ├── README.md ├── README.md.meta ├── Resources.meta ├── Resources ├── PackChannel.compute └── PackChannel.compute.meta ├── Runtime.meta ├── Runtime ├── Philira.SmartTexture.Runtime.asmdef ├── Philira.SmartTexture.Runtime.asmdef.meta ├── TextureChannelPacker.cs └── TextureChannelPacker.cs.meta ├── Shaders.meta ├── Shaders ├── PackShader.shader └── PackShader.shader.meta ├── Tests.meta ├── Tests ├── Editor.meta └── Editor │ ├── Philira.SmartTexture.Editor.Tests.asmdef │ └── Philira.SmartTexture.Editor.Tests.asmdef.meta ├── package.json └── package.json.meta /.gitignore: -------------------------------------------------------------------------------- 1 | /.vscode/ 2 | 3 | # Visual Studio cache directory 4 | .vs/ 5 | 6 | # Autogenerated VS/MD/Consulo solution and project files 7 | ExportedObj/ 8 | .consulo/ 9 | *.csproj 10 | *.unityproj 11 | *.sln 12 | *.suo 13 | *.tmp 14 | *.user 15 | *.userprefs 16 | *.pidb 17 | *.booproj 18 | *.svd 19 | *.pdb 20 | *.mdb 21 | *.opendb 22 | *.VC.db -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this package are documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 6 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 7 | 8 | ## [0.1.0] - 2020-05-16 9 | 10 | ### Added 11 | 12 | - Packing tool that supports GPU and CPU channel packing. -------------------------------------------------------------------------------- /CHANGELOG.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 79a1701d9970e4645b016ab2b257cd19 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e84552be309687144a83f2502a9eaf7d 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Philira.SmartTexture.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Phillira.SmartTexture.Editor", 3 | "references": [ 4 | "Philira.SmartTexture.Runtime" 5 | ], 6 | "optionalUnityReferences": [], 7 | "includePlatforms": [ 8 | "Editor" 9 | ], 10 | "excludePlatforms": [], 11 | "allowUnsafeCode": false, 12 | "overrideReferences": true, 13 | "precompiledReferences": [], 14 | "autoReferenced": false, 15 | "defineConstraints": [] 16 | } -------------------------------------------------------------------------------- /Editor/Philira.SmartTexture.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 447a42f34d7589946b8de01d4e806a77 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/SmartTextureImporter.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using UnityEditor; 3 | #if UNITY_2020_1_OR_NEWER 4 | using UnityEditor.AssetImporters; 5 | #else 6 | using UnityEditor.Experimental.AssetImporters; 7 | #endif 8 | using UnityEngine; 9 | using UnityEngine.Experimental.Rendering; 10 | using Object = UnityEngine.Object; 11 | 12 | namespace SmartTexture 13 | { 14 | [ScriptedImporter(k_SmartTextureVersion, k_SmartTextureExtesion)] 15 | public class SmartTextureImporter : ScriptedImporter 16 | { 17 | public const string k_SmartTextureExtesion = "smartex"; 18 | public const int k_SmartTextureVersion = 1; 19 | public const int k_MenuPriority = 320; 20 | 21 | // Input Texture Settings 22 | [SerializeField] Texture2D[] m_InputTextures = new Texture2D[4]; 23 | 24 | [SerializeField] TexturePackingSettings[] m_InputTextureSettings = new TexturePackingSettings[4] 25 | { 26 | new TexturePackingSettings {remapRange = new Vector2(0.0f, 1.0f)}, 27 | new TexturePackingSettings {remapRange = new Vector2(0.0f, 1.0f)}, 28 | new TexturePackingSettings {remapRange = new Vector2(0.0f, 1.0f)}, 29 | new TexturePackingSettings {remapRange = new Vector2(0.0f, 1.0f)}, 30 | }; 31 | 32 | // Output Texture Settings 33 | [SerializeField] bool m_IsReadable = false; 34 | [SerializeField] bool m_sRGBTexture = false; 35 | [SerializeField] bool m_EnableMipMap = true; 36 | [SerializeField] bool m_StreamingMipMaps = false; 37 | [SerializeField] int m_StreamingMipMapPriority = 0; 38 | 39 | // TODO: MipMap Generation, is it possible to configure? 40 | //[SerializeField] bool m_BorderMipMaps = false; 41 | //[SerializeField] TextureImporterMipFilter m_MipMapFilter = TextureImporterMipFilter.BoxFilter; 42 | //[SerializeField] bool m_MipMapsPreserveCoverage = false; 43 | //[SerializeField] bool m_FadeoutMipMaps = false; 44 | 45 | [SerializeField] FilterMode m_FilterMode = FilterMode.Bilinear; 46 | [SerializeField] TextureWrapMode m_WrapMode = TextureWrapMode.Repeat; 47 | [SerializeField] int m_AnisotropicLevel = 1; 48 | 49 | [SerializeField] 50 | TextureImporterPlatformSettings m_TexturePlatformSettings = new TextureImporterPlatformSettings(); 51 | 52 | [SerializeField] TextureFormat m_TextureFormat = TextureFormat.RGBA32; 53 | [SerializeField] bool m_UseExplicitTextureFormat = false; 54 | 55 | [MenuItem("Assets/Create/Smart Texture", priority = k_MenuPriority)] 56 | static void CreateSmartTextureMenuItem() 57 | { 58 | // Asset creation code from pschraut Texture2DArrayImporter 59 | // https://github.com/pschraut/UnityTexture2DArrayImportPipeline/blob/master/Editor/Texture2DArrayImporter.cs#L360-L383 60 | string directoryPath = "Assets"; 61 | foreach (Object obj in Selection.GetFiltered(typeof(Object), SelectionMode.Assets)) 62 | { 63 | directoryPath = AssetDatabase.GetAssetPath(obj); 64 | if (!string.IsNullOrEmpty(directoryPath) && File.Exists(directoryPath)) 65 | { 66 | directoryPath = Path.GetDirectoryName(directoryPath); 67 | break; 68 | } 69 | } 70 | 71 | directoryPath = directoryPath.Replace("\\", "/"); 72 | if (directoryPath.Length > 0 && directoryPath[directoryPath.Length - 1] != '/') 73 | directoryPath += "/"; 74 | if (string.IsNullOrEmpty(directoryPath)) 75 | directoryPath = "Assets/"; 76 | 77 | var fileName = string.Format("SmartTexture.{0}", k_SmartTextureExtesion); 78 | directoryPath = AssetDatabase.GenerateUniqueAssetPath(directoryPath + fileName); 79 | ProjectWindowUtil.CreateAssetWithContent(directoryPath, 80 | "Smart Texture Asset for Unity. Allows to channel pack textures by using a ScriptedImporter. Requires Smart Texture Package from https://github.com/phi-lira/SmartTexture. Developed by Felipe Lira."); 81 | } 82 | 83 | 84 | public override void OnImportAsset(AssetImportContext ctx) 85 | { 86 | int width = m_TexturePlatformSettings.maxTextureSize; 87 | int height = m_TexturePlatformSettings.maxTextureSize; 88 | Texture2D[] textures = m_InputTextures; 89 | TexturePackingSettings[] settings = m_InputTextureSettings; 90 | 91 | bool canGenerateTexture = GetOuputTextureSize(textures, out var inputW, out var inputH); 92 | bool error = false; 93 | 94 | //Mimic default importer. We use max size unless assets are smaller 95 | width = width < inputW ? width : inputW; 96 | height = height < inputH ? height : inputH; 97 | 98 | TextureFormat textureFormat = m_UseExplicitTextureFormat ? m_TextureFormat : TextureFormat.RGBA32; 99 | if (!SystemInfo.SupportsTextureFormat(m_TextureFormat)) 100 | textureFormat = TextureFormat.RGBA32; 101 | 102 | GraphicsFormat graphicsFormat = GraphicsFormatUtility.GetGraphicsFormat(textureFormat, m_sRGBTexture); 103 | if (graphicsFormat == GraphicsFormat.None) 104 | { 105 | graphicsFormat = GraphicsFormatUtility.GetGraphicsFormat(TextureFormat.RGBA32, m_sRGBTexture); 106 | error = true; 107 | } 108 | 109 | TextureCreationFlags textureCreationFlags = TextureCreationFlags.None; 110 | if (m_EnableMipMap) 111 | textureCreationFlags |= TextureCreationFlags.MipChain; 112 | if (m_TexturePlatformSettings.crunchedCompression) 113 | textureCreationFlags |= TextureCreationFlags.Crunch; 114 | 115 | Texture2D texture = new Texture2D(width, height, graphicsFormat, textureCreationFlags) 116 | { 117 | filterMode = m_FilterMode, 118 | wrapMode = m_WrapMode, 119 | anisoLevel = m_AnisotropicLevel, 120 | }; 121 | 122 | if (!texture) 123 | { 124 | canGenerateTexture = false; 125 | error = true; 126 | } 127 | 128 | if (canGenerateTexture) 129 | { 130 | //Only attempt to apply any settings if the inputs exist 131 | texture.PackChannels(textures, settings, graphicsFormat, m_sRGBTexture, m_EnableMipMap); 132 | 133 | // Mark all input textures as dependency to the texture array. 134 | // This causes the texture array to get re-generated when any input texture changes or when the build target changed. 135 | foreach (Texture2D t in textures) 136 | { 137 | if (t != null) 138 | { 139 | var path = AssetDatabase.GetAssetPath(t); 140 | ctx.DependsOnSourceAsset(path); 141 | } 142 | } 143 | 144 | // TODO: Seems like we need to call TextureImporter.SetPlatformTextureSettings to register/apply platform 145 | // settings. However we can't subclass from TextureImporter... Is there other way? 146 | 147 | //Currently just supporting one compression format in liew of TextureImporter.SetPlatformTextureSettings 148 | if (m_UseExplicitTextureFormat) 149 | EditorUtility.CompressTexture(texture, textureFormat, 100); 150 | else if (m_TexturePlatformSettings.textureCompression != TextureImporterCompression.Uncompressed) 151 | texture.Compress(m_TexturePlatformSettings.textureCompression == 152 | TextureImporterCompression.CompressedHQ); 153 | 154 | // Not applying for now, seems to cause problems during import... 155 | // ApplyPropertiesViaSerializedObj(texture); 156 | 157 | texture.Apply(m_EnableMipMap, !m_IsReadable); 158 | } 159 | 160 | if (texture) 161 | { 162 | ctx.AddObjectToAsset("mask", texture, texture); 163 | ctx.SetMainObject(texture); 164 | } 165 | 166 | if (error) 167 | { 168 | Debug.LogError($"MaskTexture ({name}): Error creating texture with format {graphicsFormat}."); 169 | } 170 | } 171 | 172 | void ApplyPropertiesViaSerializedObj(Texture tex) 173 | { 174 | var so = new SerializedObject(tex); 175 | 176 | so.FindProperty("m_IsReadable").boolValue = m_IsReadable; 177 | so.FindProperty("m_StreamingMipmaps").boolValue = m_StreamingMipMaps; 178 | so.FindProperty("m_StreamingMipmapsPriority").intValue = m_StreamingMipMapPriority; 179 | //Set ColorSpace on ctr instead 180 | //so.FindProperty("m_ColorSpace").intValue = (int)(m_sRGBTexture ? ColorSpace.Gamma : ColorSpace.Linear); 181 | so.ApplyModifiedPropertiesWithoutUndo(); 182 | } 183 | 184 | static bool GetOuputTextureSize(Texture2D[] textures, out int width, out int height) 185 | { 186 | Texture2D masterTexture = null; 187 | foreach (Texture2D t in textures) 188 | { 189 | if (t != null) 190 | { 191 | //Previously we only read the first readable asset 192 | //but we can get the width&height of unreadable textures. 193 | //May need more complex selection as now Red channel dictates minimum size 194 | //Should we try and find the smallest? 195 | masterTexture = t; 196 | break; 197 | } 198 | } 199 | 200 | if (masterTexture == null) 201 | { 202 | var defaultTexture = Texture2D.blackTexture; 203 | width = defaultTexture.width; 204 | height = defaultTexture.height; 205 | return false; 206 | } 207 | 208 | width = masterTexture.width; 209 | height = masterTexture.height; 210 | return true; 211 | } 212 | } 213 | } -------------------------------------------------------------------------------- /Editor/SmartTextureImporter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b2456aa1653d249e08f78b862a3bd857 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/SmartTextureImporterEditor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEditor; 3 | #if UNITY_2020_1_OR_NEWER 4 | using UnityEditor.AssetImporters; 5 | #else 6 | using UnityEditor.Experimental.AssetImporters; 7 | #endif 8 | using UnityEngine; 9 | using UnityEngine.Experimental.Rendering; 10 | 11 | namespace SmartTexture 12 | { 13 | [CustomEditor(typeof(SmartTextureImporter), true)] 14 | class SmartTextureImporterEditor : ScriptedImporterEditor 15 | { 16 | internal static class Styles 17 | { 18 | public static readonly GUIContent[] labelChannels = 19 | { 20 | EditorGUIUtility.TrTextContent("Texture", 21 | "This texture source channel will be packed into the Output texture red channel"), 22 | EditorGUIUtility.TrTextContent("Texture", 23 | "This texture source channel will be packed into the Output texture green channel"), 24 | EditorGUIUtility.TrTextContent("Texture", 25 | "This texture source channel will be packed into the Output texture blue channel"), 26 | EditorGUIUtility.TrTextContent("Texture", 27 | "This texture source channel will be packed into the Output texture alpha channel"), 28 | }; 29 | 30 | public static readonly GUIContent invertColor = 31 | EditorGUIUtility.TrTextContent("Invert Color", "If enabled outputs the inverted color (1.0 - color)"); 32 | 33 | public static readonly GUIContent remapRange = 34 | EditorGUIUtility.TrTextContent("Remap", "Remaps the input texture value"); 35 | 36 | public static readonly GUIContent useLuminance = EditorGUIUtility.TrTextContent("Use Luminance", 37 | "If enabled, outputs the combined rgb luminance value."); 38 | 39 | public static readonly GUIContent channel = EditorGUIUtility.TrTextContent("Input Channel", 40 | "Selects the RGBA channel to output, defaults to Red."); 41 | 42 | public static readonly GUIContent readWrite = EditorGUIUtility.TrTextContent("Read/Write Enabled", 43 | "Enable to be able to access the raw pixel data from code."); 44 | 45 | public static readonly GUIContent generateMipMaps = EditorGUIUtility.TrTextContent("Generate Mip Maps"); 46 | public static readonly GUIContent streamingMipMaps = EditorGUIUtility.TrTextContent("Streaming Mip Maps"); 47 | 48 | public static readonly GUIContent streamingMipMapsPrio = 49 | EditorGUIUtility.TrTextContent("Streaming Mip Maps Priority"); 50 | 51 | public static readonly GUIContent sRGBTexture = EditorGUIUtility.TrTextContent("sRGB (Color Texture)", 52 | "Texture content is stored in gamma space. Non-HDR color textures should enable this flag (except if used for IMGUI)."); 53 | 54 | public static readonly GUIContent format = EditorGUIUtility.TrTextContent("Output Texture Format"); 55 | 56 | public static readonly GUIContent textureFilterMode = EditorGUIUtility.TrTextContent("Filter Mode"); 57 | public static readonly GUIContent textureWrapMode = EditorGUIUtility.TrTextContent("Wrap Mode"); 58 | 59 | public static readonly GUIContent textureAnisotropicLevel = 60 | EditorGUIUtility.TrTextContent("Anisotropic Level"); 61 | 62 | public static readonly GUIContent crunchCompression = 63 | EditorGUIUtility.TrTextContent("Use Crunch Compression"); 64 | 65 | public static readonly GUIContent useExplicitTextureFormat = 66 | EditorGUIUtility.TrTextContent("Use Explicit Texture Format"); 67 | 68 | public static readonly string[] textureSizeOptions = 69 | { 70 | "32", "64", "128", "256", "512", "1024", "2048", "4096", "8192", 71 | }; 72 | 73 | public static readonly string[] textureCompressionOptions = 74 | Enum.GetNames(typeof(TextureImporterCompression)); 75 | 76 | public static readonly string[] textureFormat = Enum.GetNames(typeof(TextureFormat)); 77 | public static readonly string[] resizeAlgorithmOptions = Enum.GetNames(typeof(TextureResizeAlgorithm)); 78 | } 79 | 80 | SerializedProperty m_StreamingMipMaps; 81 | SerializedProperty m_StreamingMipMapPriority; 82 | readonly SerializedProperty[] m_InputTextures = new SerializedProperty[4]; 83 | readonly SerializedProperty[] m_InputTextureSettings = new SerializedProperty[4]; 84 | 85 | SerializedProperty m_IsReadable; 86 | SerializedProperty m_sRGBTexture; 87 | 88 | SerializedProperty m_EnableMipMap; 89 | 90 | SerializedProperty m_FilterMode; 91 | SerializedProperty m_WrapMode; 92 | SerializedProperty m_AnisotropicLevel; 93 | 94 | SerializedProperty m_TexturePlatformSettings; 95 | SerializedProperty m_TextureFormat; 96 | SerializedProperty m_UseExplicitTextureFormat; 97 | 98 | bool m_ShowAdvanced = false; 99 | 100 | const string k_AdvancedTextureSettingName = "SmartTextureImporterShowAdvanced"; 101 | 102 | public override void OnEnable() 103 | { 104 | base.OnEnable(); 105 | CacheSerializedProperties(); 106 | } 107 | 108 | public override void OnInspectorGUI() 109 | { 110 | serializedObject.Update(); 111 | 112 | m_ShowAdvanced = EditorPrefs.GetBool(k_AdvancedTextureSettingName, m_ShowAdvanced); 113 | 114 | 115 | EditorGUILayout.Space(); 116 | 117 | EditorGUILayout.LabelField("Red Input", EditorStyles.boldLabel); 118 | DrawInputTexture(0); 119 | 120 | var textureFormat = m_UseExplicitTextureFormat.boolValue 121 | ? (TextureFormat) m_TextureFormat.intValue 122 | : TextureFormat.RGBA32; 123 | var graphicsFormat = GraphicsFormatUtility.GetGraphicsFormat(textureFormat, m_sRGBTexture.boolValue); 124 | var componentCount = GraphicsFormatUtility.GetComponentCount(graphicsFormat); 125 | 126 | if (componentCount >= 2) 127 | { 128 | EditorGUILayout.LabelField("Green Input", EditorStyles.boldLabel); 129 | DrawInputTexture(1); 130 | } 131 | 132 | if (componentCount >= 3) 133 | { 134 | EditorGUILayout.LabelField("Blue Input", EditorStyles.boldLabel); 135 | DrawInputTexture(2); 136 | } 137 | 138 | if (componentCount >= 4) 139 | { 140 | EditorGUILayout.LabelField("Alpha Input", EditorStyles.boldLabel); 141 | DrawInputTexture(3); 142 | } 143 | 144 | EditorGUILayout.Space(); 145 | EditorGUILayout.Space(); 146 | 147 | 148 | EditorGUILayout.LabelField("Output Texture", EditorStyles.boldLabel); 149 | using (new EditorGUI.IndentLevelScope()) 150 | { 151 | EditorGUILayout.PropertyField(m_EnableMipMap, Styles.generateMipMaps); 152 | // EditorGUILayout.PropertyField(m_StreamingMipMaps, Styles.streamingMipMaps); 153 | // EditorGUILayout.PropertyField(m_StreamingMipMapPriority, Styles.streamingMipMapsPrio); 154 | EditorGUILayout.Space(); 155 | 156 | EditorGUILayout.PropertyField(m_FilterMode, Styles.textureFilterMode); 157 | EditorGUILayout.PropertyField(m_WrapMode, Styles.textureWrapMode); 158 | 159 | EditorGUILayout.IntSlider(m_AnisotropicLevel, 0, 16, Styles.textureAnisotropicLevel); 160 | EditorGUILayout.Space(); 161 | 162 | EditorGUILayout.PropertyField(m_IsReadable, Styles.readWrite); 163 | EditorGUILayout.PropertyField(m_sRGBTexture, Styles.sRGBTexture); 164 | } 165 | 166 | EditorGUILayout.Space(); 167 | EditorGUILayout.Space(); 168 | 169 | // TODO: Figure out how to apply PlatformTextureImporterSettings on ScriptedImporter 170 | DrawTextureImporterSettings(); 171 | EditorGUILayout.Space(); 172 | EditorGUILayout.Space(); 173 | serializedObject.ApplyModifiedProperties(); 174 | ApplyRevertGUI(); 175 | } 176 | 177 | void DrawInputTexture(int index) 178 | { 179 | if (index < 0 || index >= 4) 180 | return; 181 | 182 | EditorGUI.indentLevel++; 183 | 184 | EditorGUILayout.PropertyField(m_InputTextures[index], Styles.labelChannels[index]); 185 | 186 | SerializedProperty remapRange = m_InputTextureSettings[index].FindPropertyRelative("remapRange"); 187 | DrawMinMaxSlider(remapRange); 188 | 189 | SerializedProperty invertColor = m_InputTextureSettings[index].FindPropertyRelative("invertColor"); 190 | invertColor.boolValue = EditorGUILayout.Toggle(Styles.invertColor, invertColor.boolValue); 191 | 192 | SerializedProperty useLuminance = m_InputTextureSettings[index].FindPropertyRelative("useLuminance"); 193 | useLuminance.boolValue = EditorGUILayout.Toggle(Styles.useLuminance, useLuminance.boolValue); 194 | 195 | if (!useLuminance.boolValue) 196 | { 197 | SerializedProperty channel = m_InputTextureSettings[index].FindPropertyRelative("channel"); 198 | EditorGUILayout.PropertyField(channel, Styles.channel); 199 | } 200 | 201 | EditorGUILayout.Space(); 202 | 203 | EditorGUI.indentLevel--; 204 | } 205 | 206 | void DrawTextureImporterSettings() 207 | { 208 | SerializedProperty maxTextureSize = m_TexturePlatformSettings.FindPropertyRelative("m_MaxTextureSize"); 209 | SerializedProperty resizeAlgorithm = m_TexturePlatformSettings.FindPropertyRelative("m_ResizeAlgorithm"); 210 | SerializedProperty textureCompression = 211 | m_TexturePlatformSettings.FindPropertyRelative("m_TextureCompression"); 212 | SerializedProperty textureCompressionCrunched = 213 | m_TexturePlatformSettings.FindPropertyRelative("m_CrunchedCompression"); 214 | 215 | EditorGUILayout.LabelField("Texture Platform Settings", EditorStyles.boldLabel); 216 | using (new EditorGUI.IndentLevelScope()) 217 | { 218 | EditorGUI.BeginChangeCheck(); 219 | int sizeOption = EditorGUILayout.Popup("Texture Size", (int) Mathf.Log(maxTextureSize.intValue, 2) - 5, 220 | Styles.textureSizeOptions); 221 | if (EditorGUI.EndChangeCheck()) 222 | maxTextureSize.intValue = 32 << sizeOption; 223 | 224 | EditorGUI.BeginChangeCheck(); 225 | int resizeOption = EditorGUILayout.Popup("Resize Algorithm", resizeAlgorithm.intValue, 226 | Styles.resizeAlgorithmOptions); 227 | if (EditorGUI.EndChangeCheck()) 228 | resizeAlgorithm.intValue = resizeOption; 229 | 230 | EditorGUILayout.LabelField("Compression", EditorStyles.boldLabel); 231 | using (new EditorGUI.IndentLevelScope()) 232 | { 233 | EditorGUI.BeginChangeCheck(); 234 | bool explicitFormat = EditorGUILayout.Toggle(Styles.useExplicitTextureFormat, 235 | m_UseExplicitTextureFormat.boolValue); 236 | if (EditorGUI.EndChangeCheck()) 237 | m_UseExplicitTextureFormat.boolValue = explicitFormat; 238 | 239 | using (new EditorGUI.DisabledScope(explicitFormat)) 240 | { 241 | GUILayout.BeginHorizontal(); 242 | EditorGUI.BeginChangeCheck(); 243 | int compressionOption = EditorGUILayout.Popup("Texture Type", textureCompression.intValue, 244 | Styles.textureCompressionOptions); 245 | if (EditorGUI.EndChangeCheck()) 246 | textureCompression.intValue = compressionOption; 247 | 248 | EditorGUI.BeginChangeCheck(); 249 | var oldWidth = EditorGUIUtility.labelWidth; 250 | EditorGUIUtility.labelWidth = 100f; 251 | bool crunchOption = EditorGUILayout.Toggle(Styles.crunchCompression, 252 | textureCompressionCrunched.boolValue); 253 | EditorGUIUtility.labelWidth = oldWidth; 254 | if (EditorGUI.EndChangeCheck()) 255 | textureCompressionCrunched.boolValue = crunchOption; 256 | GUILayout.EndHorizontal(); 257 | } 258 | 259 | using (new EditorGUI.DisabledScope(!explicitFormat)) 260 | { 261 | EditorGUI.BeginChangeCheck(); 262 | 263 | int format = EditorGUILayout 264 | .EnumPopup("Texture Format", (TextureFormat) m_TextureFormat.intValue).GetHashCode(); 265 | 266 | if (EditorGUI.EndChangeCheck()) 267 | { 268 | if (!SystemInfo.SupportsTextureFormat((TextureFormat) format)) 269 | EditorGUILayout.HelpBox("Texture format unsupported.", MessageType.Warning, true); 270 | 271 | m_TextureFormat.intValue = format; 272 | } 273 | } 274 | } 275 | } 276 | } 277 | 278 | 279 | void CacheSerializedProperties() 280 | { 281 | SerializedProperty inputTextures = serializedObject.FindProperty("m_InputTextures"); 282 | SerializedProperty inputTexturesSettings = serializedObject.FindProperty("m_InputTextureSettings"); 283 | 284 | for (int i = 0; i < 4; ++i) 285 | { 286 | m_InputTextures[i] = inputTextures.GetArrayElementAtIndex(i); 287 | m_InputTextureSettings[i] = inputTexturesSettings.GetArrayElementAtIndex(i); 288 | } 289 | 290 | m_IsReadable = serializedObject.FindProperty("m_IsReadable"); 291 | m_sRGBTexture = serializedObject.FindProperty("m_sRGBTexture"); 292 | 293 | m_EnableMipMap = serializedObject.FindProperty("m_EnableMipMap"); 294 | m_StreamingMipMaps = serializedObject.FindProperty("m_StreamingMipMaps"); 295 | m_StreamingMipMapPriority = serializedObject.FindProperty("m_StreamingMipMapPriority"); 296 | 297 | m_FilterMode = serializedObject.FindProperty("m_FilterMode"); 298 | m_WrapMode = serializedObject.FindProperty("m_WrapMode"); 299 | m_AnisotropicLevel = serializedObject.FindProperty("m_AnisotropicLevel"); 300 | 301 | m_TexturePlatformSettings = serializedObject.FindProperty("m_TexturePlatformSettings"); 302 | m_TextureFormat = serializedObject.FindProperty("m_TextureFormat"); 303 | m_UseExplicitTextureFormat = serializedObject.FindProperty("m_UseExplicitTextureFormat"); 304 | } 305 | 306 | static void DrawMinMaxSlider(SerializedProperty property) 307 | { 308 | using (var horizontal = new EditorGUILayout.HorizontalScope()) 309 | { 310 | using (var propertyScope = new EditorGUI.PropertyScope(horizontal.rect, Styles.remapRange, property)) 311 | { 312 | var v = property.vector2Value; 313 | 314 | const int kFloatFieldWidth = 50; 315 | const int kSeparatorWidth = 5; 316 | 317 | float indentOffset = EditorGUI.indentLevel * 15f; 318 | var lineRect = EditorGUILayout.GetControlRect(); 319 | var labelRect = new Rect(lineRect.x, lineRect.y, EditorGUIUtility.labelWidth - indentOffset, 320 | lineRect.height); 321 | var floatFieldLeft = new Rect(labelRect.xMax, lineRect.y, kFloatFieldWidth + indentOffset, 322 | lineRect.height); 323 | var sliderRect = new Rect(floatFieldLeft.xMax + kSeparatorWidth - indentOffset, lineRect.y, 324 | lineRect.width - labelRect.width - kFloatFieldWidth * 2 - kSeparatorWidth * 2, lineRect.height); 325 | var floatFieldRight = new Rect(sliderRect.xMax + kSeparatorWidth - indentOffset, lineRect.y, 326 | kFloatFieldWidth + indentOffset, lineRect.height); 327 | 328 | EditorGUI.PrefixLabel(labelRect, propertyScope.content); 329 | v.x = EditorGUI.FloatField(floatFieldLeft, v.x); 330 | EditorGUI.MinMaxSlider(sliderRect, ref v.x, ref v.y, 0.0f, 1.0f); 331 | v.y = EditorGUI.FloatField(floatFieldRight, v.y); 332 | 333 | property.vector2Value = v; 334 | 335 | } 336 | 337 | } 338 | 339 | } 340 | } 341 | } -------------------------------------------------------------------------------- /Editor/SmartTextureImporterEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6897efd5ee27b4a3d84c5ee1d2bf4fa0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Felipe Lira 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0b1ef955611321d4c964399689ef1ef7 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SmartTexture Asset for Unity 2 | SmartTexture is a custom asset for Unity that allows you a [channel packing](http://wiki.polycount.com/wiki/ChannelPacking) workflow in the editortextures and use them in the Unity editor for a streamlined workflow. 3 | SmartTextures work as a regular 2D texture asset and you can assign it to material inspectors. 4 | 5 | Dependency tracking is handled by SmartTexture, that means you can change input textures and the texture asset will be re-generated. The input textures are editor only dependencies, they will not be included in the build, unless they are referenced by another asset or scene. 6 | 7 | inspector 8 | 9 | --- 10 | **NOTE** 11 | 12 | This package is still a Proof of Concept (POC) and it's still experimental. 13 | You can request features or submit bugs by creating new issues in the issue tab. For feature request please add "enhancement" label. 14 | 15 | --- 16 | 17 | 18 | ## Installation 19 | SmartTexture is a unity package and you can install it from Package Manager. 20 | 21 | Option 1: [Install package via Github](https://docs.unity3d.com/Manual/upm-ui-giturl.html). 22 | 23 | Option 2: Clone or download this Github project and [install it as a local package](https://docs.unity3d.com/Manual/upm-ui-local.html). 24 | 25 | ## How to use 26 | 1) Create a SmartTexture asset by clicking on `Asset -> Create -> Smart Texture`, or by right-clicking on the Project Window and then `Create -> Smart Texture`. 27 | create 28 | 29 | 2) An asset will be created in your project. 30 | asset 31 | 32 | 3) On the asset inspector you can configure input textures and texture settings for your smart texture. 33 | 4) Hit `Apply` button to generate the texture with selected settings. 34 | inspector 35 | 36 | 5) Now you can use this texture as any regular 2D texture in your project. 37 | assign 38 | 39 | ## Acknowledgements 40 | * Thanks to pschraut for [Texture2DArrayImporter](https://github.com/pschraut/UnityTexture2DArrayImportPipeline) project. I've used that project to learn a few things about ScriptedImporter and reused the code to create asset file. 41 | * Thanks to [Aras P.](https://twitter.com/aras_p) for guidance and ideas on how to create this. 42 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 348769316597fe54b9db2cd435d11a02 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e0298833e2c50e14fa9e8e2f3f06ce58 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Resources/PackChannel.compute: -------------------------------------------------------------------------------- 1 | // 2 | 3 | Texture2D _RedMap; 4 | Texture2D _GreenMap; 5 | Texture2D _BlueMap; 6 | Texture2D _AlphaMap; 7 | 8 | float4 _RedChannelParams; 9 | float4 _GreenChannelParams; 10 | float4 _BlueChannelParams; 11 | float4 _AlphaChannelParams; 12 | 13 | RWTexture2D _Output; 14 | float4 _OutputSize; 15 | 16 | sampler sampler_point_clamp; 17 | 18 | float MapSourceToChannel(float4 source, float channelOrParam, float2 remap) 19 | { 20 | // Invert? 21 | if (channelOrParam < 0) 22 | { 23 | channelOrParam = -channelOrParam; // reset 24 | source = float4(1, 1, 1, 1) - source; 25 | } 26 | 27 | float output; 28 | 29 | // Use luminance? 30 | if (channelOrParam >= 5) 31 | output = source.r * 0.3 + source.g * 0.59 + source.b * 0.11; // Photoshop desaturation : G*.59+R*.3+B*.11 32 | else 33 | output = source[channelOrParam-1]; 34 | 35 | return output * (remap.y - remap.x) + remap.x; 36 | } 37 | 38 | #pragma kernel PackChannelsCS THREADGROUP_SIZE=8 39 | [numthreads(THREADGROUP_SIZE, THREADGROUP_SIZE, 1)] 40 | void PackChannelsCS(uint2 id : SV_DispatchThreadID) 41 | { 42 | const uint2 size = (uint2)_OutputSize.xy; 43 | if (id.x >= size.x || id.y >= size.y) 44 | return; 45 | 46 | float2 sv = id + 0.5; 47 | float2 uv = sv * _OutputSize.zw; 48 | 49 | float4 color = float4(0, 0, 0, 0); 50 | color.r = MapSourceToChannel(_RedMap.SampleLevel(sampler_point_clamp, uv, 0), _RedChannelParams.x, _RedChannelParams.yz); 51 | color.g = MapSourceToChannel(_GreenMap.SampleLevel(sampler_point_clamp, uv, 0), _GreenChannelParams.x, _GreenChannelParams.yz); 52 | color.b = MapSourceToChannel(_BlueMap.SampleLevel(sampler_point_clamp, uv, 0), _BlueChannelParams.x, _BlueChannelParams.yz); 53 | color.a = MapSourceToChannel(_AlphaMap.SampleLevel(sampler_point_clamp, uv, 0), _AlphaChannelParams.x, _AlphaChannelParams.yz); 54 | 55 | _Output[id] = color; 56 | } -------------------------------------------------------------------------------- /Resources/PackChannel.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 96e7bd677a887f14aba97fecb97860c7 3 | ComputeShaderImporter: 4 | externalObjects: {} 5 | currentAPIMask: 4 6 | preprocessorOverride: 0 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 683872b7a9e58404d86a72f64355a908 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Philira.SmartTexture.Runtime.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Philira.SmartTexture.Runtime", 3 | "references": [], 4 | "includePlatforms": [ 5 | "Android", 6 | "Editor", 7 | "iOS", 8 | "LinuxStandalone64", 9 | "Lumin", 10 | "macOSStandalone", 11 | "PS4", 12 | "Switch", 13 | "tvOS", 14 | "WSA", 15 | "WebGL", 16 | "WindowsStandalone32", 17 | "WindowsStandalone64", 18 | "XboxOne" 19 | ], 20 | "excludePlatforms": [], 21 | "allowUnsafeCode": false, 22 | "overrideReferences": false, 23 | "precompiledReferences": [], 24 | "autoReferenced": true, 25 | "defineConstraints": [], 26 | "versionDefines": [], 27 | "noEngineReferences": false 28 | } -------------------------------------------------------------------------------- /Runtime/Philira.SmartTexture.Runtime.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9e705d6a72d9a354b810376671ddb3ac 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime/TextureChannelPacker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using UnityEngine.Experimental.Rendering; 4 | 5 | namespace SmartTexture 6 | { 7 | // TODO: Convert from sRGB to linear color space if necessary. 8 | // TODO: Texture compression / Format 9 | 10 | [Serializable] 11 | public enum TextureChannel 12 | { 13 | Red = 0, 14 | Green = 1, 15 | Blue = 2, 16 | Alpha = 3 17 | } 18 | 19 | [Serializable, Flags] 20 | public enum TextureChannelMask 21 | { 22 | Red = 1 << 0, 23 | Green = 1 << 1, 24 | Blue = 1 << 2, 25 | Alpha = 1 << 3, 26 | } 27 | 28 | /// 29 | /// Containts settings that apply color modifiers to each channel. 30 | /// 31 | [Serializable] 32 | public struct TexturePackingSettings 33 | { 34 | /// 35 | /// Outputs the inverted color (1.0 - color) 36 | /// 37 | public bool invertColor; 38 | 39 | /// 40 | /// Uses the combined rgb luminance factor. 41 | /// 42 | public bool useLuminance; 43 | 44 | /// 45 | /// Remaps the channel. 46 | /// 47 | public Vector2 remapRange; 48 | 49 | /// 50 | /// Outputs the selected channel. 51 | /// 52 | public TextureChannel channel; 53 | } 54 | 55 | public static class TextureExtension 56 | { 57 | static ComputeShader s_PackChannelCs; 58 | 59 | static ComputeShader packChannelCs 60 | { 61 | get 62 | { 63 | if (s_PackChannelCs == null) 64 | { 65 | s_PackChannelCs = Resources.Load("PackChannel"); 66 | } 67 | 68 | return s_PackChannelCs; 69 | } 70 | } 71 | 72 | static readonly int s_RedMap = Shader.PropertyToID("_RedMap"); 73 | static readonly int s_GreenMap = Shader.PropertyToID("_GreenMap"); 74 | static readonly int s_BlueMap = Shader.PropertyToID("_BlueMap"); 75 | static readonly int s_AlphaMap = Shader.PropertyToID("_AlphaMap"); 76 | 77 | static readonly int s_RedChannelParams = Shader.PropertyToID("_RedChannelParams"); 78 | static readonly int s_GreenChannelParams = Shader.PropertyToID("_GreenChannelParams"); 79 | static readonly int s_BlueChannelParams = Shader.PropertyToID("_BlueChannelParams"); 80 | static readonly int s_AlphaChannelParams = Shader.PropertyToID("_AlphaChannelParams"); 81 | 82 | static readonly int s_Output = Shader.PropertyToID("_Output"); 83 | static readonly int s_OutputSize = Shader.PropertyToID("_OutputSize"); 84 | 85 | public static void PackChannels(this Texture2D mask, Texture2D[] inputTextures, 86 | TexturePackingSettings[] settings, GraphicsFormat graphicsFormat, bool srgb, bool mipmaps) 87 | { 88 | if (inputTextures == null || inputTextures.Length != 4) 89 | { 90 | Debug.LogError("Invalid parameter to PackChannels. An array of 4 textures is expected"); 91 | return; 92 | } 93 | 94 | if (!packChannelCs) 95 | { 96 | Debug.LogError("Coudn't find `PackChannels` compute shader."); 97 | return; 98 | } 99 | 100 | if (settings == null) 101 | { 102 | settings = new TexturePackingSettings[4]; 103 | for (int i = 0; i < settings.Length; ++i) 104 | { 105 | settings[i].remapRange = new Vector2(0.0f, 1.0f); 106 | } 107 | } 108 | 109 | int width = mask.width; 110 | int height = mask.height; 111 | 112 | packChannelCs.SetTexture(0, s_RedMap, inputTextures[0] != null ? inputTextures[0] : Texture2D.blackTexture); 113 | packChannelCs.SetTexture(0, s_GreenMap, 114 | inputTextures[1] != null ? inputTextures[1] : Texture2D.blackTexture); 115 | packChannelCs.SetTexture(0, s_BlueMap, 116 | inputTextures[2] != null ? inputTextures[2] : Texture2D.blackTexture); 117 | packChannelCs.SetTexture(0, s_AlphaMap, 118 | inputTextures[3] != null ? inputTextures[3] : Texture2D.blackTexture); 119 | 120 | packChannelCs.SetVector(s_RedChannelParams, GetShaderChannelParams(settings[0])); 121 | packChannelCs.SetVector(s_GreenChannelParams, GetShaderChannelParams(settings[1])); 122 | packChannelCs.SetVector(s_BlueChannelParams, GetShaderChannelParams(settings[2])); 123 | packChannelCs.SetVector(s_AlphaChannelParams, GetShaderChannelParams(settings[3])); 124 | 125 | var rtForm = GraphicsFormatUtility.GetRenderTextureFormat(graphicsFormat); 126 | var rtDesc = new RenderTextureDescriptor(width, height, rtForm, 0) 127 | { 128 | sRGB = srgb, 129 | useMipMap = mipmaps, 130 | #if UNITY_2020_1_OR_NEWER 131 | mipCount = mipmaps ? mask.mipmapCount : 1, 132 | #endif 133 | autoGenerateMips = false, 134 | enableRandomWrite = true, 135 | }; 136 | 137 | var rt = new RenderTexture(rtDesc); 138 | rt.Create(); 139 | 140 | packChannelCs.SetTexture(0, s_Output, rt); 141 | packChannelCs.SetVector(s_OutputSize, new Vector4(width, height, 1.0f / width, 1.0f / height)); 142 | packChannelCs.Dispatch(0, (rt.width + 7) / 8, (rt.height + 7) / 8, 1); 143 | 144 | RenderTexture previous = RenderTexture.active; 145 | RenderTexture.active = rt; 146 | 147 | mask.ReadPixels(new Rect(0, 0, width, height), 0, 0, mipmaps); 148 | mask.Apply(mipmaps); 149 | 150 | RenderTexture.active = previous; 151 | rt.Release(); 152 | } 153 | 154 | static Vector4 GetShaderChannelParams(in TexturePackingSettings settings) 155 | { 156 | float channel = settings.useLuminance ? 5 : (int) settings.channel + 1; 157 | channel *= (settings.invertColor ? -1.0f : 1.0f); 158 | return new Vector4(channel, settings.remapRange.x, settings.remapRange.y, 0.0f); 159 | } 160 | } 161 | } -------------------------------------------------------------------------------- /Runtime/TextureChannelPacker.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d8c40e436475247d587a32d3a1d49cec 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Shaders.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: edae5c0bd738c41dc86b46b3b5f0924e 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Shaders/PackShader.shader: -------------------------------------------------------------------------------- 1 | Shader "Hidden/PackChannel" 2 | { 3 | Properties 4 | { 5 | _RedChannel("RedChannel", 2D) = "white" {} 6 | _GreenChannel("GreenChannel", 2D) = "white" {} 7 | _BlueChannel("BlueChannel", 2D) = "white" {} 8 | _AlphaChannel("AlphaChannel", 2D) = "white" {} 9 | _InvertColor("_InvertColor", Vector) = (0.0, 0.0, 0.0, 0.0) 10 | } 11 | 12 | HLSLINCLUDE 13 | Texture2D _RedChannel; 14 | Texture2D _GreenChannel; 15 | Texture2D _BlueChannel; 16 | Texture2D _AlphaChannel; 17 | sampler sampler_point_clamp; 18 | 19 | ENDHLSL 20 | 21 | SubShader 22 | { 23 | Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalRenderPipeline"} 24 | 25 | Pass 26 | { 27 | Tags { "LightMode"="Forward" } 28 | 29 | HLSLPROGRAM 30 | #pragma vertex vert 31 | #pragma fragment frag 32 | 33 | #include "HLSLSupport.cginc" 34 | #include "UnityShaderVariables.cginc" 35 | 36 | CBUFFER_START(UnityPerMaterial) 37 | float4 _RedChannel_TexelSize; 38 | half4 _InvertColor; 39 | CBUFFER_END 40 | 41 | float4 vert(float4 positionOS : POSITION) : SV_POSITION 42 | { 43 | return mul(UNITY_MATRIX_VP, mul(UNITY_MATRIX_M, float4(positionOS.xyz, 1.0))); 44 | //return TransformObjectToHClip(positionOS.xyz); 45 | } 46 | 47 | half4 frag(float4 positionHCS : SV_POSITION) : SV_Target 48 | { 49 | float2 uv = positionHCS * _RedChannel_TexelSize.xy; 50 | half r = _RedChannel.Sample(sampler_point_clamp, uv).r; 51 | half g = _GreenChannel.Sample(sampler_point_clamp, uv).r; 52 | half b = _BlueChannel.Sample(sampler_point_clamp, uv).r; 53 | half a = _AlphaChannel.Sample(sampler_point_clamp, uv).r; 54 | 55 | if (_InvertColor.x > 0.0) 56 | r = 1.0 - r; 57 | 58 | if (_InvertColor.g > 0.0) 59 | g = 1.0 - g; 60 | 61 | if (_InvertColor.b > 0.0) 62 | b = 1.0 - b; 63 | 64 | if (_InvertColor.a > 0.0) 65 | a = 1.0 - a; 66 | return half4(r, g, b, a); 67 | } 68 | ENDHLSL 69 | } 70 | } 71 | 72 | SubShader 73 | { 74 | Pass 75 | { 76 | HLSLPROGRAM 77 | #pragma vertex vert 78 | #pragma fragment frag 79 | 80 | #include "UnityCG.cginc" 81 | 82 | CBUFFER_START(UnityPerMaterial) 83 | float4 _RedChannel_TexelSize; 84 | half4 _InvertColor; 85 | CBUFFER_END 86 | 87 | float4 vert(float4 positionOS : POSITION) : SV_POSITION 88 | { 89 | return UnityObjectToClipPos(positionOS.xyz); 90 | } 91 | 92 | half4 frag(float4 positionHCS : SV_POSITION) : SV_Target 93 | { 94 | float2 uv = positionHCS * _RedChannel_TexelSize.xy; 95 | half r = _RedChannel.Sample(sampler_point_clamp, uv).r; 96 | half g = _GreenChannel.Sample(sampler_point_clamp, uv).r; 97 | half b = _BlueChannel.Sample(sampler_point_clamp, uv).r; 98 | half a = _AlphaChannel.Sample(sampler_point_clamp, uv).r; 99 | 100 | if (_InvertColor.x > 0.0) 101 | r = 1.0 - r; 102 | 103 | if (_InvertColor.g > 0.0) 104 | g = 1.0 - g; 105 | 106 | if (_InvertColor.b > 0.0) 107 | b = 1.0 - b; 108 | 109 | if (_InvertColor.a > 0.0) 110 | a = 1.0 - a; 111 | return half4(r, g, b, a); 112 | } 113 | ENDHLSL 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Shaders/PackShader.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7301b3a1d9d6947099451599aba74fde 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Tests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b06745750b9594648ae6e8a52b3dcf9e 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Tests/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8b831c344cdf9f14ab95279309d511a5 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Tests/Editor/Philira.SmartTexture.Editor.Tests.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Philira.SmartTexture.Editor.Tests", 3 | "references": [ 4 | "GUID:27619889b8ba8c24980f49ee34dbb44a", 5 | "GUID:0acc523941302664db1f4e527237feb3", 6 | "GUID:9e705d6a72d9a354b810376671ddb3ac" 7 | ], 8 | "includePlatforms": [ 9 | "Editor" 10 | ], 11 | "excludePlatforms": [], 12 | "allowUnsafeCode": false, 13 | "overrideReferences": true, 14 | "precompiledReferences": [ 15 | "nunit.framework.dll" 16 | ], 17 | "autoReferenced": false, 18 | "defineConstraints": [ 19 | "UNITY_INCLUDE_TESTS" 20 | ], 21 | "versionDefines": [], 22 | "noEngineReferences": false 23 | } -------------------------------------------------------------------------------- /Tests/Editor/Philira.SmartTexture.Editor.Tests.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4d7bdb677fe99a24bb5c724d97ffd1c3 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.phi-lira.smarttexture", 3 | "description": "Allows to create smart texture assets for Unity.", 4 | "version": "0.1.0", 5 | "unity": "2019.3", 6 | "displayName": "Smart Texture", 7 | "dependencies": { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 86eeb02d66d12f945ac8f9ca24c90772 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------