VRM仕様
Mon, Apr 16, 2018glTF-2.0のバイナリ形式glbをベースにした、VR向けモデルフォーマットです。
更新履歴
- 20181109: JsonShcemaの
Vector3
のタイプが誤ってarray
になっていた部分を修正
{
"x": {
"type": "number"
},
"y": {
"type": "number"
},
"z": {
"type": "number"
}
}
拡張子
.vrm
を使います。
gltfのバイナリ形式.glb
と互換性があるので、拡張子を.glb
に変更するとGLTF対応のアプリケーションで読み込むことができます(VRM独自の追加情報は無くなります)。
Json拡張
GLBのJSON部にVRM Extension
として拡張しています。
{
"extensionsUsed": {
"VRM"
},
"extensions": {
"VRM": {
// VRMの拡張情報
}
},
// 通常のGLTF-2.0の情報
}
仕様のJsonSchemaを作成しました
GLTF-2.0のJsonSchema
VRM拡張: VRMバージョンなど
/extensions/VRM/exporterVersion
はv0.36から
{
"title": "vrm",
"description": "VRM extension is for 3d humanoid avatars (and models) in VR applications.",
"type": "object",
"properties": {
"exporterVersion": {
"description": "Version of exporter that vrm created. UniVRM-0.42",
"type": "string"
},
"meta": {
"$ref": "vrm.meta.schema.json"
},
"humanoid": {
"$ref": "vrm.humanoid.schema.json"
},
"firstPerson": {
"$ref": "vrm.firstperson.schema.json"
},
"blendShapeMaster": {
"$ref": "vrm.blendshape.schema.json"
},
"secondaryAnimation": {
"$ref": "vrm.secondaryanimation.schema.json"
},
"materialProperties": {
"type": "array",
"items": {
"$ref": "vrm.material.schema.json"
}
}
}
}
保存できる要素
人間型モデル一体分の情報を保存します。
GLTF-2.0: Texture
- GLTF-2.0の
/textures/
VRM拡張はありません。
GLTF-2.0: Material(json.extensions.VRM.materialProperties)
- GLTF-2.0の
/materials/
GLTFのマテリアルにフォールバックした情報を保存しています(拡張子をGLBに変更した場合に使われる)。
VRM拡張: /extensions/VRM/materialProperties
VRM独自のマテリアル情報を保存しています。 現状、Unityに必要な項目を保存しています。 選択可能なShaderは、VRMが提供するシェーダーを参照してください。
{
"title": "vrm.material",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"shader": {
"type": "string"
},
"renderQueue": {
"type": "integer"
},
"floatProperties": {
"type": "object"
},
"vectorProperties": {
"type": "object"
},
"textureProperties": {
"type": "object"
},
"keywordMap": {
"type": "object"
},
"tagMap": {
"type": "object"
}
}
}
GLTF-2.0: Mesh
- GLTF-2.0の
/meshes/
VRM拡張はありません。
頂点属性
-
GLTF-2.0の
/meshes/*/primitives/*/attributes
- TANGENT (vec4) // v0.42から保存するのをやめて、import時にnormalとuvから計算するようにしています。
モーフターゲット情報
/meshes/*/primitives/*/extras/targetNames
にMoprhTargetの名称を記録しています。
GLTF-2.0: スキニング情報
- GLTF-2.0の
/skins/
VRM拡張はありません。
GLTF-2.0: Node
- GLTF-2.0の
/nodes/
VRM拡張はありません。
- node
- name
- position(vec3)
- rotation(quaternion)
- scale(vec3)
保存する値に対する規約
GLTF2の規約
GLTF2の規約に準拠します。 特に重要な項目です。
- メートル単位
- 右手Y-UP座標系1
VRMの規約
人間型モデルに特化して互換性を高めるために、以下の制約を課します。
- モデルは原点に位置する
- モデルは-Z向き1
- モデルのヒエラルキーはY-UP2
- モデルのメッシュはY-UP2
- モデルのヒエラルキーはT-Pose
- モデルのメッシュはT-Pose
- ボーンに回転を入れない
- ボーンにスケールを入れない
- ヘッドボーンは真正面を向いている3
VRMが提供するシェーダー
セル調のキャラクタモデルの運用を想定して以下のシェーダーを用意しています。
Unlit系
ライティング・シェーディングせずにテクスチャ色をそのまま表示します。 半透明の扱い別に4種類を用意しています。
- UnlitTexture(不透明)
- UnlitCutout(透明度が閾値以下の部分を透明とする)
- UnlitTransparent(アルファブレンド。ZWriteしない)4
- UnlitTransparentZWrite(アルファブレンド。ZWriteする)5
MToon
セルシェーディング、輪郭線に対応したシェーダー。 Unlitよりもきめ細かく設定できます。
VRM拡張: モデルのボーンマッピング(json.extensions.VRM.humanoid)
NodeとHumanoidで定義される標準ボーンの対応表です。
{
"title": "vrm.humanoid.bone",
"type": "object",
"properties": {
"bone": {
"description": "Human bone name.",
"type": "string",
"enum": ["hips","leftUpperLeg","rightUpperLeg","leftLowerLeg","rightLowerLeg","leftFoot","rightFoot","spine","chest","neck","head","leftShoulder","rightShoulder","leftUpperArm","rightUpperArm","leftLowerArm","rightLowerArm","leftHand","rightHand","leftToes","rightToes","leftEye","rightEye","jaw","leftThumbProximal","leftThumbIntermediate","leftThumbDistal","leftIndexProximal","leftIndexIntermediate","leftIndexDistal","leftMiddleProximal","leftMiddleIntermediate","leftMiddleDistal","leftRingProximal","leftRingIntermediate","leftRingDistal","leftLittleProximal","leftLittleIntermediate","leftLittleDistal","rightThumbProximal","rightThumbIntermediate","rightThumbDistal","rightIndexProximal","rightIndexIntermediate","rightIndexDistal","rightMiddleProximal","rightMiddleIntermediate","rightMiddleDistal","rightRingProximal","rightRingIntermediate","rightRingDistal","rightLittleProximal","rightLittleIntermediate","rightLittleDistal","upperChest"]
},
"node": {
"description": "Reference node index",
"type": "integer"
},
"useDefaultValues": {
"description": "Unity's HumanLimit.useDefaultValues",
"type": "boolean"
},
"min": {
"description": "Unity's HumanLimit.min",
"type": "array"
},
"max": {
"description": "Unity's HumanLimit.max",
"type": "array"
},
"center": {
"description": "Unity's HumanLimit.center",
"type": "array"
},
"axisLength": {
"description": "Unity's HumanLimit.axisLength",
"type": "number"
}
}
}
定義しているボーン
-
hips
-
spine
-
chest
-
upperChest6
-
neck
-
head
-
Left/Right eye6
-
Left/Right upperArm
-
Left/Right lowerArm
-
Left/Right hand
-
Left/Right upperLeg
-
Left/Right lowerLeg
-
Left/Right foot
-
Left/Right toe6
-
Left/Right thumb proximal, intermediate, distal6
-
Left/Right index proximal, intermediate, distal6
-
Left/Right middle proximal, intermediate, distal6
-
Left/Right ring proximal, intermediate, distal6
-
Left/Right little proximal, intermediate, distal6
VRM拡張: モデル情報(json.extensions.VRM.meta)
{
"title": "vrm.meta",
"type": "object",
"properties": {
"title": {
"description": "Title of VRM model",
"type": "string"
},
"version": {
"description": "Version of VRM model",
"type": "string"
},
"author": {
"description": "Author of VRM model",
"type": "string"
},
"contactInformation": {
"description": "Contact Information of VRM model author",
"type": "string"
},
"reference": {
"description": "Reference of VRM model",
"type": "string"
},
"texture": {
"description": "Thumbnail of VRM model",
"type": "integer"
},
"allowedUserName": {
"description": "A person who can perform with this avatar",
"type": "string",
"enum": ["OnlyAuthor","ExplicitlyLicensedPerson","Everyone"]
},
"violentUssageName": {
"description": "Permission to perform violent acts with this avatar",
"type": "string",
"enum": ["Disallow","Allow"]
},
"sexualUssageName": {
"description": "Permission to perform sexual acts with this avatar",
"type": "string",
"enum": ["Disallow","Allow"]
},
"commercialUssageName": {
"description": "For commercial use",
"type": "string",
"enum": ["Disallow","Allow"]
},
"otherPermissionUrl": {
"description": "If there are any conditions not mentioned above, put the URL link of the license document here.",
"type": "string"
},
"licenseName": {
"description": "License type",
"type": "string",
"enum": ["Redistribution_Prohibited","CC0","CC_BY","CC_BY_NC","CC_BY_SA","CC_BY_NC_SA","CC_BY_ND","CC_BY_NC_ND","Other"]
},
"otherLicenseUrl": {
"description": "If “Other” is selected, put the URL link of the license document here.",
"type": "string"
}
}
}
情報
タイトル(Title)
アバターモデルの名前を設定します
作者(Author)
モデルの作者の名前を記述します
連絡先(Contact Information)
モデルの作者への連絡先を記述します
参照(Reference)
何か「親作品」に相当するものがある場合は参照URLなどを記述します
サムネイル(Thumbnail)
アバターモデルのサムネイルを登録します。2048x2048程度の解像度テクスチャを推奨します。meta情報内ではtexture番号を指定します。
バージョン
モデルの作成バージョンです。
使用許諾・ライセンス情報
License
アバターの人格に関する許諾範囲
Personation / Charaterization Permission
アバターに人格を与えることの許諾範囲(json.extensions.VRM.meta.allowedUserName)
A person who can perform with this avatar
- アバターを操作することはアバター作者にのみ許される(Only Author)
- 明確に許可された人限定(Explictly Licensed Person)
- 全員に許可(Everyone)
このアバターを用いて暴力表現を演じることの許可(json.extensions.VRM.meta.violentUssageName)
Violent acts using this avatar
- 不許可(Disallow)
- 許可(Allow)
このアバターを用いて性的表現を演じることの許可(json.extensions.VRM.meta.sexualUssageName)
Sexuality acts using this avatar
- 不許可(Disallow)
- 許可(Allow)
商用利用の許可(json.extensions.VRM.meta.commercialUssageName)
For commercial use
- 不許可(Disallow)
- 許可(Allow)
その他のライセンス条件(json.extensions.VRM.meta.otherPermissionUrl)
Other License Url
上記許諾条件以外のライセンス条件がある場合はそのライセンス文書へのURLを記述
再配布・改変に関する許諾範囲
Redistribution / Modifications License
ライセンスタイプ(json.extensions.VRM.meta.licenseName)
License Type
- 再配布禁止(Redistribution Prohibited)
- 著作権放棄(CC0)
- Creative Commons CC BYライセンス(CC_BY)
- Creative Commons CC BY NCライセンス(CC_BY_NC)
- Creative Commons CC BY SAライセンス(CC_BY_SA)
- Creative Commons CC BY NC SAライセンス(CC_BY_NC_SA)
- Creative Commons CC BY NDライセンス(CC_BY_ND)
- Creative Commons CC BY NC NDライセンス(CC_BY_NC_ND)
- その他(Other)
その他ライセンス条件(json.extensions.VRM.meta.otherLicenseUrl)
Other License Url
上記許諾条件以外のライセンス条件がある場合はそのライセンス文書へのURLを記述
VRM拡張: モーフ設定(json.extensions.VRM.blendShapeMaster)
BlendShapeをグループ化するBlendShapeGroupの配列を設定します。
{
"title": "vrm.blendshape",
"type": "object",
"properties": {
"blendShapeGroups": {
"type": "array",
"items": {
"$ref": "vrm.blendshape.group.schema.json"
}
}
}
}
ブレンドシェイプグループ(json.extensions.VRM.blendShapeMaster.blendShapeGroups)
{
"title": "vrm.blendshape.group",
"type": "object",
"properties": {
"name": {
"description": "Expression name",
"type": "string"
},
"presetName": {
"description": "Predefined Expression name",
"type": "string",
"enum": ["Neutral","A","I","U","E","O","Blink","Joy","Angry","Sorrow","Fun","LookUp","LookDown","LookLeft","LookRight","Blink_L","Blink_R"]
},
"binds": {
"description": "Low level blendshape references.",
"type": "array",
"items": {
"$ref": "vrm.blendshape.bind.schema.json"
}
},
"materialValues": {
"description": "Material animation references.",
"type": "array",
"items": {
"$ref": "vrm.blendshape.materialbind.schema.json"
}
}
}
}
{
"title": "vrm.blendshape.bind",
"type": "object",
"properties": {
"mesh": {
"type": "integer"
},
"index": {
"type": "integer"
},
"weight": {
"type": "number"
}
}
}
{
"title": "vrm.blendshape.materialbind",
"type": "object",
"properties": {
"materialName": {
"type": "string"
},
"propertyName": {
"type": "string"
},
"targetValue": {
"type": "array",
"items": {
"type": "number"
}
}
}
}
名前
名前です。事前定義名と同じ(大文字)を推奨します
事前定義名
待機状態の表情
- Neutral
リップシンク
- A
- I
- U
- E
- O
瞬き
- Blink
- Blink_L
- Blink_R
喜怒哀楽
- Fun
- Angry
- Sorrow
- Joy
視線制御
- LookUp
- LookDown
- LookLeft
- LookRight
その他
- Unknown
ブレンドシェイプの名前の識別名
システムからブレンドシェイプを一意に認識する文字列IDを以下のロジックで決定します。
// 疑似コード
function GetID(preset, name)
{
if (Preset != BlendShapePreset.Unknown)
{
return preset.ToString().ToUpper();
}
else
{
return name.ToUpper();
}
}
- ブレンドシェイプIDがユニークになるようにPresetとNameを設定する
VRM拡張: 一人称設定(json.extensions.VRM.firstPerson)
{
"title": "vrm.firstperson",
"type": "object",
"properties": {
"firstPersonBone": {
"description": "The bone whose rendering should be turned off in first-person view. Usually Head is specified.",
"type": "integer"
},
"firstPersonBoneOffset": {
"description": "The target position of the VR headset in first-person view. It is assumed that an offset from the head bone to the VR headset is added.",
"type": "object",
"properties": {
"x": {
"type": "number"
},
"y": {
"type": "number"
},
"z": {
"type": "number"
}
}
},
"meshAnnotations": {
"description": "Switch display \/ undisplay for each mesh in first-person view or the others.",
"type": "array",
"items": {
"$ref": "vrm.firstperson.meshannotation.schema.json"
}
},
"lookAtTypeName": {
"description": "Eye controller mode.",
"type": "string",
"enum": ["Bone","BlendShape"]
},
"lookAtHorizontalInner": {
"$ref": "vrm.firstperson.degreemap.schema.json"
},
"lookAtHorizontalOuter": {
"$ref": "vrm.firstperson.degreemap.schema.json"
},
"lookAtVerticalDown": {
"$ref": "vrm.firstperson.degreemap.schema.json"
},
"lookAtVerticalUp": {
"$ref": "vrm.firstperson.degreemap.schema.json"
}
}
}
一人称視点のアバターを描画する場合、自モデルの頭部の中が見えてしまうという問題が生じます7。 これに対応するために、一人称時の表示状態を指定できます。
firstPersonBone(json.extensions.VRM.firstPerson.firstPersonBone)
一人称時に描画を切り替えるべきボーンを指定します。通常Head
です。
firstPersonBoneOffset(json.extensions.VRM.firstPerson.firstPersonBoneOffset)
一人時のヘッドセットの目標位置。 頭ボーンからヘッドセットへのオフセットを加味することを想定している。
meshAnnotations(json.extensions.VRM.firstPerson.meshAnnotations)
各メッシュに対して一人称時とそれ以外で表示・非表示を切り替えることができます。 以下の設定があります。
- Auto: firstPersonBoneとその子孫に対するボーンWeightを持つポリゴンを自動で非表示にする8
- FirstPersonOnly: 一人称のみ表示
- ThirdPersonOnly: 三人称のみ表示(頭など一人称時に非表示にするメッシュに指定する)
- Both: 特に表示切替をしない
視線設定
ターゲットの方向を向くようにキャラクタの視線を制御します。
目線タイプ(json.extensions.VRM.firstPerson.lookAtTypeName)
- Bone: ボーンにより目線を操作します。
- BlendShape: BlendShapeにより目線を操作します。BlendShapePreset.LookUp, LookDown, LookLeft, LookRightを使います。
角度調整
頭と目標物の角度差を目ボーンに適用する場合の角度を調整します。
json.extensions.VRM.firstPerson.lookAtHorizontalInner
json.extensions.VRM.firstPerson.lookAtHorizontalOuter
json.extensions.VRM.firstPerson.lookAtVerticalDown
json.extensions.VRM.firstPerson.lookAtVerticalUp
VRM拡張: 揺れモノ設定(json.extensions.VRM.secondaryAnimation)
尻尾や髪の毛などのひも状のオブジェクトの自動アニメーションの設定です。
揺れるボーン(secondaryAnimation.boneGroups)
{
"title": "vrm.secondaryanimation",
"type": "object",
"properties": {
"boneGroups": {
"type": "array",
"items": {
"$ref": "vrm.secondaryanimation.spring.schema.json"
}
},
"colliderGroups": {
"type": "array",
"items": {
"$ref": "vrm.secondaryanimation.collidergroup.schema.json"
}
}
}
}
{
"title": "vrm.secondaryanimation.spring",
"type": "object",
"properties": {
"comment": {
"description": "Annotation comment",
"type": "string"
},
"stiffiness": {
"description": "The resilience of the swaying object (the power of returning to the initial pose).",
"type": "number"
},
"gravityPower": {
"description": "The strength of gravity.",
"type": "number"
},
"gravityDir": {
"description": "The direction of gravity. Set (0, -1, 0) for simulating the gravity. Set (1, 0, 0) for simulating the wind.",
"type": "object",
"properties": {
"x": {
"type": "number"
},
"y": {
"type": "number"
},
"z": {
"type": "number"
}
}
},
"dragForce": {
"description": "The resistance (deceleration) of automatic animation.",
"type": "number"
},
"center": {
"description": "The reference point of a swaying object can be set at any location except the origin. When implementing UI moving with warp, the parent node to move with warp can be specified if you don't want to make the object swaying with warp movement.",
"type": "integer"
},
"hitRadius": {
"description": "The radius of the sphere used for the collision detection with colliders.",
"type": "number"
},
"bones": {
"description": "Specify the node index of the root bone of the swaying object.",
"type": "array",
"items": {
"type": "integer"
}
},
"colliderGroups": {
"description": "Specify the index of the collider group for collisions with swaying objects.",
"type": "array",
"items": {
"type": "integer"
}
}
}
}
揺れるボーンの根元のボーン(json.extensions.VRM.secondaryAnimation.boneGroups[0].bones)
揺れモノの根元のボーンのノードインデックスを指定します。
揺れるボーンと衝突する当たり判定(json.extensions.VRM.secondaryAnimation.boneGroups[0].colliderGroups)
揺れモノに対する衝突判定グループのインデックスを指定します。
パラメーター
center(json.extensions.VRM.secondaryAnimation.boneGroups[0].center)
world原点以外の、揺れモノの基準点を設定できます。 ワープで移動するUIを実装した場合に、ワープ移動で揺れモノを揺らしたくない場合にワープで移動する親ノードを指定できます。
dragForce(json.extensions.VRM.secondaryAnimation.boneGroups[0].dragForce)
自動アニメーションの抵抗(減速)です。
gravityDir(json.extensions.VRM.secondaryAnimation.boneGroups[0].gravityDir)
重力の方向です。(0, -1, 0)にすると重力に、(1, 0, 0)にすると風のように作用します。
gravityPower(json.extensions.VRM.secondaryAnimation.boneGroups[0].gravityPower)
重力の強さです。
hitRadius(json.extensions.VRM.secondaryAnimation.boneGroups[0].hitRadius)
Colliderとの当たり判定の半径です
stiffness(json.extensions.VRM.secondaryAnimation.boneGroups[0].stiffiness)
揺れモノの復元力(初期姿勢に戻る力)です
揺れモノ当たり判定設定(json.extensions.VRM.secondaryAnimation.colliderGroups)
揺れモノと衝突する球を設定します。
{
"title": "vrm.secondaryanimation.collidergroup",
"type": "object",
"properties": {
"node": {
"description": "The node of the collider group for setting up collision detections.",
"type": "integer"
},
"colliders": {
"type": "array",
"items": {
"type": "object",
"properties": {
"offset": {
"description": "The local coordinate from the node of the collider group.",
"type": "object",
"properties": {
"x": {
"type": "number"
},
"y": {
"type": "number"
},
"z": {
"type": "number"
}
}
},
"radius": {
"description": "The radius of the collider.",
"type": "number"
}
}
}
}
}
}
ノード(json.extensions.VRM.secondaryAnimation.colliderGroups[0].node)
当たり判定を設置するノードです。
ローカル座標(json.extensions.VRM.secondaryAnimation.colliderGroups[0].colliders[1].offset)
当たり判定のノードからのローカル座標です。
半径(json.extensions.VRM.secondaryAnimation.colliderGroups[0].colliders[1].radius)
当たり判定の半径です。