ライセンスについて
Spineランタイムをアプリケーションに組み込むにはSpineライセンスが必要です。
主要なコンポーネント
spine-unityランタイムは、Spineからエクスポートされたスケルトンの表示、アニメーション、追従および修正を可能にするコンポーネントのセットを提供します。これらのコンポーネントは、アセットセクションで説明されているインポートされたスケルトンデータとテクスチャアトラスアセットを参照します。
スケルトンをシーンに追加する
ご自身のUnityプロジェクトにSpineスケルトンを素早く表示するには :
- アセットセクションで説明されているスケルトンデータとテクスチャアトラスをインポートします。
- _SkeletonDataアセットをSceneビューまたはHierarchyパネルにドラッグし、
SkeletonAnimation
を選択します。すると、あらかじめ必要なSpineコンポーネントが設定された新しいGameObjectがインスタンス化されます。
補足: STEP2の代わりに、同じGameObjectをいちから作ることもできます :
GameObject -> Create Empty
で空のGameObjectを新規作成します。- GameObjectを選択し、Inspectorで
Add Component
をクリックして、SkeletonAnimation
を選択します。これを行うと、追加のMeshRenderer
とMeshFilter
コンポーネントも自動的に追加されます。- SkeletonAnimationコンポーネントへ、必要な
Skeleton Data Asset
をドラッグして、_SkeletonDataプロパティに割り当てます。
注意: Sceneビューで、画像がアタッチされていないボーンだけのスケルトンが表示されてしまう場合、
Initial Skin
プロパティをdefault
以外のスキンに切り替えると良いでしょう。
これで、コンポーネントのC# APIを使って、スケルトンをアニメーションさせたり、アニメーション中で発生するイベントへの反応などができるようになります。詳細は後述のコンポーネントのドキュメントを参照してください。
SkeletonAnimationの代わりとなるもの - SkeletonGraphic (UI) と SkeletonMecanim
UnityでSpineスケルトンを使用する上で推奨される方法はSkeletonAnimationとしてスケルトンをインスタンス化することで、3つの選択肢の中で最も完全な機能セットを提供します。
スケルトンをインスタンス化するには、3つの選択肢があります:
- SkeletonAnimation - Spineのカスタムアニメーションとイベントシステムを使用し、最高のカスタマイズ性を実現しています。レンダリングには
MeshRenderer
を使用し、Unityのスプライトと同様にSpriteMask
などのマスクと連動します。 これがUnityでSpineのスケルトンを使用する際に推奨されている方法です。 - SkeletonGraphic (UI) - Unity
Canvas
と共にUI要素として使用します。RectMask2D
のようなUIマスクを、Unityに元から入っているUI要素のようにレンダリングおよび作用させることができます。アニメーションとイベントの動作はSkeletonAnimationと同じです。 - SkeletonMecanim - UnityのMecanimアニメーションとイベントシステムを使用して、アニメーションの開始、ミキシング、アニメーション間の移行(トランジション)を行います。SkeletonAnimationに比べて、アニメーションのミキシングやトランジションの選択肢が少ないという欠点があります。また、
SkeletonMecanim
を使用した場合、トランジションがSpineエディターでプレビューされた通りに表示されるかは保証されません。
高度な情報 - 実行中でのインスタンス化
注意: 通常のワークフローでは、シーンにスケルトンを追加してプレハブに格納するか、インスタンスプールからプールされたオブジェクトを再利用してインスタンス化するのが望ましいです。その方がカスタマイズや調整が容易になります。
推奨されるワークフローではありませんが、spine-unity APIでは、SkeletonDataAsset
から、またはエクスポートされた3つのアセットから直接、実行中に SkeletonAnimation
と SkeletonGraphic
をインスタンス化することができます。エクスポートされたアセットから直接インスタンスを作成するのは、通常のUnityインポートパイプラインでは SkeletonDataAsset
と SpineAtlasAsset
を事前に自動作成できない場合にのみ行うことを推奨します。
SkeletonAnimation instance = SkeletonAnimation.NewSkeletonAnimationGameObject(skeletonDataAsset);
// SkeletonGraphic GameObject を SkeletonDataAsset からインスタンス化する
SkeletonGraphic instance
= SkeletonGraphic.NewSkeletonGraphicGameObject(skeletonDataAsset, transform, skeletonGraphicMaterial);
// 1. AtlasAssetを作成します (atlas.textアセットとテクスチャ、マテリアル/シェーダーが必要です);
// 2. SkeletonDataAssetを作成します (JSONまたはバイナリアセットファイル、およびAtlasAssetが必要です)
SpineAtlasAsset runtimeAtlasAsset
= SpineAtlasAsset.CreateRuntimeInstance(atlasTxt, textures, materialPropertySource, true);
SkeletonDataAsset runtimeSkeletonDataAsset
= SkeletonDataAsset.CreateRuntimeInstance(skeletonJson, runtimeAtlasAsset, true);
// 3. SkeletonAnimationを作成します(有効なSkeletonDataAssetが必要です)
SkeletonAnimation instance = SkeletonAnimation.NewSkeletonAnimationGameObject(runtimeSkeletonDataAsset);
サンプルシーン Spine Examples/Other Examples/Instantiate from Script
や、そこで使用されているサンプルスクリプト SpawnFromSkeletonDataExample.cs
、RuntimeLoadFromExportsExample.cs
、SpawnSkeletonGraphicExample.cs
でさらに詳しく確認できます。
SkeletonAnimationコンポーネント
SkeletonAnimation
コンポーネントは、SpineスケルトンをUnityで使用する3つの方法のうちの1つです。3つの方法とは、SkeletonAnimation、SkeletonMecanim、SkeletonGraphic (UI)のことです。
SkeletonAnimationコンポーネントは、spine-unityランタイムの核となるものです。SpineスケルトンをGameObjectに追加し、そのスケルトンをアニメーションさせたり、アニメーションイベントに反応させたりすることができます。
Skeleton Data設定
SkeletonAnimationコンポーネントは、スケルトンのボーン階層やスロットなどの情報を取得できるスケルトンデータアセットへの参照を必要とします。
スケルトンをドラッグ&ドロップでSceneに追加した場合、そのスケルトンデータアセットが自動的に割り当てられます。 既に設定されているGameObjectがあってそのスケルトンを別のアセットに変更したくなった場合は、Inspectorプロパティを使って手動で変更することができます。
スケルトンデータを設定・変更するには
- SkeletonAnimation GameObjectを選択します。
- Inspectorの
SkeletonData Asset
プロパティに _SkeletonData アセットを割り当てます。
初期スキンとアニメーションの設定
SkeletonAnimationのInspectorは以下のパラメーターを公開しています :
- Initial Skin : ここで設定したスキンがスタート時に割り当てられます。 注意: 画像がアタッチされていないボーンだけのスケルトンが表示されている場合は、
default
以外のスキンに切り替えて、スキンを表示した方が良いでしょう。 - Animation Name : ここで設定したアニメーションがスタート時に再生されます。
- Loop : 初期アニメーションをループさせるか、一度だけ再生するかを定義します。
- Time Scale : ここでタイムスケールを設定することで、アニメーションの再生を遅くしたり、速くしたりすることができます。
- Unscaled Time :
true
に設定すると、アップデートが Time.deltaTime の代わりに Time.unscaledDeltaTime に従って実行されます。これはスローモーションなどの影響を受けずに独立したUI要素をアニメーションさせたい場合などに便利です。
ルートモーションの有効化
SkeletonAnimation
およびSkeletonGraphic (UI)コンポーネントのルートモーションは、別のSkeletonRootMotionコンポーネントを介して提供されます。SkeletonAnimation
のInspectorには Root Motion
Add Component
ボタンがあり、適切なコンポーネントをスケルトンのGameObjectに素早く追加できます。
高度なパラメーターの設定
SkeletonAnimationのInspectorのAdvanced
セクションを展開すると、高度な設定パラメーターが表示されます。
SkeletonAnimationのInspectorでは、以下の詳細なパラメーターを公開しています
- Initial Flip X、Initial Flip Y : これらのパラメーターは、スタート時にスケルトンを水平または垂直方向に反転させることができます。これにより、反転した部分のScaleXとScaleYが-1になります。
- Animation Update : 通常の
Update
(デフォルト)、物理ステップFixedUpdate
、またはユーザーコールによる手動アニメーション更新のいずれかを指定します。Rigidbody
またはRigidbody2D
が割り当てられたSkeletonRootMotionコンポーネントを使用する場合、更新モードをIn FixedUpdate
に設定することをお勧めします。それ以外の場合は、In Update
を推奨します。 - Update When Invisible : MeshRendererが非表示になったときに使用されるアップデートモードを設定します。メッシュが再び表示されるようになると、アップデートモードは自動的に
UpdateMode.FullUpdate
にリセットされます。 - Use single submesh : 1つのマテリアルのみを使用し、1つのサブメッシュのみを必要とすると前提した場合に、サブメッシュの生成を簡素化するために有効にすることができます。これは、複数マテリアルの使用、レンダリングの分割、カスタムスロットマテリアルを無効にします。
- Fix Draw Order : この設定は3つ以上のサブメッシュが使用されている場合のみ適用されます(2つ以上のマテリアルが交互に並んでいる場合、例:「A B A」)。trueの場合、MaterialPropertyBlockが各マテリアルに割り当てられ、LWRPレンダラーなどによるサブメッシュの積極的なバッチ処理を防ぎ、誤った描画順序になるのを防ぎます(例:「A1 B A2」が「A1 A2 B」に変更される等)。すべてが正しく描画されている場合は、このパラメーターを無効にしておくことでパフォーマンスコストを節約することができます。
- Immutable triangles : この設定は、アタッチメントの表示状態を変更することが無いスケルトンのレンダリングを最適化するために有効にすることができます。trueの場合、三角形が更新されなくなります。スケルトンがアタッチメントの切り替えや非表示、または描画順序キーを使用しない場合、最適化のためにこれを有効にします。そうでない場合は、これをfalseに設定するとレンダリングでエラーが発生する可能性があります。
- Clear State on Disable : このコンポーネントまたはそのGameObjectが無効になったときに、レンダーとスケルトンの状態をクリアする設定です。これにより、再び有効になったときに以前の状態が保持されるのを防ぐことができます。スケルトンをプールする場合は、これをtrueに設定すると便利です。
- Fix Prefab Override MeshFilter : Prefabが常に変更されたものとしてマークされるのを修正します(
MeshFilter
の非表示フラグをDontSaveInEditor
に設定)。 ただし、他のコンポーネントからのMeshFilter
への参照は失われます。Use Global Settings
に設定すると、Spine Preferencesの設定が使用されます。 - Separator Slot Names : レンダリングを分割する場所を決めるスロットを設定します。これは
SkeletonRenderSeparator
などのコンポーネントで使用され、スケルトンを異なるGameObject上に2つの別々のレンダラーでレンダリングすることができます。 - Z-Spacing : この設定を変更すると、アタッチメントが
SkeletonRenderer
コンポーネントによって、x/y平面上で前後にレンダリングされるようになります。各アタッチメントが、z軸上のカスタマイズ可能なz-spacing値によってオフセットされ、Zファイティング(z-fighting)を回避します。
- PMA Vertex Colors : 頂点カラーRGBと頂点カラーアルファを乗算します。レンダリングに使用されているシェーダーがSpineシェーダー(
ストレートアルファテクスチャ
を使用している場合も)またはPMAのAdditive(加算)ブレンドモードBlend One OneMinusSrcAlpha
を使用するサードパーティ製シェーダーの場合、このパラメーターを有効にしてください。通常のブレンドモードBlend SrcAlpha OneMinusSrcAlpha
を伴う通常のシェーダーの場合は、このパラメーターを無効にしてください。有効にすると、加算スロットを通常スロットと一緒に1回のドローコールでレンダリングできます。無効にすると、加算スロットのためにSkeletonData
の Blend Mode Materials - Apply Additive Material を有効にする必要があり、このために別のドローコールが必要になってしまうので、パフォーマンスに悪影響を与える可能性があります。 - Tint Black (!) : ブラックティントの頂点データをメッシュに追加します。スケルトンの中にティントブラックが設定されたスロットがあれば有効にしてください。 ブラックティントは、この効果が機能するために、シェーダーがUV2とUV3をブラックティントカラーとして解釈する必要があります。そのために付属の
Spine/Skeleton Tint Black
シェーダーを使用することができます。個々のパーツではなくスケルトン全体を着色する必要がある場合は、効率が良く、MaterialPropertyBlockで_Black
マテリアルプロパティを変更およびアニメーションさせることができるSpine/Skeleton Tint
シェーダーをお勧めします。詳しくはシェーダーセクションを参照してください。複数のスケルトンを異なる方法でティントする際にバッチングを維持するにはSkeleton.R .G .B .Aによるティントをお勧めします。 - Add Normals : 有効にすると、メッシュジェネレーターは出力メッシュに法線を追加します。使用するシェーダーが頂点法線を必要とする場合に有効にしてください。パフォーマンスを向上させ、メモリ使用量を削減するには、代わりに
Spine/Skeleton Lit
シェーダーのような、希望する法線を想定するシェーダーを使用することができます。Spine/Sprite
シェーダーはFixed Normal
を仮定するようにも設定できることに注意してください。 - Solve Tangents : 一部のライトシェーダーは、通常、ノーマルマップ(法線マップ)を適用するために、頂点接線を必要とします。有効にすると、毎フレームで接線が計算され、出力メッシュに追加されます。
- Physics Inheritance : トランスフォームの動きをスケルトンの物理コンストレイントに適用する方法を制御します。
- Position : ゼロ以外に設定すると、X方向およびY方向のトランスフォームの位置移動がスケルトンの物理コンストレイントに適用され、ここで設定したXおよびYのスケール係数で乗算されます。一般的な組み合わせは以下の通りです:
(1,1) にした場合、XY移動が通常通り適用されます。
(2,2) にした場合、XY移動が倍の強さで適用されます。
(1,0) にした場合、水平方向の移動だけが適用されます。
(0,0) にした場合、トランスフォームの移動の動きは全く適用されなくなります。 - Rotation : ゼロ以外に設定すると、トランスフォームの回転の動きがスケルトンの物理コンストレイントに適用され、ここで設定したスケール係数で乗算されます。一般的な値は以下の通りです:
1 にした場合、通常通り適用されます。
2 にした場合、倍の強さで適用されます。
0 にした場合、トランスフォームの回転の動きは全く適用されなくなります。 - Movement relative to 親トランスフォームなどに対する相対的なトランスフォームの動きを適用するには、これを動きを計算する基準となるトランスフォームに設定します。None に設定すると、ワールドの絶対位置(デフォルト)を使用します。
- Position : ゼロ以外に設定すると、X方向およびY方向のトランスフォームの位置移動がスケルトンの物理コンストレイントに適用され、ここで設定したXおよびYのスケール係数で乗算されます。一般的な組み合わせは以下の通りです:
- Add Skeleton Utility : このボタンを使用すると、ボーンの位置をトラッキングしたり、オーバーライドしたりするための
SkeletonUtility
コンポーネントをGameObjectに素早く追加することができます。詳しくはSkeletonUtilityを参照してください。 - Debug : ゲームの実行中にスロットの現在のカラーやボーンのスケール値などの情報を知りたい時は、Debugボタンを押せばデバッグ用のSkeleton Debugウィンドウを開けます。ここで、ボーン、スロット、コンストレイント、表示順序、イベント、スケルトンの統計情報などの現在の状態を確認することができます。
ライフサイクル
SkeletonAnimationコンポーネントでは、AnimationStateが現在再生中のアニメーションやキューされたアニメーションのステート(状態)を保持しています。 Update
ごとにAnimationStateが更新され、アニメーションが時間的に進むようになります。そして、新しいフレームが新しいポーズとしてスケルトンに適用されます。
スクリプトは、SkeletonAnimationの Update
の前でも後でも実行できます。 あなたのコードがSkeletonAnimationのUpdateの前にスケルトンまたはボーンの値を取得する場合、コードは現在のフレームではなく前のフレームから値を読み取ります。
このコンポーネントは、イベントコールバックデリゲートをプロパティとして公開しており、すべてのボーンのワールドトランスフォームが計算される前と後に、このライフサイクルをインターセプトすることができます。これらのデリゲートにバインドすることで、アクターやコンポーネントの更新順序を気にすることなく、ボーンの位置やスケルトンの他の側面を修正することができます。
SkeletonAnimation Update コールバック
SkeletonAnimation.BeforeApply
は、そのフレームのアニメーションが適用される前に発生します。このコールバックは、アニメーションが適用される前にスケルトンの状態を変更したい場合に使用します。SkeletonAnimation.UpdateLocal
は、そのフレームのアニメーションが更新され、スケルトンのローカル値に適用された後に発生します。ボーンのローカル値を読み込んだり修正したりする必要がある場合に使用します。SkeletonAnimation.UpdateComplete
は、Skeletonのすべてのボーンに対してワールド値が計算された後に発生します。SkeletonAnimationは、この後、Updateでそれ以上の操作をしません。ボーンのワールド値を読み取る必要がある場合は、これを使用してください。これらの値は、SkeletonAnimationのUpdate後にスクリプトが変更すると、まだ変更される可能性があります。SkeletonAnimation.UpdateWorld
は、Skeletonのすべてのボーンについてワールド値が計算された後に発生します。このイベントをサブスクライブすると、skeleton.UpdateWorldTransform
が2回目に呼び出されます。スケルトンの複雑さやあなたがやっていることによっては、これは不要であったり、無駄であったりします。このイベントは、ボーンのワールド値に基づいて、ボーンのローカル値を修正する必要がある場合に使用します。これは、Unityのコードでカスタムコンストレイントを実装するのに便利です。
void AfterUpdateComplete (ISkeletonAnimation anim) {
// これはアニメーションの更新が完了した後に呼び出されます
}
// あなたのデリゲートメソッドを登録
void Start() {
skeletonAnimation.UpdateComplete -= AfterUpdateComplete;
skeletonAnimation.UpdateComplete += AfterUpdateComplete;
}
SkeletonRenderer Update コールバック
OnRebuild
は、スケルトンが正常に初期化された後に発生します。OnMeshAndMaterialsUpdated
は、メッシュとすべてのマテリアルが更新された後、LateUpdate()
の最後に発生します。
void AfterMeshAndMaterialsUpdated (SkeletonRenderer renderer) {
// これはメッシュとマテリアルが更新された後に呼び出されます
}
// OnRebuild 用のデリゲートメソッド
void AfterRebuild (SkeletonRenderer renderer) {
// これはスケルトンが正常に初期化された後に呼び出されます
}
// あなたのデリゲートメソッドを登録
void Start() {
skeletonAnimation.OnMeshAndMaterialsUpdated -= AfterMeshAndMaterialsUpdated;
skeletonAnimation.OnMeshAndMaterialsUpdated += AfterMeshAndMaterialsUpdated;
skeletonAnimation.OnRebuild -= AfterRebuild;
skeletonAnimation.OnRebuild += AfterRebuild;
}
別の方法として、スクリプトの実行順序をSkeletonAnimationのUpdateメソッドの後に実行するように変更することもできます。
UnityのMonoBehaviourのライフサイクルについては、こちらをご覧ください: docs.unity3d.com/Manual/ExecutionOrder
C#
スケルトンをコードで操作するには、SkeletonAnimationコンポーネントにアクセスする必要があります。一般的なUnityコンポーネントと同様に、一度リファレンスを参照して、その後の使用のために保存しておくことをお勧めします。
using Spine.Unity;
public class YourComponent : MonoBehaviour {
SkeletonAnimation skeletonAnimation;
Spine.AnimationState animationState;
Spine.Skeleton skeleton;
void Awake () {
skeletonAnimation = GetComponent<SkeletonAnimation>();
skeleton = skeletonAnimation.Skeleton;
//skeletonAnimation.Initialize(false); // skeletonAnimation.Skeletonにアクセスしない場合
// Initialize(false)を使用して、すべてがロードされていることを確認します。
animationState = skeletonAnimation.AnimationState;
}
Skeleton
SkeletonAnimationコンポーネントは、SkeletonAnimation.Skeleton
プロパティを介して、基礎となるSkeletonへのアクセスを提供します。Skeletonには、スケルトンデータアセットへの参照が格納されており、このアセットは1つまたは複数のアトラスアセットを参照します。
Skeletonでは、スキンやアタッチメントを設定したり、ボーンをリセットしてポーズやスケールを設定したり、スケルトン全体を反転させたりすることができます。
アタッチメントの設定
アタッチメントを設定するには、スロットとアタッチメント名を入力します。
[SpineSlot] public string slotProperty = "slotName";
[SpineAttachment] public string attachmentProperty = "attachmentName";
...
bool success = skeletonAnimation.Skeleton.SetAttachment(slotProperty, attachmentProperty);
上記コード中の[SpineSlot]
と[SpineAttachment]
は、こちらのセクションで説明しているStringのプロパティ属性(Attribute)です。
セットアップポーズへのリセット
プロシージャルなアニメーションでは、ボーンやスロットをセットアップのポーズに戻すことが必要な場合があります。スキンを設定した後は、後述のスキンの設定セクションで説明するように Skeleton.SetSlotsToSetupPose
を呼び出す必要があるケースが多いでしょう。
skeleton.SetBonesToSetupPose();
skeleton.SetSlotsToSetupPose();
スキンの設定
Spineスケルトンは、どのアタッチメントをどのスロットに装着するかを定義する複数のスキンを持っている場合があります。Skeletonコンポーネントは、スキンを切り替える簡単な方法を提供します。
skeletonAnimation.Skeleton.SetSlotsToSetupPose(); // 後述の補足を参照
[SpineSkin] public string skinProperty = "skinName";
...
bool success = skeletonAnimation.Skeleton.SetSkin(skinProperty);
skeletonAnimation.Skeleton.SetSlotsToSetupPose(); // 後述の補足を参照
以前に設定したアタッチメントが現在のアタッチメントの表示に影響するのを避けたい場合、スキンを変更した後に Skeleton.SetSlotsToSetupPose
を呼び出す必要があります。詳細はこちらのドキュメントを参照してください。
スキンの組み合わせ
Spineスキンは組み合わせることが可能です。例えば、衣装アイテムスキンを組み合わせて完全なキャラクタースキンを形成することができます。 詳細は、新しいSkin APIドキュメントをご覧ください。
var skeletonData = skeleton.Data;
var mixAndMatchSkin = new Skin("custom-girl");
mixAndMatchSkin.AddSkin(skeletonData.FindSkin("skin-base"));
mixAndMatchSkin.AddSkin(skeletonData.FindSkin("nose/short"));
mixAndMatchSkin.AddSkin(skeletonData.FindSkin("eyelids/girly"));
mixAndMatchSkin.AddSkin(skeletonData.FindSkin("eyes/violet"));
mixAndMatchSkin.AddSkin(skeletonData.FindSkin("hair/brown"));
mixAndMatchSkin.AddSkin(skeletonData.FindSkin("clothes/hoodie-orange"));
mixAndMatchSkin.AddSkin(skeletonData.FindSkin("legs/pants-jeans"));
mixAndMatchSkin.AddSkin(skeletonData.FindSkin("accessories/bag"));
mixAndMatchSkin.AddSkin(skeletonData.FindSkin("accessories/hat-red-yellow"));
skeleton.SetSkin(mixAndMatchSkin);
skeleton.SetSlotsToSetupPose();
skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton); // SkeletonMecanimの場合は skeletonMecanim.Update() を使用してください
ランタイムでの再パッキング
スキンを組み合わせると、複数のマテリアルが蓄積されることがあります。しかしこれは、ドローコールの増加につながってしまいます。 Skin.GetRepackedSkin()
メソッドを使えば、収集したスキンに使用されているテクスチャ領域を、実行時に単一のテクスチャにまとめることができます。
// 再パックされたスキンを作成します。
Skin repackedSkin = collectedSkin.GetRepackedSkin("Repacked skin", skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial, out runtimeMaterial, out runtimeAtlas);
collectedSkin.Clear();
// 再パックされたスキンを使用します。
skeletonAnimation.Skeleton.Skin = repackedSkin;
skeletonAnimation.Skeleton.SetSlotsToSetupPose();
skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton); // skeletonMecanim.Update() for SkeletonMecanim
// オプションとして、複数の再パック操作後にキャッシュをクリアすることができます。
AtlasUtilities.ClearCache();
重要な注意事項: 再パッキングに失敗したり、予期せぬ結果になる場合は、以下の原因が考えられます。:
- Read/Writeが無効になっている : プラットフォームの性能によっては、再パックされたテクスチャに結合されるソーステクスチャに
Read/Write Enabled
パラメーターを設定する必要があります。- Compressionが有効になっている : プラットフォームによっては、ソーステクスチャのテクスチャインポート設定の
Compression
がNormal Quality
ではなくNone
に設定されていることを確認してください。- Qualityの設定で、半分または1/4の解像度のテクスチャを使用している : 半分または1/4の解像度のテクスチャが使用されている場合、正しくない領域がコピーされるというUnityの既知のバグがあります。Project SettingsのQualityの設定がすべてフル解像度のテクスチャを使用していることを確認してください。
- ソーステクスチャが2のべき乗になっていなくてもUnityがそれを最も近い累乗に拡大している : このため、a)パック設定の
Power of two(2のべき乗)
を有効にしてSpineからエクスポートするか、b)Unityのアトラステクスチャのインポート設定でNon-Power of Two
がNone
になっていることを確認してください。
さらに深く理解するには、サンプルシーンの Spine Examples/Other Examples/Mix and Match
と Spine Examples/Other Examples/Mix and Match Equip
、そして使用されている MixAndMatch.cs
のサンプルスクリプトを参考にしてください。
高度な情報 - ノーマルマップと一緒にランタイムで再パッキングする
メインテクスチャと一緒に、ノーマルマップ(法線マップ)やその他の追加テクスチャレイヤーを再パックすることもできます。 int[] additionalTexturePropertyIDsToCopy = new int[] { Shader.PropertyToID("_BumpMap") };
を GetRepackedSkin()
のパラメーターとして渡すことで、メインテクスチャとノーマルマップ(法線マップ)レイヤーの両方を再パックすることができます。
Texture2D runtimeAtlas;
Texture2D[] additionalOutputTextures = null;
int[] additionalTexturePropertyIDsToCopy = new int[] { Shader.PropertyToID("_BumpMap") };
Skin repackedSkin = prevSkin.GetRepackedSkin("Repacked skin", skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial, out runtimeMaterial, out runtimeAtlas,
additionalTexturePropertyIDsToCopy : additionalTexturePropertyIDsToCopy, additionalOutputTextures : additionalOutputTextures);
// 再パックされたスキンを使用します。
skeletonAnimation.Skeleton.Skin = repackedSkin;
skeletonAnimation.Skeleton.SetSlotsToSetupPose();
skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton); //SkeletonMecanimの場合はskeletonMecanim.Update()
注意: 通常、ノーマルマップ(法線マップ)のプロパティは
"_BumpMap"
という名前になっていますが、カスタムシェーダーを使用する場合は、必ずそれぞれのプロパティ名を使用してください。なお、この名前はシェーダー内のプロパティ名であり、Inspectorに表示される"Normal Map"
ラベル文字列ではないことに注意してください。
スケルトンのスケール変更と反転
スケルトンを垂直または水平方向に反転させることで、アニメーションを再利用することができます。例えば、左向きの歩行アニメーションを右向きにして再生することができます。
skeleton.ScaleX = -1;
bool isFlippedY = skeleton.ScaleY < 0;
skeleton.ScaleY = -1;
skeleton.ScaleX = -skeleton.ScaleX; // x反転の状態を切り替え
ボーントランスフォームへの手動アクセス
注意: こちらは非常に特殊なケースでのみ使用することをお勧めします。 SpineのBoneFollowerやSkeletonUtilityBoneコンポーネントの方がより簡単にボーンを操作することができます。
Skeletonでは、ボーンのトランスフォーム値を設定・取得できるので、IKによる地形追従を実装したり、パーティクルシステムなどの他のアクターやコンポーネントをスケルトンのボーンに追従させることができます。
注意:
SkeletonAnimation.UpdateWorld
デリゲートをサブスクライブすることで、ワールドトランスフォームの更新のライフサイクルの一部として新しいボーンの位置を取得して適用するようにしてください。そうしないと、ロード時に修正が1フレーム遅れたり、設定したときにアニメーションによって上書きされたりする可能性があります。
Vector3 worldPosition = bone.GetWorldPosition(skeletonAnimation.transform);
// 注意:SkeletonGraphicを使用する場合、すべての値は親のCanvas.referencePixelsPerUnitでスケーリングする必要があります。
Vector3 position = ...;
bone.SetPositionSkeletonSpace(position);
Quaternion worldRotationQuaternion = bone.GetQuaternion();
アニメーション - AnimationState
ライフサイクル
SkeletonAnimationコンポーネントは Update
メソッドを実装しています。このメソッドでは、デルタタイムに基づいて基礎となるAnimationStateを更新し、そのAnimationState
をスケルトンに適用し、スケルトンのすべてのボーンのワールドトランスフォームを更新します。
SkeletonAnimationコンポーネントは、SkeletonAnimation.AnimationState
プロパティを介してAnimationStateAPIを公開しています。このセクションでは、トラック、TrackEntry、ミックスタイム、アニメーションのキューイングなどの概念について、全般的なSpineランタイムガイドのアニメーションの適用の項で説明されている内容を前提としています。
タイムスケール
SkeletonAnimationコンポーネントのタイムスケールを設定することで、アニメーションの再生を遅くしたり、速くしたりすることができます。例えば、タイムスケールが0.5の場合、アニメーションは通常の半分の速度になり、タイムスケールが2の場合、アニメーションは通常の2倍の速度になるというように、アニメーションの進行に使用されるデルタタイムは、単純にタイムスケールを乗じたものになります。
skeletonAnimation.timeScale = 0.5f;
アニメーションの設定
アニメーションを設定するには、トラックのインデックス、アニメーション名、アニメーションをループさせるかどうかを指定します。
[SpineAnimation] public string animationProperty = "walk";
...
TrackEntry entry = skeletonAnimation.AnimationState.SetAnimation(trackIndex, animationProperty, true);
別の方法として、文字列ではなくAnimationReferenceAssetをパラメーターとして使用することもできます。
public AnimationReferenceAsset animationReferenceAsset; // 生成された AnimationReferenceAsset をこのプロパティに割り当てます。
...
TrackEntry entry = skeletonAnimation.AnimationState.SetAnimation(trackIndex, animationReferenceAsset, true);
アニメーションのキューイング
アニメーションをキューに入れるには、トラックのインデックス、アニメーション名、アニメーションをループさせるかどうか、このアニメーションがトラックで再生を開始するまでの遅延時間を秒単位で指定します。
[SpineAnimation] public string animationProperty = "run";
...
TrackEntry entry = skeletonAnimation.AnimationState.AddAnimation(trackIndex, animationProperty, true, 2);
空のアニメーションとクリア処理
SkeletonAnimationコンポーネントには、空のアニメーションを設定したり、空のアニメーションをキューに入れたり、1つまたはすべてのトラックをクリアするメソッドも用意されています。これらはすべて、上述のメソッドやノードと同様に動作します。
entry = skeletonAnimation.AnimationState.AddEmptyAnimation(trackIndex, mixDuration, delay);
skeletonAnimation.AnimationState.ClearTrack(trackIndex);
skeletonAnimation.AnimationState.ClearTracks();
TrackEntry
すべてのメソッドからTrackEntryを受け取り、特定のアニメーションの再生をさらにカスタマイズしたり、TrackEntryのイベントのデリゲートにバインドしたりすることができます。詳しくは後述の「AnimationStateイベントの処理」をご覧ください。
注意: 返されたTrackEntryは、対応するアニメーションが根底となるAnimationStateから削除されるまでのみ有効です。Unityのガベージコレクターが自動的にこれらを解放します。TrackEntryのdisposeイベントを受け取った後は、もう保存もアクセスもしないようにしてください。
entry.EventThreshold = 2;
float trackEnd = entry.TrackEnd;
AnimationStateイベントの処理
アニメーションがAnimationState
によって再生されている間、様々なイベントが発行され、リスナーに以下を通知します。
- アニメーションが開始された(start)。
- トラックをクリアしたり、新しいアニメーションを設定するなどして、アニメーションが中断された(interrupt)。
- 途切れることなくアニメーションが完了した(complete)。※ループしている場合は複数回発生
- アニメーションが終了した(end)。
- アニメーションとそれに対応する
TrackEntry
が破棄された(dispose)。 - ユーザーが定義したイベント(event)が発生した。
補足: 前のアニメーションを中断して新しいアニメーションを設定した場合、
complete
イベントは発生せず、代わりにinterrupt
とend
イベントが発生します。
SkeletonAnimationコンポーネントは、すべてのトラックでキューイングされたすべてのアニメーションのイベントに反応するために、C#コードがバインドできるデリゲートを提供します。また、リスナーは特定のTrackEntry
の対応するデリゲートにのみバインドすることもできます。例えばAnimationState.Complete
に登録すればあらゆるアニメーションのComplete
イベントで処理が実行され、TrackEntry.Complete
に登録すれば特定のアニメーションによって発行されたComplete
イベントのみを処理することができます。
C#
AnimationState
イベントに反応するクラスで、取得したいイベントのデリゲートを追加します:
Spine.AnimationState animationState;
void Awake () {
skeletonAnimation = GetComponent<SkeletonAnimation>();
animationState = skeletonAnimation.AnimationState;
// あらゆるアニメーションから発生されるイベントに対して登録する
animationState.Start += OnSpineAnimationStart;
animationState.Interrupt += OnSpineAnimationInterrupt;
animationState.End += OnSpineAnimationEnd;
animationState.Dispose += OnSpineAnimationDispose;
animationState.Complete += OnSpineAnimationComplete;
animationState.Event += OnUserDefinedEvent;
// 特定のアニメーショントラックエントリーから発生されるイベントに対して登録する
Spine.TrackEntry trackEntry = animationState.SetAnimation(trackIndex, "walk", true);
trackEntry.Start += OnSpineAnimationStart;
trackEntry.Interrupt += OnSpineAnimationInterrupt;
trackEntry.End += OnSpineAnimationEnd;
trackEntry.Dispose += OnSpineAnimationDispose;
trackEntry.Complete += OnSpineAnimationComplete;
trackEntry.Event += OnUserDefinedEvent;
}
public void OnSpineAnimationStart(TrackEntry trackEntry) {
// startイベントに反応させたい実装コードをここに追加してください
}
public void OnSpineAnimationInterrupt(TrackEntry trackEntry) {
// interruptイベントに反応させたい実装コードをここに追加してください
}
public void OnSpineAnimationEnd(TrackEntry trackEntry) {
// endイベントに反応させたい実装コードをここに追加してください
}
public void OnSpineAnimationDispose(TrackEntry trackEntry) {
// disposeイベントに反応させたい実装コードをここに追加してください
}
public void OnSpineAnimationComplete(TrackEntry trackEntry) {
// completeイベントに反応させたい実装コードをここに追加してください
}
string targetEventName = "targetEvent";
string targetEventNameInFolder = "eventFolderName/targetEvent";
public void OnUserDefinedEvent(Spine.TrackEntry trackEntry, Spine.Event e) {
if (e.Data.Name == targetEventName) {
// ユーザー定義イベントに反応させたい実装コードをここに追加してください
}
}
// イベントデータをキャッシュすることで、文字列の比較を省略することができます
Spine.EventData targetEventData;
void Start () {
targetEventData = skeletonAnimation.Skeleton.Data.FindEvent(targetEventName);
}
public void OnUserDefinedEvent(Spine.TrackEntry trackEntry, Spine.Event e) {
if (e.Data == targetEventData) {
// ユーザー定義イベントに反応させたい実装コードをここに追加してください
}
}
詳細はSpine API Referenceをご覧ください。
コールバック内でのAnimationStateやゲームのステートの変更について
AnimationState
のイベントコールバックから AnimationState.SetAnimation()
を呼び出すなどして AnimationState
を変更することができますが、ここには考慮すべき以下のようなタイミングの問題があります。これは、イベントコールバックからゲームステートを変更する場合にも当てはまります。
AnimationState
イベントコールバックはSkeletonAnimation.Update()
でアニメーションが適用されるときに発行され、SkeletonAnimation.LateUpdate()
でメッシュが更新されるよりも前に発行されます。AnimationState.End
コールバックからAnimationState.SetAnimation()
を呼び出すと、同じフレームでAnimationState.Start
イベントがトリガーされます。- 1つのアニメーションから別のアニメーションへのミックストランジションのために、
Start
イベントは1つ目のアニメーションのEnd
イベントよりも 前に 発行されます。これは、ゲームステートを変更するときに考慮すべきよくある落とし穴です。
このようなイベントコールバック内からの呼び出しを、次の Update()
サイクルまで遅らせたい場合は、次のように StartCoroutine
を使用できます:
StartCoroutine(NextFrame(() => {
YourCode();
}));
};
...
IEnumerator NextFrame (System.Action call) {
yield return 0;
if (call != null)
call();
}
コルーチンのyield命令
spine-unityランタイムは、Unityのコルーチン(Coroutines)で使用するための一連のyield命令を提供しています。Unityのコルーチンを初めて使用される方は、コルーチンのチュートリアルとコルーチンのドキュメントから始めることをお勧めします。
以下のようなyield命令があります:
-
WaitForSpineAnimation
Spine.TrackEntry
が指定されたイベントの1つを発生させるまで待機します。C#var track = skeletonAnimation.state.SetAnimation(0, "interruptible", false);
var completeOrEnd = WaitForSpineAnimation.AnimationEventTypes.Complete |
WaitForSpineAnimation.AnimationEventTypes.End;
yield return new WaitForSpineAnimation(track, completeOrEnd); -
WaitForSpineAnimationComplete
Spine.TrackEntry
がComplete
イベントを発生させるまで待機します。C#var track = skeletonAnimation.state.SetAnimation(0, "talk", false);
yield return new WaitForSpineAnimationComplete(track); -
WaitForSpineAnimationEnd
Spine.TrackEntry
がEnd
イベントを発生させるまで待機します。C#var track = skeletonAnimation.state.SetAnimation(0, "talk", false);
yield return new WaitForSpineAnimationEnd(track); -
WaitForSpineEvent
Spine.AnimationState
が、ユーザーが定義したSpine.Event
(Spineエディター内で命名)を発生させるまで待機します。C#yield return new WaitForSpineEvent(skeletonAnimation.state, "spawn bullet");
// Spine.EventのSpine.EventDataリファレンスを渡すこともできます。
Spine.EventData spawnBulletEvent; // Start() などでキャッシュされます。
..
yield return new WaitForSpineEvent(skeletonAnimation.state, spawnBulletEvent);
補足: Unityに組み込まれているyield命令と同様に、spine-unityのyield命令のインスタンスも再利用することができ、追加のメモリ割り当てを防ぐことができます。
チュートリアルページ
こちらでspine-unityのイベントのチュートリアルページを確認できます。
stringのプロパティ属性のスクリプティング
Inspectorでアニメーションの名前などを手入力するのは少し手間がかかります。そこでspine-unityは文字列(string)パラメーターのポップアップフィールドを提供します。string
プロパティの前に以下のプロパティ属性(Attribute)のいずれかを指定すると、スケルトンで利用可能なすべてのアニメーションなどが入力されたポップアップ選択フィールドが自動的に表示されます。提供されているSpineコンポーネントにこのようなポップアップフィールドがある場合、カスタムコンポーネントでもプロパティ属性を使って同じポップアップを使用することができます。以下は利用可能なプロパティ属性の一覧です。
[SpineSlot] public string slot;
[SpineAttachment] public string attachment;
[SpineSkin] public string skin;
[SpineAnimation] public string animation;
[SpineEvent] public string event;
[SpineIkConstraint] public string ikConstraint;
[SpineTransformConstraint] public string transformConstraint;
[SpinePathConstraint] public string pathConstraint;
spine-unityパッケージに含まれるサンプルシーンで、stringプロパティ属性が使用されているのを確認してみてください。
SkeletonMecanimコンポーネント
SkeletonMecanim
コンポーネントは、UnityでSpineスケルトンを使用する3つの方法のうちの1つです。3つの方法とは、SkeletonAnimation、SkeletonMecanim、SkeletonGraphic (UI)のことです。
SkeletonMecanim
コンポーネントはSkeletonAnimationコンポーネントの代わりに使用できるもので、Spineのアニメーションシステムの代わりにUnityのMecanimアニメーションシステムを使用します。SkeletonAnimationコンポーネントと同様に、SpineスケルトンをGameObjectに追加し、アニメーションさせたり、アニメーションイベントに反応させたりすることができます。ただし、SkeletonAnimationと比較して以下のようないくつかの制限と追加要件があります:
注意: SkeletonAnimationコンポーネントと異なり
SkeletonMecanim
は先行するアニメーションのタイムラインの状態をスムーズにミックスアウトするために、アニメーションの最初のフレームで追加のタイムラインキーを必要とします。詳しくは後述の必要になる追加のキーをご覧ください。
注意:
TrackEntry.MixAttachmentThreshold
および同様のミックスしきい値の機能はSkeletonMecanim
では使用できません。
SkeletonMecanim
コンポーネントにはSkeletonAnimationコンポーネントと類似したパラメーターが用意されているので、詳しくはSkeletonAnimationセクションを参照してください。
必要になる追加のキー
あるアニメーションから次のアニメーションへとタイムラインの状態(ボーンの回転など)をスムーズにミックスアウトさせるために、2つ目のアニメーションでは、最初のフレームでセットアップポーズの状態の追加のキーが必要になります。そうしないと、前のアニメーションのタイムラインの状態が残ってしまうからです。これはSkeletonAnimationと比較した際のSkeletonMecanim
の欠点の一つです。
簡単な例:
idle
アニメーションが、先に再生されているjump
アニメーションをスムーズにミックスアウトする必要があるとします。jump
の終了時にボーンbone1
とbone2
がセットアップポーズとは異なる位置でキー設定されている場合、jump
の状態を適切にミックスアウトするためには、idle
アニメーションの最初のフレームにbone1
とbone2
のキー(セットアップポーズまたは任意のポーズ)を追加する必要があります。
Auto Reset
パラメーターを使えばタイムラインの状態をリセットできますが、アニメーションのトランジション終了時に唐突にミックスアウトしてしまい、スムーズなトランジションを実現できません。
また、スケルトンを .json
または .skel.bytes
でエクスポートする際は必ず Animation cleanup(アニメーションクリーンアップ)
を無効にしてください。そうしないとセットアップポーズと全く同じキーはエクスポートされなくなってしまいます!
アニメーションブレンドのコントロール
SkeletonMecanim
のInspectorは以下の追加パラメーターを公開しています :
-
Mecanim Translator
-
Auto Reset :
true
に設定すると、アニメーションが終了したときに、アニメーションのキーが設定されたアイテムに応じて、スケルトンの状態がセットアップポーズにミックスアウトされます。これは、アニメーションがアタッチメントの表示状態を変更した場合に特に重要になることがあります。ミックスアウトされると、アタッチメントの表示状態はセットアップポーズの状態に戻りますが、そうでなければ、現在のアタッチメントの状態は別のアニメーションがそれぞれのアタッチメントのタイムラインにキーを設定するまで保持されます。 -
Custom MixMode : 無効にすると、レイヤーのブレンドモードに応じて、推奨される
MixMode
が使用されます。有効にすると、以下のようなMix Modes
セクションが表示され、各MecanimレイヤーのMixMode
を指定することができます。 -
Mix Modes : 上記の
Custom MixMode
パラメーターが有効な場合に表示されます。このパラメーターは、連続したアニメーション間、およびレイヤー間のアニメーションのミックスモードを決定します。- Mix Next (
Base Layer
とOverride
レイヤーで推奨されます)
前のトラックを適用した後、Mecanimのトランジションウェイトを使って次のトラックを上からミックスします。 - Always Mix (
Additive
レイヤーで推奨されます)
前のトラックをフェードアウトし(Auto Reset
が有効な場合、セットアップポーズになる可能性があります)、Mecanimのトランジションウェイトを使用して次のトラックをトップにミックスします。Base Layerに使用すると、意図しないアニメーションのディッピング効果が発生する場合がありますのでご注意ください。 - Hard (旧名称:
Spine Style
) 次のトラックをすぐに適用します。
- Mix Next (
-
Auto Reset
とレイヤーのMix Mode
パラメーターの結果
トランジションがアクティブになる際、現在のステートの最後のフレーム
と セットアップポーズ
、前のクリップのポーズ
と 新しいクリップのポーズ
の4つのポーズがあり、これらは次のように組み合わされます :
- まず
現在のステートの最後のフレーム
(またはSkeletonMecanimのupdate前のこのフレームの他の修正)で開始します。 セットアップポーズ
を適用します :Auto Reset
が有効な場合、セットアップポーズ
が現在のステートの最後のフレーム
に置き換わります。Auto Reset
が無効な場合、セットアップポーズ
はミックスに含まれません。
前のクリップのポーズ
を適用します :- モードが
Always Mix
に設定されている場合は、前のクリップのポーズ
が現在の状態とミックスされます (Auto Reset
が有効な場合はセットアップポーズ
とミックスされます)。 Hard
またはMix Next
に設定されている場合は、前のクリップのポーズ
がフルウェイトで適用され、現在のステートよりも優先されます(つまりセットアップポーズ
よりも優先されます)。
- モードが
新しいクリップのポーズ
を適用します :- モードが
Always Mix
またはMix Next
に設定されている場合、新しいクリップのポーズ
は現在のステートとミックスされます。つまり、Auto Reset
を有効にしている場合のAlways Mix
は、セットアップポーズ
、前のクリップのポーズ
、新しいクリップのポーズ
が混合されます。 - モードが
Hard
に設定されている場合、新しいクリップのポーズ
はフルウェイトで適用され、以前に適用されたすべてのポーズよりも優先されます。
- モードが
下の表は、前のクリップ P
と新しいクリップ N
の両方が同じタイムラインの値(例えば同じボーンの回転)を変更する場合を表しています。S
は、Auto Reset
が有効な場合はセットアップポーズを、無効な場合は現在のステート(例:前フレームのステート)を表します。トランジションウェイト(トランジション開始時に0、トランジション終了時に1)は、変数 w
で表されます。各レイヤーのブレンドモードにおけるデフォルト(推奨)のミックスモードは、太字でハイライトされています。
Always Mix | Mix Next | Hard | |
---|---|---|---|
Base Layer | lerp(lerp(S, P, 1-w), N, w) | lerp(P, N, w) | N |
Override | lerp( lerp(lower_layers_result, P, (1-w) * layer_weight), N, w * layer_weight) | lerp( lerp(lower_layers_result, P, layer_weight), N, w * layer_weight) | lerp(lower_layers_result, N, layer_weight) |
Additive | lower_layers_result + layer_weight * lerp(P, N, w)) | counts as Always Mix | lower_layers_result + layer_weight * N |
省略形 | 意味 |
---|---|
S | Setup pose(セットアップポーズ) |
P | Previous clip pose(前のクリップのポーズ) |
N | New clip pose(新しいクリップのポーズ) |
w | Transition weight(トランジションウェイト) |
lerp(a, b, weight) | Linear interpolation from a to b by weight (aからbへのウェイトによるリニア補間) |
ControllerとAnimator
SkeletonMecanim
コンポーネントは、UnityのMecanimと同様に Animator
コンポーネントで割り当てられたControllerアセットを使用します。Controllerアセットはスケルトンをドラッグ&ドロップでSkeletonMecanim
としてインスタンス化する際に自動的に生成され、割り当てられます。
補足:
Apply Root Motion
を有効にすると、SkeletonMecanimRootMotionコンポーネントがSkeletonMecanim
GameObjectに自動的に追加されます。
Controllerのアニメーションステートマシンにアニメーションを追加するには、SpineアニメーションをAnimatorパネルにドラッグ&ドロップします。アニメーションはControllerアセットの下にあります。
SkeletonDataAssetで設定されたMix duration値は、SkeletonMecanim
では無視されます。代わりにAnimatorパネルで設定したMecanimのトランジションタイムが使用されます。
SkeletonMecanimイベント
SkeletonMecanim
を使用する場合、イベントは各 AnimationClip
に格納され、他のUnityのアニメーションイベントと同様に発生します。例えば、Spine内でイベント名を "Footstep"
と命名した場合、SkeletonMecanim
のGameObjectに MonoBehaviour
スクリプトを用意し、Footstep()
というメソッドを用意して処理する必要があります。Spine内でフォルダを使用している場合、メソッド名はフォルダ名とアニメーション名を連結したものになります。例えば、先ほどのイベントが Foldername
というフォルダに入っている場合、FoldernameFootstep()
となります。
// フォルダの外に置かれてる場合にイベント"Footstep"をキャプチャするには
void Footstep() {
Debug.Log("Footstep event received");
}
// "Foldername"というフォルダの中に置かれている場合にイベント"Footstep"をキャプチャするには
void FoldernameFootstep () {
Debug.Log("Footstep (in folder Foldername) received");
}
}
Unity Mecanimのイベントの詳細については、アニメーションイベントに関するUnityのドキュメントを参照してください。
SkeletonGraphicコンポーネント
SkeletonGraphic
コンポーネントはUnityでSpineスケルトンを使用する3つの方法のうちの1つです。3つの方法とは、SkeletonAnimation、SkeletonMecanim、SkeletonGraphic (UI)のことです。
SkeletonGraphic
コンポーネントはSkeletonAnimationコンポーネントの代わりに使用できるもので、レイアウト、レンダリング、マスクのインタラクションにUnityのUIシステムを使用します。SkeletonAnimationコンポーネントと同様に、SpineのスケルトンをGameObjectに追加し、アニメーションさせたり、アニメーションイベントに反応させたりすることができます。
なぜ特定のUIコンポーネントなのか
UnityのUI(UnityEngine.UI)は、Canvas
と CanvasRenderers
システムを使って、レンダリング可能なオブジェクトを分類・管理しています。Text
、Image
、RawImage
などの組み込みのレンダリング可能なUIコンポーネントは CanvasRenderer
に依存して正しく機能します。MeshRenderers
(例:デフォルトのCubeオブジェクト)や SpriteRenderers
(例:Sprite)のようなオブジェクトをUIの下に置くと、Canvas
ではレンダリングされません。SkeletonAnimation
は MeshRenderer
を使用しているため、同様の挙動になります。そのため、spine-unityランタイムでは UnityEngine.UI.MaskableGraphic
のサブクラスで CanvasRenderer
コンポーネントをレンダリングに使用する SkeletonAnimation
のvariantである SkeletonGraphic
を提供しています。
マテリアルの重要な要件
SkeletonGraphicコンポーネントでは、デフォルトで割り当てられている Spine/SkeletonGraphic*
シェーダーなど、CanvasRenderer互換の特殊なシェーダーを持つマテリアルのみを使用してください。URP、LWRP、Spine/Skeleton
のような通常のシェーダーを SkeletonGraphic
コンポーネントで使用しないでください。視覚的なエラーが出ないからといって、そのシェーダーが SkeletonGraphic
で動作するとは限りません。実際、Unityエディター上では問題なくレンダリングできるのにモバイルデバイスでは正しくレンダリングできないという事例が確認されています。他のUIコンポーネントと同様に、SkeletonGraphic
は MeshRenderer
ではなく CanvasRenderer
を使用しており、別のレンダリングパイプラインを使用しています。
SpineAtlasAsset
で割り当てられた通常のマテリアルは、SkeletonDataAsset
を SkeletonGraphic
としてインスタンス化する際には無視され、テクスチャのみが使用されます。SkeletonGraphicCustomMaterials コンポーネントを使用すれば、SkeletonGraphic
コンポーネントのマテリアルをオーバーライドすることができます。
重要な注意事項: Unityの
CanvasRenderer
の制限により、SkeletonGraphicはデフォルトでテクスチャの枚数が1枚だけに制限されています。SkeletonGraphic
コンポーネントのInspectorでAdvanced - Multiple CanvasRenderers
を有効にすると、サブメッシュごとに 子CanvasRenderer
GameObject
を生成して、テクスチャの枚数上限を上げることができます。ただし、パフォーマンス上の理由から、これは可能な限り避けた方が良いでしょう。つまり、UIで使用されるスケルトンは、複数ページのアトラスではなく、単一テクスチャー(単一ページ)のアトラスとしてパックされなければなりません。 アタッチメントを単一のアトラスページテクスチャにパックする方法については高度な情報 - 単一テクスチャアトラスのエクスポートとSkeletonGraphicをご覧ください。
正しい構成とマテリアル
"Spine/SkeletonGraphic Tint Black"
のような特殊なシェーダーを使用したり、CanvasGroup以下で SkeletonGraphic
を使用したりするには、それに応じて頂点データを生成する必要があります。関連するパラメーターは、Inspectorの Advanced - Vertex Data
セクションにあります。設定するのは、Tint Black
、CanvasGroup Compatible
、PMA Vertex Color
の3つです。各プロパティの横には Detect
(検出)ボタンが用意されており、これを使って自動的に正しい設定を導き出せます。また、Detect Settings
ボタンを使えば3つのプロパティすべての設定を検出できます。
Advanced - Vertex Data
の設定を変更したら、アクティブな設定に合わせて使用するマテリアルを更新する必要があります。 SkeletonGraphic
では、マテリアルはテクスチャから独立しているので、同じマテリアルプロパティを使用する異なるスケルトンで共有することができます。このため、主なパラメーターとシェーダーの組み合わせに対して、特別な共有SkeletonGraphicマテリアルが用意されています。選択した Advanced - Vertex Data
設定に対して適切なマテリアルは、Material
プロパティの隣にある Detect
ボタンを使って自動的に割り当てることができます。
スケルトンが複数のブレンドモードを使用していて Advanced - Multiple CanvasRenderers
が有効になっている場合は、Blend Mode Materials
の隣にある Detect
ボタンを使用することで、同様の方法で適切なブレンドモードマテリアルを自動的に割り当てることができます。
正しくない結果が表示された場合は、アトラステクスチャのインポート設定が正しくない可能性があります(ドキュメントのこちらを参照してください)。
CanvasGroupアルファ
Spine/SkeletonGraphic*
シェーダーを CanvasGroup
で使用すると、以下の画像のように CanvasGroup
の Alpha
値 を減らすとスケルトンが明るくなってしまいます。
これは、水面下でUnityが頂点カラーのアルファ値を変更していることにより、残念ながらspine-unityランタイムの事前乗算アルファ(PMA)シェーダーではうまく再生できないためです。
重要な注意: spine-unity 4.2以降のランタイムには、
Advanced - Vertex Data
セクションのパラメーターに正しい設定を自動的に割り当てるためのDetect
ボタンと、アクティブな設定に基づいて適切なマテリアルを自動的に割り当てるためのDetect Material
ボタンが用意されています。そのため、詳細な情報が必要でない限り、以下のセクションは読み飛ばしてかまいません。
ティントブラック無しのSkeletonGraphicの場合
Spine/SkeletonGraphic TintBlack*
以外の Spine/SkeletonGraphic
シェーダーでマテリアルを使用する場合は、以下が適用されます。このようなマテリアルをアルファフェードアウトを伴う CanvasGroup
以下で使用する場合、そのマテリアルは CanvasGroup Compatible
パラメーターを有効にし、SkeletonGraphic コンポーネント PMA Vertex Colors
を無効にする必要があります:
- a) spine-unityランタイムのバージョン4.2以降では、各マテリアルの
CanvasGroup Compatible
バリアントをそれぞれMaterials/SkeletonGraphic-PMATexture/CanvasGroupCompatible
フォルダとMaterials/SkeletonGraphic-StaightAlphaTexture/CanvasGroupCompatible
フォルダで見つけられます。
b) 古いバージョンでは、元のマテリアルを変更する代わりに、共有マテリアルSkeletonGraphicDefault
のコピーを作成し、名前をSkeletonGraphic CanvasGroup
などに変更するのが最善です。 - そしてこの
CanvasGroup Compatible
マテリアルを、CanvasGroup
以下のSkeletonGraphic
コンポーネントに割り当ててください。 - この
CanvasGroup
互換マテリアルを使用するSkeletonGraphic
コンポーネントでは、半透明部分が二重に暗くなってしまうのを避けるために、Advanced - PMA Vertex Colors
も無効にしておく必要があります。しかしこれを設定すると、残念ながら加算スロットを通常スロットと一緒にシングルバッチレンダリングすることができなくなるため、ドローコールが増えてしまう可能性があります。
SkeletonGraphic TintBlackの場合
同様に、Spine/SkeletonGraphic TintBlack
シェーダーを使用しているマテリアルをアルファフェードアウトを伴う CanvasGroup
以下で使用する場合にも似たような設定が必要ですが、加算スロットの制限はありません。
- a) 上記と同様に、spine-unityランタイムのバージョン4.2以降では、
CanvasGroupCompatible
フォルダ内にある用意されるSkeletonGraphic TintBlack
マテリアルを使用してください。
b) 古いバージョンでは、元のマテリアルを変更する代わりに、共有マテリアルSkeletonGraphicTintBlack
のコピーを作成し、名前をSkeletonGraphicTintBlack CanvasGroup
などに変更してください。この共有SkeletonGraphicマテリアルを作成する必要があるのは1度だけであり、使用するテクスチャに依存しないため、異なるスケルトンでも使用できることに注意してください。 - そしてこのマテリアルを
CanvasGroup
以下のSkeletonGraphic
コンポーネントに割り当てます。 - コンポーネントで
Advanced - PMA Vertex Colors
を無効にする必要はありませんので、このパラメーターは有効のままにしておいてください。 (バージョン4.1以前ではAdvanced - Canvas Group Tint Black
)。 - a) spine-unity 4.2 以降を使用している場合、
Advanced - PMA Vertex Colors
のSkeletonGraphic
設定は、有効 / 無効の両方に対応しています。単一のドローコールで加算スロットをレンダリングできる利点があるため、Advanced - PMA Vertex Colors
は有効にしておくことをお勧めします。 b) 古いバージョンでは、半透明の加算スロットが二重に暗くなるのを避けるために、Advanced - PMA Vertex Colors
を無効にしてください。
境界と正しい表示
SkeletonGraphic
の表示状態はRectTransformの境界によって決定されます。スケルトンが Canvas
GameObjectの子としてドラッグ&ドロップでインスタンス化された場合はRectTransformの境界は自動的に初期ポーズにマッチします。また、Match RectTransform with Mesh
ボタンをクリックすることで、RectTransformを現在のポーズの寸法に手動で合わせることもできます。RectTransformの境界がメッシュよりも小さくならないようにすることが重要です。そうしないと、例えば RectMask2D
はメッシュの一部がまだ内側にあってレンダリングされるべきであるにもかかわらずRectTransformが外に出た時点でスケルトンの描画を省略してしまいます。現在のRectTransformの境界は、5つのトランスフォームモードのRectTransformツールがアクティブになっているときにSceneビューに表示されます。
パラメーター
SkeletonGraphic
には、SkeletonAnimationコンポーネントと同様のパラメーターが用意されているので、そちらについての詳細はSkeletonAnimationセクションを参照してください。
SkeletonGraphic
のInspectorは、以下の追加パラメーターを公開しています :
-
Material - Detect ボタン :
Advanced - Vertex Data
の設定に従って、適切な"Spine/SkeletonGraphic*"
マテリアルを割り当てます。後述のAdvanced
セクションの Detect Material パラメータと同様です。 -
Freeze :
true
に設定すると、SkeletonGraphic
はアップデートされなくなります。 -
Layout Scale Mode :
SkeletonGraphic
は、RectTransform
の境界に基づいた自動均一スケーリングに対応しています。デフォルトはNone
で、以前の動作を維持します。自動スケーリングは、このパラメーターをWidth Controls Height
、Height Controls Width
、Fit In Parent
またはEnvelope Parent
(それぞれの詳細はこちらを参照)のいずれかに設定することで有効にすることができます。参照レイアウト境界を変更するには、Edit Layout Bounds
トグルボタンを押して編集モードに入り、スケルトンの境界を調整することができます。スケルトンは、参照レイアウト境界をオブジェクトのRectTransform
に合わせて、適宜スケーリングされます。 -
Edit Layout Bounds : 上記の
Layout Scale Mode
で使用される参照レイアウト境界を変更するには、このトグルボタンを押して編集モードにします。その後、手動で境界を調整するか、Match RectTransform with Mesh
を押して、現在のポーズに合わせることができます。調整が完了したら、Edit Layout Bounds
トグルボタンをもう一度押して、編集モードを終了します。 -
Match RectTransform with Mesh :
Match
ボタンをクリックするとSkeletonGraphic
のRectTransformを現在のポーズの寸法に合わせることができます。RectTransformの境界がメッシュよりも小さくならないようにすることが重要です。そうしないと、例えばRectMask2D
は、メッシュの一部がまだマスクの内側にあってレンダリングされるべきであったとしても、RectTransformが外に出た時点でスケルトンの描画を省略してしまいます。Layout Scale Mode
がNone
に設定されているか、Edit Layout Bounds
トグルボタンがedit-modeに設定されていない限り、このオプションはグレーアウトされます。
-
Advanced
-
Use Clipping :
false
に設定すると、いかなるSpineのクリッピング・アタッチメントも無視されるようになります。 -
Tint Black (!) : メッシュにブラックティント頂点データを追加します。スケルトンにティントブラックカラーが設定されたスロットがある場合は有効にしてください。
ブラックティントは、提供されているSpine/SkeletonGraphic Tint Black*
シェーダーのように、シェーダーが UV2 と UV3 をブラックティントカラーとして解釈する必要があります。 親Canvasで UV2 と UV3 データを許可するには、そのCanvasを選択し、Additional Shader Channels
でTexCoord1
とTexCoord2
を有効にする必要があります。SkeletonDataにティントブラックが設定されているスロットがあればこのパラメーターを有効にし、そうでなければ無効にする
Detect
ボタンが用意されています。 -
CanvasGroup Compatible : SkeletonGraphic が
CanvasGroup
GameObject の下で使用されている場合は有効にしてください。マテリアルもCanvasGroup Compatible
を有効にする必要があるので、Detect Material
を使うか、または手動でこの設定を変更した後に適切なマテリアルを割り当ててください。
SkeletonGraphic Tint Black*
シェーダーを使用していて、Tint Black
とPMA Vertex Color
の両方が有効になっている場合、アルファ値はプライマリ頂点カラーcolor.a
ではなくuv2.g
に保存され、color.a
はcolor.a
を変更するCanvasGroup
を捕捉するために定数1.0
を保存します。階層内でSkeletonGraphicコンポーネントが
CanvasGroup
コンポーネントの下にあるならこのパラメータを有効にし、そうでない場合は無効にするDetect
ボタンが用意されています。 -
[4.1以前のバージョンのみ] Canvas Group Tint Black : これは
SkeletonGraphic Tint Black
シェーダーを使用する場合のみ有効にしてください。Tint Black
が無効の場合、またはPMA Vertex Color
が無効な場合は効果がありません。CanvasGroup
の下にあるSkeletonGraphic
のスロットでAdditive
ブレンドモードを使用する場合に有効にしてください。有効にすると、アルファ値はプライマリ頂点カラーcolor.a
の代わりにuv2.g
に格納され、color.a
は、color.a
を変更するCanvasGroup
を捕捉するために定数1.0
を保存します。 -
PMA Vertex Colors (CanvasGroupアルファ用の追加ルール) : 頂点カラーRGBと頂点カラーアルファを乗算します。このパラメーターはデフォルトで有効になっており、サードパーティ製のシェーダーを使用する場合や
CanvasGroup Compatible
を有効にする必要がある場合を除き、そのままにしておくのが正しい設定です。具体的には以下のルールが適用されます:Detect
ボタンが用意されていますが、これはTint Black
とCanvasGroup Compatible
が正しく設定されている必要があります。Detect
は、サードパーティー製(つまりSpineに付属しているもの以外)のシェーダーが使用されている場合、またはCanvasGroup Compatible
が有効でTint Black
が無効の場合、このパラメーターを無効にします。それ以外の場合はこのパラメーターを有効にします。具体的には以下のルールが PMA Vertex Color に適用されます (これが必要なのは
Detect
がうまくいかなかった時のみです):spine-unity 4.2以降を使用している場合:
このパラメーターを有効にする必要がある場合 (デフォルト):- 使用する
"Spine/SkeletonGraphic*"
シェーダーでCanvasGroup Compatible
が無効になっている場合(Straight Alpha Texture
が有効になっている場合でも)。または "Spine/SkeletonGraphicTintBlack*"
シェーダーを使用している場合(Straight Alpha Texture
が有効になっている場合でも)。または- PMAとして頂点カラーを必要とするサードパーティー製(つまりSpineに付属しているもの以外)のシェーダーを使用している場合。(そのシェーダーが、PMA加算出力ブレンドモード
Blend One OneMinusSrcAlpha
を使用している場合など。)
このパラメーターを無効にする必要がある場合:
"Spine/SkeletonGraphicTintBlack*"
は使用していなくて、通常の"Spine/SkeletonGraphic*"
シェーダーでCanvasGroup Compatible
が有効になっている場合。または- 通常の頂点カラーを必要とするサードパーティー製(つまりSpineに付属しているもの以外)のシェーダーを使用している場合。(そのシェーダーが、通常出力ブレンドモード
Blend SrcAlpha OneMinusSrcAlpha
で使用している場合など。)
spine-unity 4.1以前を使用している場合:
このパラメーターを有効にする必要がある場合 (デフォルト):- 使用する
"Spine/SkeletonGraphic*"
シェーダーでCanvasGroup Compatible
が無効になっている場合(Straight Alpha Texture
が有効になっている場合でも)。または - PMAとして頂点カラーを必要とするサードパーティー製(つまりSpineに付属しているもの以外)のシェーダーを使用している場合。(そのシェーダーが、PMA加算出力ブレンドモード
Blend One OneMinusSrcAlpha
を使用している場合など。)
このパラメーターを無効にする必要がある場合:
"Spine/SkeletonGraphic*"
シェーダーを使用していてCanvasGroup Compatible
が有効になっている場合。または- 通常の頂点カラーを必要とするサードパーティー製(つまりSpineに付属しているもの以外)のシェーダーを使用している場合。(そのシェーダーが、通常出力ブレンドモード
Blend SrcAlpha OneMinusSrcAlpha
で使用している場合など。)
有効にすると、加算スロットは通常スロットと一緒に1回のドローコールでレンダリングできます。無効にすると、加算スロットのために
SkeletonData
の Blend Mode Materials - Apply Additive Material を有効にする必要があり、それによって別のドローコールが必要になってしまうため、パフォーマンスに悪影響を与える可能性があります。 - 使用する
-
Detect Settings:
Tint Black
、CanvasGroup Compatible
、PMA Vertex Colors
の適切なパラメーターの検出を一度に適用します。 -
Detect Material: 上記の
Tint Black
とCanvasGroup Compatible
パラメーターとアトラステクスチャのインポート設定(PMA設定なのかストレートアルファ設定なのか)に基づいて、適切なSkeletonGraphic
マテリアルを割り当てます。正しくない結果が表示された場合は、テクスチャの設定が正しくない可能性があります(詳しくはドキュメントの こちらを参照してください)。 -
Multiple CanvasRenderers :
true
に設定すると、SkeletonGraphic
は1つのCanvasRenderer
を使用せず、必要なドローコール(サブメッシュ)ごとに、必要な数の 子CanvasRenderer
GameObjectを自動的に作成します。これにより、単一テクスチャの制限を緩和することができますが、パフォーマンスのオーバーヘッド(処理負荷)が発生します。-
Blend Mode Materials : スロットのブレンドモードごとに異なる
SkeletonGraphic
マテリアルを使用できるようにします。ただしここでは、"Spine/SkeletonGraphic *"
または他のCanvasRenderer互換のマテリアルのみを使用してください。 -
Assign Default
を選択すると、デフォルトのブレンドモードマテリアルSkeletonGraphicAdditive
、SkeletonGraphicMultiply
、SkeletonGraphicScreen
が割り当てられます。注意:
SkeletonGraphic
のBlend Mode Materials
の割り当てはSkeletonDataAsset
のマテリアルに依存しているため、SkeletonDataAsset
でブレンドモードマテリアルが適切に設定されていることを確認してください。PMA Vertex Colors
が有効な場合、Additive Material
は無視されます。
-
-
-
Animation Update : 通常の
Update
(デフォルト)、物理ステップFixedUpdate
、またはユーザーコールによる手動アニメーション更新のいずれかを指定します。Rigidbody
またはRigidbody2D
が割り当てられたSkeletonRootMotion コンポーネントを使用する場合、更新モードをIn FixedUpdate
に設定することをお勧めします。それ以外の場合は、In Update
を推奨します。-
Update When Invisible : MeshRendererが非表示になった時に使用されるUpdateモードです。メッシュが再び表示されるようになると、Updateモードは自動的に
UpdateMode.FullUpdate
にリセットされます。 -
Separator Slot Names : Enable Separationが
true
に設定されているときに、レンダリングを分割する場所を決定するスロットです。レンダリングの分割に関する全般的な情報はSkeletonRenderSeparatorセクションを参照してください。ただしSkeletonGraphic
においては追加のコンポーネントは必要ありません。 -
Enable Separation : レンダリングの分割は、このInspectorセクションで直接有効にすることができ、追加のコンポーネント(
SkeletonRenderSeparator
やSkeletonRenderer
コンポーネントのSkeletonPartsRenderer
など)は必要ありません。有効にすると、追加の分割されたGameObjectが自動的に作成され、それに応じてCanvasRenderer
GameObjectが再ペアリングされます。分割されたGameObjectは、必要に応じて階層内で移動させたり再配置したりしてCanvas
内での望ましい描画順序を実現することができます。 -
Update Part Location : 有効にすると、分割されたGameObjectの位置が
SkeletonGraphic
の位置に合わせて更新されます。これは、パーツを別のGameObjectに再ペアリングしたい場合に役立ちます。 -
Physics Inheritance : トランスフォームの動きをスケルトンの物理コンストレイントに適用する方法を制御します。
- Position : ゼロ以外に設定すると、X方向およびY方向のトランスフォームの位置移動がスケルトンの物理コンストレイントに適用され、ここで設定したXおよびYのスケール係数で乗算されます。一般的な組み合わせは以下の通りです:
(1,1) にした場合、XY移動が通常通り適用されます。
(2,2) にした場合、XY移動が倍の強さで適用されます。
(1,0) にした場合、水平方向の移動だけが適用されます。
(0,0) にした場合、トランスフォームの移動の動きは全く適用されなくなります。 - Rotation : ゼロ以外に設定すると、トランスフォームの回転の動きがスケルトンの物理コンストレイントに適用され、ここで設定したスケール係数で乗算されます。一般的な値は以下の通りです:
1 にした場合、通常通り適用されます。
2 にした場合、倍の強さで適用されます。
0 にした場合、トランスフォームの回転の動きは全く適用されなくなります。
- Position : ゼロ以外に設定すると、X方向およびY方向のトランスフォームの位置移動がスケルトンの物理コンストレイントに適用され、ここで設定したXおよびYのスケール係数で乗算されます。一般的な組み合わせは以下の通りです:
-
サンプルシーン
基本的な使用方法については、Spine Examples/Getting Started/6 Skeleton Graphicにあるサンプルシーンで確認することができます。 また、Separator Slotを設定したり、描画順序を変更する方法を紹介している高度なサンプルシーンは、Spine Examples/Other Examples/SkeletonRenderSeparator
で確認できます。
SkeletonRendererコンポーネント
SkeletonRenderer
コンポーネントは、スケルトンの現在のステートを描画する役割を担っています。これはSkeletonAnimationとSkeletonMecanimの基底クラスとなっています。
補足: ほとんどの場合、代わりにSkeletonAnimation、SkeletonMecanim、SkeletonGraphic (UI)のいずれかを使用することになるでしょう。これらのコンポーネントは、アニメーションを制御する高度な手段を提供します。UIのゲージ要素のように、トランジションなしで手動でアニメーションを適用したい場合に限り、このコンポーネントはそのままで役立ちます。
レンダリングは、MeshRenderer
コンポーネントで更新されるプロシージャルメッシュによって行われます。このコンポーネントはSkeletonDataAssetによって参照されるテクスチャアトラスアセットを使用して、スケルトンのアタッチメントを描画するのに必要なテクスチャとマテリアルを見つけます。詳細はSkeletonAnimationセクションを参照してください。
SkeletonRenderer
コンポーネントを直接使用する方法については、サンプルシーンの Spine Examples/Other Examples/SpineGauge
で確認できます。