質問するログイン新規登録
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

702閲覧

Unity 2D Animationのボーンを使用して変形したスプライトを取得したい。

After

総合スコア1

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2024/01/23 07:51

0

0

実現したいこと

Unity2DAnimationを使用して、ボーンとSpriteSkinで変形したスプライトがあるのですが
そこから「ボーンで変形したスプライト」をテクスチャとして取得したいです。

ボーン変形したスプライトをテクスチャとして取得出来れば、
既存のアセットを使用して
自由変形させることが出来るので、そのためにテクスチャとして取得したいです。

ボーンにより無理やり自由変形する事も可能ではあるのですが、
どうしても自由変形できるアセットよりも
クオリティが落ちてしまうため ボーンではなくそのアセットで自由変形をしたいです。

発生している問題・分からないこと

SpriteSkinがスプライトを変形させてる、というのは分かったのですが
スプリクトなどはほとんど初心者のため、SpriteSkinから
どうやってボーン変形したスプライトを取得すれば良いのかがわかりませんでした。
もし可能でありましたら、解決のヒントなど頂けたらありがたいです。

該当のソースコード

特になし

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

teratailやグーグルで検索をかけたり、SpriteSkinのコードを読み解こうと試みたりしたのですが
変形した頂点の座標の位置などhttps://docs.unity3d.com/Packages/com.unity.2d.animation@5.0/api/UnityEngine.U2D.Animation.SpriteSkin.html
分かる関数などはあったのですが 変形したスプライトそのものの情報をどこで取得するのかが
わかりませんでした。

補足

Unity2022.3.12f1 Windows10

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

おっしゃるとおり変形後のメッシュの頂点座標は取得できるものの、変形後の画像を取得する機能は用意されていなさそうですね。
自前で別途レンダリングしてやらないといけないかもしれません。レンダリング用のスクリプトとして、下記のようなものを作ってみました。

C#

