単色テクスチャを作るエディタスクリプト
不意に適当なサイズのテクスチャが欲しくなる時がありませんか?
私はあります。
一々Photoshopやペイントを立ち上げるのが面倒だったりするので。。
なので、エディタスクリプトで手軽にテクスチャを追加できる仕組みを作りました
using System.Collections.Generic; using System.IO; using UnityEngine; using UnityEditor; namespace ScreenPocket { public class TextureUtility { [MenuItem("Assets/ScreenPocket/Texture/Create")] static void Create() { OpenCreateTextureWindow((w,h,col) => { var icon = EditorGUIUtility.FindTexture("Texture2D Icon"); ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, new DoCreateTexture() { width = w, height = h, color = col }, "New Texture.png", icon, null); }); } static void OpenCreateTextureWindow(System.Action<int,int,Color> callback) { var w = EditorWindow.GetWindow<CreateTextureInformationWindow>(true, "テクスチャ作成"); w.callback = callback; w.position = new Rect(150f, 150f, 280f, 100f); } public static void Fill(Texture2D texture, Color color ) { for (int y = 0; y < texture.height; ++y) { for (int x = 0; x < texture.width; ++x) { texture.SetPixel(x, y, color); } } texture.Apply(); } } class DoCreateTexture : UnityEditor.ProjectWindowCallback.EndNameEditAction { public int width; public int height; public Color color; public override void Action(int instanceId, string pathName, string resourceFile) { var texture = new Texture2D( width, height ); texture.name = Path.GetFileNameWithoutExtension( pathName ); TextureUtility.Fill( texture, color ); byte[] bytes = texture.EncodeToPNG(); DestroyImmediate( texture ); File.WriteAllBytes(pathName, bytes); AssetDatabase.Refresh(); } } public class CreateTextureInformationWindow : EditorWindow { int w = 0; int h = 0; TextureImporterNPOTScale npotW = TextureImporterNPOTScale.None; TextureImporterNPOTScale npotH = TextureImporterNPOTScale.None; Color color = Color.white; public System.Action<int, int, Color> callback = null; void OnGUI() { EditorGUILayout.BeginHorizontal(); w = EditorGUILayout.IntField(w); EditorGUILayout.LabelField("x", GUILayout.Width(12f)); h = EditorGUILayout.IntField(h); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); GUI.enabled = !( Mathf.IsPowerOfTwo(w) ); npotW = (TextureImporterNPOTScale)EditorGUILayout.EnumPopup(npotW); GUI.enabled = !(Mathf.IsPowerOfTwo(h)); npotH = (TextureImporterNPOTScale)EditorGUILayout.EnumPopup(npotH); EditorGUILayout.EndHorizontal(); int finalW = w; int finalH = h; switch (npotW) { case TextureImporterNPOTScale.ToNearest: finalW = Mathf.ClosestPowerOfTwo(finalW); break; case TextureImporterNPOTScale.ToLarger: finalW = Mathf.NextPowerOfTwo(finalW); break; case TextureImporterNPOTScale.ToSmaller: finalW = Mathf.NextPowerOfTwo(finalW)/2; break; } switch (npotH) { case TextureImporterNPOTScale.ToNearest: finalH = Mathf.ClosestPowerOfTwo(finalH); break; case TextureImporterNPOTScale.ToLarger: finalH = Mathf.NextPowerOfTwo(finalH); break; case TextureImporterNPOTScale.ToSmaller: finalH = Mathf.NextPowerOfTwo(finalH)/2; break; } color = EditorGUILayout.ColorField(color); var isValidSize = !(finalW == 0 || finalH == 0); string msg = "サイズが不正なため、テクスチャを作成できません!"; if (isValidSize) { msg = finalW.ToString() + "x" + finalH.ToString() + " のテクスチャを作成します"; } EditorGUILayout.LabelField(msg); GUI.enabled = isValidSize; if (GUILayout.Button("Create")) { if (callback != null) { callback(w,h,color); } Close(); } GUI.enabled = true; } } }
使うときは Projectフォルダを右クリック > ScreenPocket > Texture > Create で、パネルを表示して入力して下さい。
OnGUI()内でEditorGUILayout.TextField()を呼ぶと例外
タイトルで完結してしまいましたが、この間やった凡ミスのメモ書き。
using UnityEngine; using UnityEditor; #if DEVELOPMENT_BUILD || UNITY_EDITOR namespace ScreenPocket { public class Hoge : MonoBehaviour { string inputText; void OnGUI() { inputText = EditorGUILayout.TextField(inputText); } } } #endif
と書いてしまって、NullReferenceExceptionを起こしてしまったので同じミスをしないようにメモ。
すぐには例外が出なくて、クリックした時に内部で例外を発するので気づくのが遅れた;
EditorGUILayout → GUILayout
にしましょう。
大きなサイズのpngテクスチャをMultipleSpriteで分割する
お久しぶりです。
マイルストーンやら転職やら、色々ありまして、半年ほど時期が開いてしまいました。
現在転職前の有給消化期間なので、趣味のプログラムを組んでいたのですが、
こちらのアセット
https://assetstore.unity.com/packages/2d/gui/cartoon-ui-pack-200-sprites-70518
を買った所、めちゃくちゃデカい画像だったので、ちょっと分割したいなぁと思い、Unity上で分割できないかどうかを試してみることにしました。
問題点は下記
・サイズが 3981x16104px と膨大
・UnityのTexture2Dアセットとして、Assetdatabase.LoadAsset()で読み込むと、2048(とか4096とかの設定した最大サイズ)で読み込まれてしまう。。
・どうせ分割するなら、解像度も担保したいし元々のサイズを基準に分割したい!
という事で、下記のスクリプトを作成しました。
using System.Collections.Generic; using System.IO; using UnityEngine; using UnityEditor; namespace ScreenPocket { public class TextureUtility { [MenuItem("Assets/ScreenPocket/Texture/DivideBySprite")] static void DivideTextureBySprite() { Object[] selections = Selection.GetFiltered(typeof(Object), SelectionMode.Assets | SelectionMode.DeepAssets); List<Texture2D> targets = new List<Texture2D>(selections.Length); foreach (var @object in selections) { var texture = @object as Texture2D; if (texture == null) { continue; } targets.Add(texture); } if (targets.Count == 0) { EditorUtility.DisplayDialog("Error", "NotFound Texture", "OK"); return; } foreach ( var targetTexture in targets) { var path = AssetDatabase.GetAssetPath(targetTexture); var importer = (TextureImporter)TextureImporter.GetAtPath( path ); if (importer.spriteImportMode != SpriteImportMode.Multiple) { EditorUtility.DisplayDialog("Error", "Not Multiple Speite" + importer.name, "OK"); continue; } //テクスチャ名と同一名のディレクトリを追加する var createDirectryPath = Path.GetDirectoryName(path) + "/" + Path.GetFileNameWithoutExtension(path); if (!Directory.Exists(createDirectryPath)) { Directory.CreateDirectory(createDirectryPath); } var isReadable = importer.isReadable; importer.isReadable = true; if (!isReadable) { importer.SaveAndReimport(); } var originalPngTexture = ReadPng(path); var spriteMetaDatas = importer.spritesheet; foreach (var spriteMetaData in spriteMetaDatas) { var spriteRect = spriteMetaData.rect; int x = Mathf.RoundToInt(spriteRect.x); int y = Mathf.RoundToInt(spriteRect.y); int w = Mathf.RoundToInt(spriteRect.width); int h = Mathf.RoundToInt(spriteRect.height); Texture2D newSpriteTexture = new Texture2D( w, h ); newSpriteTexture.SetPixels(originalPngTexture.GetPixels(x,y,w,h)); var pngData = newSpriteTexture.EncodeToPNG(); string filePath = GetSavePath(createDirectryPath, spriteMetaData.name); File.WriteAllBytes(filePath, pngData); } //Readableを戻す importer.isReadable = isReadable; if (!isReadable) { importer.SaveAndReimport(); } //TextureImporterを作るためにリフレッシュ AssetDatabase.Refresh(); //BorderとPivotを元のSpriteと合わせる foreach (var spriteMetaData in spriteMetaDatas) { string filePath = GetSavePath( createDirectryPath, spriteMetaData.name); var newImporter = (TextureImporter)TextureImporter.GetAtPath(filePath); bool isNeedSave = false; if (newImporter.spriteBorder != spriteMetaData.border) { newImporter.spriteBorder = spriteMetaData.border; isNeedSave = true; } TextureImporterSettings settings = new TextureImporterSettings(); newImporter.ReadTextureSettings(settings); if (settings.spritePivot != spriteMetaData.pivot) { settings.spritePivot = spriteMetaData.pivot; settings.spriteAlignment = spriteMetaData.alignment; newImporter.SetTextureSettings(settings); isNeedSave = true; } //大本のテクスチャのImporterと設定を合わせたいなら、ここで値を代入する処理を追加する if (isNeedSave) { newImporter.SaveAndReimport(); } } } AssetDatabase.SaveAssets(); } private static string GetSavePath(string parentDirectryName, string spriteMetaDataName) { return parentDirectryName + "/" + spriteMetaDataName + ".png"; } /// <summary> /// pngファイルをそのまま読み込む /// ↓参考サイト /// http://macomu.sakura.ne.jp/blog/?p=55 /// </summary> /// <param name="path"></param> /// <returns></returns> static byte[] ReadPngFile(string path) { FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read); BinaryReader bin = new BinaryReader(fileStream); byte[] values = bin.ReadBytes((int)bin.BaseStream.Length); bin.Close(); return values; } /// <summary> /// 対象パスのpngをそのまま読み込んでTexture2Dにする /// ※Texture2Dアセットを読み込むわけではないのでテクスチャサイズの制限を越えて取得できる /// ↓参考サイト /// https://qiita.com/r-ngtm/items/6cff25643a1a6ba82a6c /// </summary> /// <param name="path"></param> /// <returns></returns> static Texture2D ReadPng(string path) { byte[] readBinary = ReadPngFile(path); int pos = 16; // 16バイトから開始 int width = 0; for (int i = 0; i < 4; i++) { width = width * 256 + readBinary[pos++]; } int height = 0; for (int i = 0; i < 4; i++) { height = height * 256 + readBinary[pos++]; } Texture2D texture = new Texture2D(width, height); texture.LoadImage(readBinary); return texture; } } }
使用する際はProjectツリーで該当のテクスチャを右クリックして ScreenPocket > Texture > DivideBySprite を実行して下さい。
MultipleSpriteのテクスチャと同名のディレクトリを作成し、その中にスプライト名をファイル名としたpngを列挙します。
参考サイトは下記
UnityでPNGファイルを動的に読み込む方法 | ma_comu雑記帳
【Unity】pngファイルを読み込み同サイズのTexture2Dを生成する - Qiita
pngをそもそもTexture2Dアセットではなく、直接読み込んだ上でTexture2D化したい、という事で、上記のサイトのコードを使わせていただきました。
とりあえず上記でファイルを分割しつつ、MultipleSprite時のBorderとか、Pivotを引き継いだテクスチャが作成されるかと思います。
上記のコードで懸念としては、
Mathf.RoundToInt()で、ピクセルが少しずれてしまわないか?という点と、
Importer設定を完全に引き継いでいないので、もうちょっとしっかりコピーしたい点でしょうか。
使用する際は良い感じに書き換えてあげて下さいmm
CEPHtmlEngineによる高い使用率による問題、の解決策ファイル(DL224.zip)のある場所
全くプログラム関係ないですが、新年早々イライラ案件があったのでメモ。
家のPCでやけにCPU使用率が高く、Adobe製品を立ち上げた覚えもないのに CEPHtmlEngine タスクの使用率が高いことがわかりました。
※Photoshopのみインストール済み
で、見つけた記事がこちら。
helpx.adobe.com
解決策1の
>%USERPROFILE%\AppData\Local\Adobe\Creative Cloud Libraries\Logs
フォルダはなかったので、解決策2を参照。
指示通りにフォルダをバックアップを取って、DL224.zipをDLしようとしたら404が…。
どうせ日本語訳の際のリンク貼りミスだろう…、と思ったら案の定、元になったっぽいページから取得することが出来ました。
helpx.adobe.com
↑このページ内のDL224.zipリンクは生きてるっぽい
同じ探す苦労をする人が少しでも減ると良いですね;
SharedBetweenAnimatorsAttribute メモ
SharedBetweenAnimatorsAttribute を指定すると、メモリフットプリントを削減できるそうな。
ただ、変数の変更が他のAnimatorにも影響しちゃうみたい?
なので、振る舞いだけを書いた StateMachineBehaviour派生クラスだったら指定してみるのも良いかもしれませんね。
Photoshop クリッピングマスクをOn/Offするスクリプト
ScriptListenerでレコったのをメモ。
選択中レイヤーのクリッピングマスクON
var idGrpL = charIDToTypeID( "GrpL" ); var desc13 = new ActionDescriptor(); var idnull = charIDToTypeID( "null" ); var ref7 = new ActionReference(); var idLyr = charIDToTypeID( "Lyr " ); var idOrdn = charIDToTypeID( "Ordn" ); var idTrgt = charIDToTypeID( "Trgt" ); ref7.putEnumerated( idLyr, idOrdn, idTrgt ); desc13.putReference( idnull, ref7 ); executeAction( idGrpL, desc13, DialogModes.NO );
選択中レイヤーのクリッピングマスクOFF
var idUngr = charIDToTypeID( "Ungr" ); var desc11 = new ActionDescriptor(); var idnull = charIDToTypeID( "null" ); var ref6 = new ActionReference(); var idLyr = charIDToTypeID( "Lyr " ); var idOrdn = charIDToTypeID( "Ordn" ); var idTrgt = charIDToTypeID( "Trgt" ); ref6.putEnumerated( idLyr, idOrdn, idTrgt ); desc11.putReference( idnull, ref6 ); executeAction( idUngr, desc11, DialogModes.NO );
後は、選択中のArtLayerがクリッピングマスクかどうか判定できればトグルも作れそうですね
Photoshop CC用Scripting Listenerのダウンロード
地味に迷ったのでリンク紹介だけ
Adobe Photoshop Scripting | Adobe Developer Connection
現状このページの中段くらいにあります。
と思ったら、こっちにもあった。
後は
この辺とか
この辺を見ればインストールできるんじゃないかと。