着せ替えAPI (β)¶
このページでは、アプリ内で着せ替えを実装する際に利用する着せ替えAPIについて説明しています。
Info
本機能はβ版のため、将来仕様が変更する可能性があります。着せ替えAPIは、一部のパートナー様に限定して提供しています。
概要¶
着せ替えAPIは、パスが /v1/Avatar/{avatarId}/FittingRoom 以下に配置されるAPIを指し、このAPIを使ってアプリ内に着せ替え画面の機能とUIを実装できます。ここでは、着せ替えアプリでのUIを例に、アバターをクライアントサイドで3Dレンダリングする場合での実装方法を説明します。
Info
着せ替えAPIは、着せ替え画面をアプリのUI/UXに合わせて実装したいパートナー様向けです。既存の着せ替え画面を流用して実装コストを抑えたい場合、着せ替えアプリや UI Kit を利用できます。
着せ替えアプリのUI¶
着せ替えアプリの画面は次のような構成です。
試着のユースケース¶
ユーザーは着せ替え画面から試着を行った後、自身のアバターとして保存・反映させます。試着のユースケースは次のとおりです。
- ユーザーは、「パーツを切り替えるタブ」から変更したいパーツを選択します
- アプリは、選択されたパーツの1ページ目のアイテムリストを表示します
- ユーザーは、アイテムリストをスクロールします
- アプリは、選択されたパーツの2ページ目のアイテムリストを追加します
- ユーザーは、試着したいアイテムのサムネイルを選択します
- アプリは、選択されたアイテムを試着中のアバターへ反映します
UI要素(ボタンのデザイン、テキスト、配置、ページングの仕方など)はアプリ側で自由に設計し、同様のユースケースを実装します。
必要なパーミッション¶
着せ替えAPIの利用には、Fitting
パーミッションを取得する必要があります。パーミッションはアバターID発行時に指定します。パーミッションの詳細は着せ替えアプリとの接続を参照してください。
着せ替え画面を実装する¶
必要な情報を取得する¶
着せ替え画面には、試着中のアバターと所持アイテムリストを表示する必要があります。必要な情報は GET /v1/Avatar/{avatarId}/FittingRoom へアクセスして入手します。
ボディを含む3Dデータを取得するために、パラメータ includeBodyItem
と setAssetUrl
に true
を指定します。part
に指定できる値は、アバターに着用できるパーツ(Hat
Hair
Face
Clothes
Accessory
)に限定されます。パーツの種類については、本ページ下部を参照してください。
Info
パラメータ part
を指定することで、指定したパーツの1ページ目のアイテム情報を取得できます。 part
は複数指定できます。各パーツの1ページ目のアイテム情報を事前に取得しておくことで、パーツ切替時のAPI再アクセスを回避できます。
試着中アバターの表示¶
アバターに着用できるアイテム(wearable
が true
となるアイテム)の assetUrl
から3Dデータを入手し、それらを結合させてアバターを構成します。APIはアバターに着用できないアイテム(wearable
が false
となるアイテム)、具体的には置物やフレームの情報も返しますが、無視してください。
デフォーム処理に関する情報がある場合、アバターに適用する必要があります。デフォームについては本ページ下部を参照してください。
以後、ユーザーが試着操作をする度に、試着中のアバターを更新します。
アイテムリストの表示¶
アイテムはAPIから取得した順序で表示してください。
サムネイル画像は60x60ピクセルのPNG形式で提供され、thumbnailUrl
で指定するURLからダウンロードして利用できます。このサムネイル画像はリスティング用に最適化されており、小さなアイテム(イヤリングなど)であっても視認できるようデザインされています。
Info
より高い解像度が必要な場合、代わりに imageUrl
を利用できますが、リスティング用に最適化していないため、視認性に問題が出るアイテムが存在します。
取り外せないアイテムなど、何かしらの理由で選択できないアイテムがあります。選択可否は selectable
で判別できるため、この値が false
となるアイテムは、グレーアウトするなど選択できないことが分かるUIとするか、最初から非表示にします。アイテムの selectable
の値は、試着操作によって変化することがあります。
Info
リスティング用のアイテム情報内では assetUrl
に値が設定されない点に注意してください。assetUrl
は後述の試着API経由で入手します。
アイテムリストのページング¶
GET /v1/Avatar/{avatarId}/FittingRoom で取得できるアイテムは1ページ目のみで、2ページ目以降は GET /v1/Avatar/{avatarId}/Items を使って取得します。次のページが存在するかどうかは、hasNext
で判別できます。
Info
GET /v1/Avatar/{avatarId}/Items を使って1ページ目の情報を取得することもできます。
アイテムの試着¶
ユーザーがアイテムを選択したら、PATCH /v1/Avatar/{avatarId}/FittingRoom を呼び出して試着(または取り外し)処理を実行します。
試着処理の結果、試着したパーツ以外のパーツが変更(または削除)される可能性がある点に注意してください。例えば、男性ボティの状態で女性ボディ用の服を選択した場合、ボティが女性ボディに切り替わります。
selectable
が true
となるアイテムの試着処理は必ず成功します。試着の結果情報を受け取り、その指示に従って試着中のアバターとアイテムリストを更新します。
試着中アバターの更新¶
APIが返す情報に従って試着中アバターを再構成します。アバター全体を再ロードするか、パーツ個別にロード/アンロードする場合は removedItemIds
が指定するアイテムIDの3Dデータをアンロードし、addedItemIds
が指定する3Dデータを新たにロードします。3Dデータは assetUrl
で指定されたURLから入手します。
デフォーム処理に関する情報がある場合は適用します。デフォームについては本ページ下部を参照してください。
アイテムリストの更新¶
試着の結果、アイテムの selectable
の値が変わる可能性があります。changedToSelectableItemIds
には選択可能に変更されたアイテムIDが、changedToUnselectableItemIds
には選択不可に変更されたアイテムIDが設定されるため、それに従ってアイテムリストを更新します。
着せ替えの完了¶
ユーザーが「保存」ボタンなどで着せ替えを完了した場合、POST /v1/Avatar/{avatarId}/FittingRoom を呼び出して本アバターに反映させます。試着中のアバターやアイテムリストは変化しません。
詳細な仕様¶
パーツの種類¶
パーツの種類は以下で、APIではコードで取り扱われます。「アバターへの着用」が「◯」となるものが、VRM出力に対応しているパーツです。
パーツ名 | コード | アバターへの着用 |
---|---|---|
帽子 | Hat | ◯ |
髪 | Hair | ◯ |
顔 | Face | ◯ |
服 | Clothes | ◯ |
アクセサリー | Accessory | ◯ |
持ち物 | Hand | |
エフェクト | Effect | |
置物 | Object | |
フレーム | Frame | |
モーション | Motion | |
体 | Body | ◯ |
1つのパーツにアイテムが複数付くこともあります。例えば、メガネアイテムとマントアイテムはどちらもアクセサリーに属しますが、同時に付けられます。
デフォーム¶
帽子や着包みの服を着用した場合、髪と顔が貫通しないようデフォーム処理をかける必要があります。どのように変形すべきかは、API経由で指定されます。
例えば下の画像は、左が帽子を被っていないアバター、中央が帽子を被ったアバター、右が帽子を被ったアバターの帽子を非表示にしたアバターです。
APIからは、どの地点からどの方向にどれくらいの強さの力を加えるべきかが指定されます。前述の帽子の場合、以下のようなデータが返されます。各プロパティの詳細はAPIリファレンスを参照してください。
"deform": {
"center": [ 0, 1340, 0 ],
"axis": [ 0, 1, 0 ],
"factor": 400,
"targetItemIds": [
5527262535352320,
4833974807429120
]
}
targetItemIds
では、どのアイテムに力を加えるべきかが指示されます。主に髪と顔が対象になります。
クライアントサイドでのデフォーム処理の実装例です。
// C# での実装例
var inoutVertices = model.Vertices.coords.ToArray();
var inoutNormals = model.Vertices.normals.ToArray();
var axis = math.normalize(deform.axis);
var center = deform.center;
var factor = math.max(deform.factor, 1.0e-4f);
for (int i = 0; i < inoutVertices.Length; i++)
{
double3 sp = inoutVertices[i] - center;
double h = math.dot(axis, sp);
if (h > 0.0f)
{
double k1 = 1.0f / (factor + h);
double k = factor * k1;
inoutVertices[i] = math.double3(k * sp + center);
double3 rn = (math.dot(inoutNormals[i], sp) / math.dot(sp, sp)) * sp;
inoutNormals[i] = (inoutNormals[i] - rn) * k + rn;
}
}
model.Vertices.coords = inoutVertices;
model.Vertices.normals = inoutNormals;