1using UnityEngine; 2using UnityEngine.Rendering; 3using UnityEngine.U2D.Animation; 4 5public static class SpriteSkinUtility 6{ 7 public static Sprite CaptureDeformedSprite(this SpriteSkin spriteSkin) 8 { 9 var renderer = spriteSkin.GetComponent<SpriteRenderer>(); 10 if (renderer == null) 11 { 12 Debug.LogError($"{nameof(SpriteRenderer)} not found."); 13 return null; 14 } 15 16 var sourceSprite = renderer.sprite; 17 if (sourceSprite == null) 18 { 19 Debug.LogError($"{nameof(Sprite)} not found."); 20 return null; 21 } 22 23 // 変形されたスプライトのバウンディングボックスを取得する 24 var bounds = renderer.localBounds; 25 var boundingRect = new Rect(bounds.min, bounds.size); 26 27 // テクスチャのサイズを決める 28 var pixelsPerUnit = sourceSprite.pixelsPerUnit; 29 var textureWidth = Mathf.RoundToInt(boundingRect.width * pixelsPerUnit); 30 var textureHeight = Mathf.RoundToInt(boundingRect.height * pixelsPerUnit); 31 32 // スプライト撮影にあたってオブジェクトの配置を操作したいので、後で元に戻すために現在の配置を覚えておく 33 var transform = renderer.transform; 34 var spriteParent = transform.parent; 35 var spriteScale = transform.localScale; 36 transform.GetLocalPositionAndRotation(out var spritePosition, out var spriteRotation); 37 38 // スプライトの配置を調整する 39 // 中心をワールド空間原点に置き、2m四方の正方形になるよう伸縮する 40 var scale = new Vector3(2.0f / boundingRect.width, 2.0f / boundingRect.height, 1.0f); 41 transform.SetParent(null, false); 42 transform.localScale = scale; 43 transform.SetLocalPositionAndRotation( 44 Vector3.Scale(-bounds.min - bounds.extents, scale), 45 Quaternion.identity); 46 47 // レンダーテクスチャ上にスプライトをレンダリングする 48 var currentTarget = RenderTexture.active; 49 var renderTexture = RenderTexture.GetTemporary(textureWidth, textureHeight); 50 RenderTexture.active = renderTexture; 51 var commands = new CommandBuffer(); 52 commands.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity); 53 commands.DrawRenderer(renderer, renderer.sharedMaterial); 54 Graphics.ExecuteCommandBuffer(commands); 55 commands.Dispose(); 56 57 // スプライトの配置を元に戻す 58 transform.SetParent(spriteParent, false); 59 transform.localScale = spriteScale; 60 transform.SetLocalPositionAndRotation(spritePosition, spriteRotation); 61 62 // レンダリング結果をTexture2Dに読み取って、それを使ったスプライトを作る 63 var spriteName = $"{sourceSprite.name} (Captured)"; 64 var texture = new Texture2D(textureWidth, textureHeight) 65 { 66 name = spriteName 67 }; 68 var textureRect = new Rect(0.0f, 0.0f, textureWidth, textureHeight); 69 texture.ReadPixels(textureRect, 0, 0); 70 texture.Apply(); 71 RenderTexture.active = currentTarget; 72 RenderTexture.ReleaseTemporary(renderTexture); 73 var sprite = Sprite.Create(texture, textureRect, -boundingRect.min / boundingRect.size, pixelsPerUnit); 74 sprite.name = spriteName; 75 return sprite; 76 } 77}

使用例として、下記のようにSpriteSkinを撮影して別のSpriteRendererに結果をセットするスクリプトを試してみたところ、

C#

1using UnityEngine; 2using UnityEngine.U2D.Animation; 3 4public class SpriteSetter : MonoBehaviour 5{ 6 [SerializeField] private SpriteSkin source; 7 [SerializeField] private SpriteRenderer destination; 8 9 private Sprite capturedSprite; 10 11 private void OnDestroy() 12 { 13 DestroySprite(this.capturedSprite); 14 } 15 16 private void OnGUI() 17 { 18 if ((this.source == null) || (this.destination == null)) 19 { 20 return; 21 } 22 23 if (GUILayout.Button("Capture")) 24 { 25 // 古いスプライトを削除し... 26 DestroySprite(this.capturedSprite); 27 28 // SpriteSkinをキャプチャーしたスプライトを作り... 29 this.capturedSprite = this.source.CaptureDeformedSprite(); 30 31 // 隣に配置してあるSpriteRendererにセットする 32 this.destination.sprite = this.capturedSprite; 33 } 34 } 35 36 // スプライトが使っているテクスチャも新しく作ったものなので、 37 // スプライトを削除したい時は併せてテクスチャも削除してやるといいでしょう 38 private static void DestroySprite(Sprite sprite) 39 { 40 if (sprite == null) 41 { 42 return; 43 } 44 45 Destroy(sprite.texture); 46 Destroy(sprite); 47 } 48}

下図のようにボタンクリック時のSpriteSkin(左側)を撮影し、別のSpriteRenderer(右側)に反映させることができました。

図

投稿2024/02/04 00:40

Bongo

総合スコア10816

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

After

2024/02/04 10:13

丁寧なお返事・お答え、誠にありがとうございます! スプリクトまで組んでくださり、本当にありがたいです・・・! また実装するスプリクトや動画によるわかりやすい参考例も、とてもありがたいです・・・! 自分でスプリクトじゃない範囲で試してみて カメラを使って無理やり 該当のスプライトだけを映すカメラを作り、RawImageで表示するやり方をやっていたのですが、 その場合だとレイヤーがその分、必要となり31個の制限を超えてしまう上に オブジェクト数も一つのスプライトに対して ボーン変形するスプライトとカメラとRawImageと かなり管理がし辛いヒエラルキー構成になってしまっていたため カメラを使わずに撮影出来ることは思いもよらなかったので、本当にありがたいです・・・! 重ねて、ご丁寧なスプリクトを書いてくださり、本当にありがとうございます・・・!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問