avatar-animations
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAuthoring Avatar Animations (Scene Emotes)
制作Avatar动画(场景表情)
This skill covers making the animation file: posing the official Decentraland avatar rig in Blender, exporting a clip as a , verifying it, and handing it to the scene. The scene-side API that plays it — , , , the enum, the permission — lives in player-avatar; this skill links there rather than repeating it.
*_emote.glbtriggerSceneEmotestopEmoteAvatarEmoteCommandAvatarMaskScope check before you start:
| The user wants | Skill |
|---|---|
| A new animation of the player's avatar that doesn't exist yet | this skill |
To play a built-in emote, or a | player-avatar |
To play an animation clip baked into a | animations-tweens |
| To animate an NPC | npcs |
| To move/rotate an entity procedurally | animations-tweens ( |
本技能涵盖动画文件制作:在Blender中为官方Decentraland Avatar绑定摆姿势,将动画片段导出为 格式,验证后交付给场景。播放该动画的场景端API——、、、 枚举、权限——位于 player-avatar 技能中;本技能会链接到该部分,不再重复说明。
*_emote.glbtriggerSceneEmotestopEmoteAvatarEmoteCommandAvatarMask开始前的范围检查:
| 用户需求 | 对应技能 |
|---|---|
| 尚不存在的玩家Avatar新动画 | 本技能 |
播放内置表情,或已有的 | player-avatar |
播放烘焙到 | animations-tweens |
| 为NPC添加动画 | npcs |
| 以程序化方式移动/旋转实体 | animations-tweens( |
Workflow
工作流
- Get the rig — , never a hand-built armature. Download + bone/control/property reference:
Avatar_File.blend.{baseDir}/references/avatar-rig.md - Set up — set the scene to 30 fps (the shipped file is 24), capture the values, create one new action per clip.
Starting_Pose - Author — pose bones only, in Pose mode, keyframing every bone you touch at every keyframe.
CTRL_ - Verify while authoring — print world positions (clipping, floor, animation area) and render four angles per keyframe into a contact sheet.
- Export — one clip per file, armature only, ,
export_def_bones=True.ACTIVE_ACTIONS - Verify the GLB — parse the JSON chunk: 1 animation, 0 meshes, 63 nodes, 62 channels per path, duration = .
(frames − 1) / 30 - Hand off — rename to , drop under
*_emote.glb, add the permission, play it (see player-avatar).assets/animations/
Ready-made helpers for every step — the helper module, sign detection, render/contact-sheet setup, the export call, and the GLB verifier — are in .
bpy{baseDir}/references/blender-emote-patterns.mdHow to drive Blender (headless CLI vs Blender MCP, binary paths, and the rule that you must never fall back from the MCP to headless silently) is already covered in . Emote authoring uses exactly those two paths; do not re-derive them.
{baseDir}/../add-3d-models/references/blender-authoring.md- 获取绑定 — 使用 ,切勿使用手动构建的骨架。下载地址及骨骼/控件/属性参考:
Avatar_File.blend。{baseDir}/references/avatar-rig.md - 设置场景 — 将场景帧率设为 30 fps(默认文件为24fps),记录 的数值,为每个动画片段创建一个新的动作(action)。
Starting_Pose - 制作动画 — 仅在姿态模式下调整 前缀的骨骼,为所有你调整过的骨骼在每个关键帧都设置关键帧。
CTRL_ - 制作过程中验证 — 打印世界坐标(检查穿模、地面接触、动画区域)并为每个关键帧渲染四个角度,拼成联系表。
- 导出 — 每个文件仅包含一个动画片段,仅导出骨架,设置 、
export_def_bones=True。ACTIVE_ACTIONS - 验证GLB文件 — 解析JSON块:1个动画、0个网格、63个节点、每个路径62个通道,时长 = 。
(帧数 − 1) / 30 - 交付 — 重命名为 ,放入
*_emote.glb目录下,添加权限,播放动画(参见 player-avatar)。assets/animations/
每个步骤都有现成的 辅助工具——辅助模块、符号检测、渲染/联系表设置、导出调用、GLB验证器——都在 中。
bpy{baseDir}/references/blender-emote-patterns.md如何操作Blender(无头CLI vs Blender MCP、二进制路径,以及绝不能从MCP静默回退到无头模式的规则)已在 中说明。表情制作完全遵循这两种方式,请勿重新推导。
{baseDir}/../add-3d-models/references/blender-authoring.mdRULE: One new action per clip — and reset to the idle pose, not identity
规则:每个动画片段对应一个新动作——重置为空闲姿势,而非初始姿态
Create a fresh action for every clip. In Blender 4.4+/5 actions are slotted, and no longer exists (curves live under ):
Action.fcurvesact.layers[0].strips[0].channelbagspython
act = bpy.data.actions.new(name)
slot = act.slots.new('OBJECT', 'Avatar_Animation')
arm.animation_data.action = act
arm.animation_data.action_slot = slotBefore authoring anything, to evaluate and capture every pose bone's transform. That snapshot — not the identity transform — is the baseline you reset to between keyframes. The rest pose of the armature is an A/T-pose; the idle the runtime blends from is . Resetting to identity gives you a clip that snaps to a T-pose on the first frame.
scene.frame_set(0)Starting_PoseStarting_Pose为每个动画片段创建全新的动作。在Blender 4.4+/5版本中,动作是槽位化的, 已不存在(曲线位于 下):
Action.fcurvesact.layers[0].strips[0].channelbagspython
act = bpy.data.actions.new(name)
slot = act.slots.new('OBJECT', 'Avatar_Animation')
arm.animation_data.action = act
arm.animation_data.action_slot = slot在制作任何内容之前,执行 以评估 并记录每个姿态骨骼的变换。这个快照——而非初始变换——是你在关键帧之间重置的基准。骨架的静止姿势是A/T型姿势;运行时混合的空闲姿势是 。重置为初始姿态会导致动画片段在第一帧突然跳转到T型姿势。
scene.frame_set(0)Starting_PoseStarting_PoseRULE: Key everything you pose, at every keyframe
规则:为所有你调整过的姿势在每个关键帧都设置关键帧
scene.frame_set()view_layer.update()frame_setpython
pb.keyframe_insert('["FK > IK Leg L"]', frame=f)On the first and last frame, also key location/rotation/scale on every deform bone. Channels left without boundary keys stay "open" and keep whatever a previously playing emote left there — the official docs call these emote overrides, and they show up as an avatar whose legs are still doing the last emote.
scene.frame_set()view_layer.update()frame_setpython
pb.keyframe_insert('["FK > IK Leg L"]', frame=f)在第一帧和最后一帧,还要为所有变形骨骼设置位置/旋转/缩放关键帧。没有边界关键帧的通道会保持“打开”状态,并保留上一个播放的表情留下的数值——官方文档称之为表情覆盖,表现为Avatar的腿还在做上一个表情的动作。
RULE: Upper arms — world axes for direction, local Y for twist
规则:上臂——方向用世界轴,扭转用局部Y轴
The upper-arm bone's local X is tilted. Rotating about it sweeps the arm across the chest, and a pose that should have both arms forward ends up with the arms crossed — this happens in practice and is not obvious in a front render. So set the arm's direction with world axes, converting the world axis into the bone's current frame first:
python
M = (arm.matrix_world @ pb.matrix).to_3x3().normalized()
local_axis = M.inverted() @ Vector(world_axis)
pb.rotation_quaternion @= Quaternion(local_axis, math.radians(deg))- Pure forward raise → world X.
- Moving a raised arm in/out → yaw about world Z.
World axes alone do not give a perfect arm pose, though. Arms move in many directions, and the rig's animator works with world and local rotations together. Two things need the bone's local axes:
- Twist — palm up/down, elbow pointing out or in, a wrist that has to face a prop — can only be done by rotating the bone about its own length, which is local Y on this rig (verified: local Y of is the bone axis; rotating it leaves the elbow where it is and only rolls the forearm and hand).
CTRL_FK_Avatar_Arm.*.rl('CTRL_FK_Avatar_Arm.L', 'Y', deg) - Fine-tuning once the gross direction is right — a small local correction is often more precise than another world-axis rotation.
Elbows, knees, wrists and fingers hinge on their local X (Y/Z are locked on those controls) — is correct there.
rl()上臂骨骼的局部X轴是倾斜的。绕它旋转会让手臂扫过胸部,原本应该双臂向前的姿势最终会变成双臂交叉——这种情况在实际中经常发生,而且在正面渲染中不明显。因此,要用世界轴设置手臂的方向,先将世界轴转换到骨骼的当前坐标系中:
python
M = (arm.matrix_world @ pb.matrix).to_3x3().normalized()
local_axis = M.inverted() @ Vector(world_axis)
pb.rotation_quaternion @= Quaternion(local_axis, math.radians(deg))- 纯向前抬起 → 世界 X 轴。
- 抬起的手臂向内/向外移动 → 绕世界 Z 轴偏航。
不过,仅用世界轴无法得到完美的手臂姿势。手臂可以向多个方向运动,绑定的动画师会结合世界和局部旋转一起使用。有两种情况需要用到骨骼的局部轴:
- 扭转——手掌向上/向下、肘部向外或向内、手腕必须朝向某个道具——只能通过绕骨骼自身长度旋转来实现,也就是这个绑定上的局部Y轴(已验证:的局部Y轴是骨骼轴向;绕它旋转不会移动肘部,只会转动前臂和手)。使用
CTRL_FK_Avatar_Arm.*。rl('CTRL_FK_Avatar_Arm.L', 'Y', deg) - 在大致方向正确后进行微调——小的局部校正通常比再次绕世界轴旋转更精确。
肘部、膝盖、手腕和手指绕其局部X轴铰接(这些控件的Y/Z轴是锁定的)—— 在这些部位是正确的。
rl()RULE: Legs mirror, the upper body does not — fix the pasted upper body by flipping X and Z
规则:腿部可镜像,上半身不可——通过翻转X和Z修正粘贴的上半身姿势
Blender's Pose ▸ Copy Pose / Paste X-Flipped only works on half of this rig (verified on ; numbers in ):
Avatar_File.blend{baseDir}/references/avatar-rig.md- Legs and feet mirror normally, FK or IK — Paste X-Flipped is exact for IK legs and within ~3 cm for FK legs.
- Shoulders, upper arms, forearms, hands and fingers do not — Paste X-Flipped lands the other hand 40–70 cm away. The rig animator's fix: on every pasted upper-body control, negate the X and Z values and keep Y. Example: a pasted arm reading X −0.5, Z 0.1 becomes X 0.5, Z −0.1. Apply it to the rotation (quaternion or Euler) and, on the IK hand and elbow controls, to the location too. Verified exact (0.000 m) for the whole arm chain, FK and IK, all 30 finger controls included.
- in
mirror_side('L')does both steps for every control at once.{baseDir}/references/blender-emote-patterns.md - When you pose a single joint rather than mirroring, still detect its sign programmatically — rotate +15°, measure which way the downstream bone moved, cache (). The same angle on
auto_signand.Ldoes not produce a symmetric pose..R
Blender的姿态 ▸ 复制姿势 / 粘贴X翻转 仅对这个绑定的一半有效(已在 中验证;数值见 ):
Avatar_File.blend{baseDir}/references/avatar-rig.md- 腿和脚可以正常镜像,无论是FK还是IK——粘贴X翻转对IK腿是完全精确的,对FK腿误差在约3厘米以内。
- 肩膀、上臂、前臂、手和手指不行——粘贴X翻转后,另一只手会偏离40-70厘米。绑定动画师的解决方法是:对每个粘贴的上半身控件,取X和Z值的相反数,保持Y值不变。例如:粘贴的手臂数值为X −0.5、Z 0.1,要改成X 0.5、Z −0.1。对旋转(四元数或欧拉角)应用此规则,对于IK手和肘部控件,位置也要应用。已验证整个手臂链(包括FK和IK,以及全部30个手指控件)完全精确(误差0.000米)。
- 中的
{baseDir}/references/blender-emote-patterns.md可以一次性对所有控件执行这两个步骤。mirror_side('L') - 当你为单个关节摆姿势而非镜像时,仍要通过程序检测其符号——旋转+15°,测量下游骨骼的移动方向,缓存结果()。对
auto_sign和.L使用相同的角度不会产生对称的姿势。.R
RULE: FK or IK — lose contact → FK, keep contact → IK
规则:FK或IK——失去接触用FK,保持接触用IK
Legs default to IK, arms to FK ( properties on ). Switch only when the pose needs it, using one rule: if a hand or foot has to keep contact with the floor, a seat, a wall or a prop, it should be IK; if it loses contact, it should be FK.
FK > IK *CTRL_Avatar_UpperBody- FK legs: jumps, rolls, flying, handstands, swimming, legs dangling off a ledge or a theatre seat.
- IK hands: push-ups, climbing, leaning on a table, both hands fixed on one prop.
- Do not flip modes during walk cycles, dances or anywhere contact is lost only briefly — the defaults handle those, and every switch pops unless the two chains match exactly at that frame.
- Key the property itself when you change it, not just the bones.
FK > IK
Seated poses. Lower the body with — it is the centre of gravity and moves the whole body. moves only pelvis + legs and stretches the torso — wrong tool for sitting. Then decide per leg:
CTRL_Avatar_UpperBodyCTRL_Avatar_Hips| Feet | Legs |
|---|---|
| Both feet on the ground (chair, bench) | Stay IK: move |
| One leg crossed over the other | Only the lifted leg to FK; the grounded one stays IK. |
| Feet off the ground (pond edge, theatre seat, high stool) | Both legs FK. |
python
setprop('CTRL_Avatar_UpperBody', 'FK > IK Leg L', 0.0) # only for a leg that leaves the ground
setprop('CTRL_Avatar_UpperBody', 'FK > IK Leg R', 0.0)腿部默认使用IK,手臂默认使用FK( 上的 属性)。仅在姿势需要时切换,遵循一条规则:如果手或脚必须与地面、座椅、墙壁或道具保持接触,就用IK;如果失去接触,就用FK。
CTRL_Avatar_UpperBodyFK > IK *- FK腿:跳跃、翻滚、飞行、倒立、游泳、腿悬在悬崖或剧院座位外。
- IK手:俯卧撑、攀爬、靠在桌子上、双手固定在一个道具上。
- 不要在行走循环、舞蹈或仅短暂失去接触的场景中切换模式——默认设置可以处理这些情况,而且每次切换都会产生跳变,除非两个骨骼链在该帧完全匹配。
- 切换时要为 属性本身设置关键帧,而不仅仅是骨骼。
FK > IK
坐姿。 用 降低身体——它是重心,会移动整个身体。 只会移动骨盆+腿,还会拉伸躯干——是错误的坐姿工具。然后每条腿单独决定:
CTRL_Avatar_UpperBodyCTRL_Avatar_Hips| 脚部状态 | 腿部模式 |
|---|---|
| 双脚都在地面上(椅子、长凳) | 保持IK:将 |
| 一条腿搭在另一条腿上 | 仅抬起的腿切换为FK;着地的腿保持IK。 |
| 双脚离地(池塘边、剧院座位、高凳) | 双腿都用FK。 |
python
setprop('CTRL_Avatar_UpperBody', 'FK > IK Leg L', 0.0) # 仅用于离开地面的腿
setprop('CTRL_Avatar_UpperBody', 'FK > IK Leg R', 0.0)...then pose CTRL_FK_Avatar_UpLeg / _Leg / _Foot / _ToeBase on that side
...然后在该侧调整 CTRL_FK_Avatar_UpLeg / _Leg / _Foot / _ToeBase
Whatever the mode, check the feet: world Z of `Avatar_LeftToeBase` / `Avatar_RightToeBase` must stay **≥ 0** or the avatar sinks through the floor.
无论哪种模式,都要检查脚部:`Avatar_LeftToeBase` / `Avatar_RightToeBase` 的世界Z坐标必须**≥ 0**,否则Avatar会穿进地面。RULE: Verify with numbers as well as renders
规则:既要用渲染验证,也要用数值验证
Renders catch composition; numbers catch clipping. Print world positions of hands, head, feet and any prop reference at every keyframe:
- Keep hands ≥ ~0.3 m from the head centre when a limb passes the head. A throw over the shoulder clipped straight through the skull until the arm was routed outward first.
- Keep hands ≥ ~0.10 m apart rather than overlapping at the centre line.
- Keep the face visible in any default/holding pose — hold objects at upper-chest height with the head tilted down, not in front of the face.
Render four angles per keyframe (front three-quarter, straight front, side, top) with Workbench and tile them into one contact sheet. Iterate in a cheap pose-only stage first (seconds per run), and only then do the full build with exports.
渲染能检查构图;数值能检查穿模。在每个关键帧打印手、头、脚和任何道具参考点的世界坐标:
- 当肢体经过头部时,手与头部中心的距离保持**≥ ~0.3米**。有一个过肩投掷的动画曾直接穿过头骨,直到先把手臂向外调整才解决。
- 双手之间的距离保持**≥ ~0.10米**,不要在中心线处重叠。
- 在任何默认/持物姿势下,面部要可见——将物体举到上胸高度,头部微微低下,不要挡在脸前面。
为每个关键帧渲染四个角度(前四分之三视角、正前方、侧面、顶部),使用Workbench渲染器,并将它们拼成一张联系表。先在低成本的仅姿态阶段迭代(每次运行只需几秒),然后再进行完整的导出构建。
RULE: Stay inside the animation area
规则:待在动画区域内
Measured on the reference objects in (world metres, Blender Z-up):
Avatar_File.blend| Reference object | Extent | Meaning |
|---|---|---|
| 4 × 4 × 4 m box — X, Y ∈ [−2, 2], Z ∈ [0, 4] | Everything stays inside for the whole clip: every body part, prop and particle. Nothing moves more than 4 m in any direction. |
| 2 m diameter cylinder on the origin | The avatar root / centre of gravity ( |
| plane at Z = 0 | Nothing below it. |
Legs, arms, head and props may leave the root cylinder — a kick or a cartwheel does — as long as they stay inside the box. Add the checks to the per-keyframe report: , , every deform bone head and tail inside the box, every toe Z ≥ 0 ( in ). The Decentraland Tools add-on's Validate Emote only warns when moves more than 1 m horizontally or vertically from its first frame; it does not check the box, so the check is yours to run.
|hips.x| ≤ 1|hips.y| ≤ 1in_area(){baseDir}/references/blender-emote-patterns.mdCTRL_Avatar_UpperBodyin_area()根据 中的参考对象测量(世界米,Blender Z轴向上):
Avatar_File.blend| 参考对象 | 范围 | 含义 |
|---|---|---|
| 4 × 4 × 4 米的立方体——X、Y ∈ [−2, 2],Z ∈ [0, 4] | 所有内容在整个动画片段中都要待在里面:每个身体部位、道具、粒子。任何物体在任何方向上的移动都不能超过4米。 |
| 原点处直径2米的圆柱体 | Avatar根节点/重心( |
| Z=0的平面 | 任何物体不能低于它。 |
腿、手臂、头和道具可以离开根圆柱体——比如踢腿或侧手翻——只要它们待在立方体内。将这些检查添加到每个关键帧的报告中:、、所有变形骨骼的头部和尾部都在立方体内、所有脚趾Z ≥ 0( 中的 )。Decentraland Tools插件的Validate Emote 仅在 水平或垂直移动超过1米时发出警告;它不会检查立方体边界,因此 检查需要你自己运行。
|hips.x| ≤ 1|hips.y| ≤ 1{baseDir}/references/blender-emote-patterns.mdin_area()CTRL_Avatar_UpperBodyin_area()RULE: Loops must close; one-shots must land where the scene resumes
规则:循环动画必须闭合;一次性动画必须落在场景恢复的位置
- Looping clip: make the first and last keyframes identical (e.g. frame 1 and frame 121 for a 4 s loop) or the loop pops.
- One-shot clip: start and end in the resting pose the scene returns to — for a seated game, the seated holding pose; otherwise .
Starting_Pose
- 循环动画片段:让第一帧和最后一帧完全相同(例如,4秒循环的第1帧和第121帧),否则循环会跳变。
- 一次性动画片段:开始和结束都要在场景返回的静止姿势——对于坐姿游戏,就是坐姿持物姿势;否则是 。
Starting_Pose
RULE: Export one clip per file, armature only
规则:每个文件导出一个动画片段,仅导出骨架
Delete every other object first — meshes, widgets, reference planes, , cameras, lights — and remove the action, or the exporter emits two clips. is what guarantees exactly one animation per file. Full export call in .
WGT_*Armature_PropStarting_Poseexport_animation_mode='ACTIVE_ACTIONS'{baseDir}/references/blender-emote-patterns.mdSave an editable (meshes included) before stripping, so the user can tweak the actions by hand afterwards.
.blend先删除所有其他对象——网格、 控件、参考平面、、相机、灯光——并移除 动作,否则导出器会输出两个片段。 可以保证每个文件恰好有一个动画。完整导出调用见 。
WGT_*Armature_PropStarting_Poseexport_animation_mode='ACTIVE_ACTIONS'{baseDir}/references/blender-emote-patterns.md在删除对象之前先保存可编辑的 文件(包含网格),这样用户之后可以手动调整动作。
.blendRULE: Verify the exported GLB before handing it over
规则:交付前验证导出的GLB文件
Parse the GLB's JSON chunk and assert: 1 animation, 0 meshes, 63 nodes ( + 62 deform bones), 1 skin, 62 channels each for translation/rotation/scale, and . Verifier script in . A duration mismatch means the scene FPS wasn't 30.
Armatureduration == (last_frame − first_frame) / 30{baseDir}/references/blender-emote-patterns.mdTypical size for a 1–4 s clip at is 70–110 KB — far under the 3 MB cap, so there is normally no reason to raise the sampling step.
export_frame_step=1解析GLB的JSON块并断言:1个动画、0个网格、63个节点( + 62个变形骨骼)、1个蒙皮、各62个位置/旋转/缩放通道,且 。验证脚本见 。时长不匹配意味着场景帧率不是30。
Armatureduration == (last_frame − first_frame) / 30{baseDir}/references/blender-emote-patterns.md1-4秒的片段在 时的典型大小是 70-110 KB——远低于3 MB的上限,因此通常没有理由提高采样步长。
export_frame_step=1Upper-body (masked) animations
上半身(遮罩)动画
A masked emote is not a different file format — the same is played with at trigger time (API and enum details: player-avatar → "Emote masks"). What changes is what you should author.
.glbmask: AvatarMask.AM_UPPER_BODYWhich bones the mask keeps — verified against the Explorer's asset:
UpperBodyAvatarMask.mask- Animated: ,
Avatar_Spine,_Spine1, both shoulders/arms/forearms/hands, all 40 finger bones,_Spine2,Avatar_Neck.Avatar_Head - Ignored: and both legs (
Avatar_Hips/UpLeg/Leg/Foot) — these keep whatever the locomotion state or another emote is doing that frame.ToeBase
Mechanically the renderer samples your clip each , then restores the non-masked bones' local position and rotation from the pose the Animator had already produced (). So:
LateUpdateMaskedLegacyEmoteBlender- Hip/root motion in a masked clip has no effect. is outside the mask, so the drop you authored with
Avatar_Hipsto sit the avatar down is discarded; the legs show the locomotion state (idle, walk, run).CTRL_Avatar_UpperBody - A masked clip does NOT layer over another emote. Verified in the Explorer's : starting a masked emote on the local player stops any full-body emote that is playing, and starting a full-body emote cancels the masked one. So a masked clip cannot run on top of a chair's sitting emote — the avatar stands up. It layers only over locomotion, which is what the mask is for: carrying, holding or cheering while the player walks, runs or idles.
SceneMaskedEmoteSystem - For a seated player, play the clip full body. Author a seated lower body into every clip (hips lowered, FK legs bent), trigger it unmasked, and have the scene replay the sitting emote (or the chair's own) when the clip ends and no looping seated clip takes over. A one-shot that returns to the same seated pose as your looping idle clip chains into it without a pop; the only visible pop is the height difference against the built-in sitting emote, which you tune with the hip drop.
triggerEmote({ predefinedEmote: 'sittingChair1' }) - Author the full body anyway, even for masked use. A plausible lower body makes the same file usable unmasked. The mask is a trigger-time decision, not a property of the file.
- Masked emotes on the local player emit no lifecycle events (documented in player-avatar). The scene must therefore time them itself — store each clip's duration alongside its path in scene config, since you know it exactly from the frame count.
AvatarEmoteCommand
Design notes for a seated holding pose that reads well: hips ≈ 0.6 m, hands at chest height, head tilted toward the hands.
The bone list and blending mechanism above were read from the Explorer source (,MaskedLegacyEmoteBlender,SceneMaskedEmoteSystemonCharacterEmoteSystem, 2026-09); the "masked stops full-body" rule was confirmed in-world on a seated player. For the enum values and call signatures, trust player-avatar, which is verified against the shipped protocol.main
遮罩表情不是不同的文件格式——同一个 文件在触发时使用 播放(API和枚举详情:player-avatar → "表情遮罩")。改变的是你应该制作的内容。
.glbmask: AvatarMask.AM_UPPER_BODY遮罩保留哪些骨骼——已对照Explorer的 资源验证:
UpperBodyAvatarMask.mask- 动画生效: 、
Avatar_Spine、_Spine1、双肩/双臂/前臂/双手、全部40根手指骨骼、_Spine2、Avatar_Neck。Avatar_Head - 被忽略: 和双腿(
Avatar_Hips/UpLeg/Leg/Foot)——这些会保持该帧的运动状态或另一个表情的动作。ToeBase
从机制上讲,渲染器会在每次 时采样你的动画片段,然后从Animator已经生成的姿势中恢复非遮罩骨骼的局部位置和旋转()。因此:
LateUpdateMaskedLegacyEmoteBlender- 遮罩片段中的髋部/根节点运动无效。 在遮罩之外,因此你用
Avatar_Hips制作的坐姿下沉会被丢弃;腿部会显示运动状态(空闲、行走、奔跑)。CTRL_Avatar_UpperBody - 遮罩片段不会叠加在另一个表情之上。 已在Explorer的 中验证:在本地玩家上启动遮罩表情会停止正在播放的任何全身表情,而启动全身表情会取消遮罩表情。因此,遮罩片段不能在椅子的坐姿表情之上运行——Avatar会站起来。它只叠加在运动状态之上,这就是遮罩的用途:在玩家行走、奔跑或空闲时,进行携带、持物或欢呼。
SceneMaskedEmoteSystem - 对于坐姿玩家,要播放全身动画。 在每个片段中都制作坐姿下半身(髋部下沉、FK腿弯曲),不加遮罩触发,当片段结束且没有循环坐姿片段接替时,让场景重新播放坐姿表情(或椅子自己的表情)。如果一次性动画结束时回到与循环空闲片段相同的坐姿,就可以无缝衔接;唯一可见的跳变是与内置坐姿表情的高度差,你可以通过髋部下沉来调整。
triggerEmote({ predefinedEmote: 'sittingChair1' }) - 即使是用于遮罩,也要制作全身动画。 合理的下半身可以让同一个文件在不加遮罩时也能使用。遮罩是触发时的决定,不是文件的属性。
- 本地玩家的遮罩表情不会发出 生命周期事件(已在 player-avatar 中记录)。因此场景必须自己计时——将每个片段的时长与其路径一起存储在场景配置中,因为你可以从帧数中准确得知时长。
AvatarEmoteCommand
坐姿持物姿势的设计建议,效果较好的是:髋部≈0.6米,手在胸部高度,头部向手的方向倾斜。
上述骨骼列表和混合机制来自Explorer源码(分支,2026-09,main、MaskedLegacyEmoteBlender、SceneMaskedEmoteSystem);"遮罩会停止全身表情"的规则已在坐姿玩家的游戏内验证。对于枚举值和调用签名,请以 player-avatar 为准,该部分已对照发布的协议验证。CharacterEmoteSystem
File requirements
文件要求
| Requirement | Value | Source |
|---|---|---|
| Frame rate | 30 fps (Blender defaults to 24) | docs |
| Max length | 10 s / 300 frames | docs |
| Format | | docs |
| Max file size | 3 MB | docs |
| Sampling rate | | docs |
| Animation clips per file | exactly 1 (Emotes 2.0 may add 1 prop clip; sequences unsupported) | docs |
| File contents | deforming skeleton + animation only — no mesh, no control bones, no cameras/lights | docs |
| Start / end pose | both from the idle ( | docs |
| Deform-bone keys | location + rotation + scale on the first and last frame, every bone | docs |
| Animation area | root ≤ 1 m in each horizontal direction (2 m across); every mesh part and prop inside the 4 × 4 × 4 m | docs + measured |
| Filename | must end | player-avatar |
| Scene permission | | player-avatar |
Conventional location in the scene: . The glTF animation's name is irrelevant to the runtime — the file path is the identifier.
assets/animations/Blender's glTF exporter UI equivalents, if the user is exporting by hand: Include > Limit to > Visible Objects, Data > Armature > Export Deformation Bones Only, Animation > Sampling Animations.
The Decentraland Tools add-on's Validate Emote operator checks most of this (30 fps, ≤ 300 frames, exactly one armature action, first/last-frame keys on deform channels) before it will export, and warns — without blocking — when the COG moves more than 1 m horizontally or vertically. It does not check the 4 m bounding box.
| 要求 | 数值 | 来源 |
|---|---|---|
| 帧率 | 30 fps(Blender默认为24) | 文档 |
| 最大长度 | 10秒 / 300帧 | 文档 |
| 格式 | | 文档 |
| 最大文件大小 | 3 MB | 文档 |
| 采样率 | 默认 | 文档 |
| 每个文件的动画片段数 | 恰好1个(Emotes 2.0可能会添加1个道具片段;不支持序列) | 文档 |
| 文件内容 | 仅变形骨架 + 动画——无网格、无控制骨骼、无相机/灯光 | 文档 |
| 开始/结束姿势 | 都来自空闲姿势( | 文档 |
| 变形骨骼关键帧 | 在第一帧和最后一帧为所有骨骼设置位置+旋转+缩放关键帧 | 文档 |
| 动画区域 | 根节点每个水平方向移动≤1米(总跨度2米);每个网格部件和道具都在 4 × 4 × 4 米 的 | 文档 + 实测 |
| 文件名 | 必须以 | player-avatar |
| 场景权限 | | player-avatar |
场景中的常规位置:。glTF动画的名称与运行时无关——文件路径才是标识符。
assets/animations/如果用户手动导出,Blender的glTF导出器UI对应选项:Include > Limit to > Visible Objects、Data > Armature > Export Deformation Bones Only、Animation > Sampling Animations。
Decentraland Tools插件的Validate Emote 操作符会在导出前检查大部分要求(30 fps、≤300帧、恰好一个骨架动作、变形通道的首末帧关键帧),并且在重心水平或垂直移动超过1米时发出警告(但不会阻止导出)。它不会检查4米边界框。
Testing in the scene
在场景中测试
The fastest harness is a row of clickable primitive cubes — + + with a generous so they stay clickable from a chair — one per clip, plus a Stop cube and a mask toggle cube:
MeshRendererMeshColliderpointerEventsSystem.onPointerDownmaxDistancetypescript
pointerEventsSystem.onPointerDown(
{ entity: cube, opts: { button: InputAction.IA_POINTER, hoverText: label, maxDistance } },
() => void triggerSceneEmote({ src, loop: false, mask: upperBody ? AvatarMask.AM_UPPER_BODY : undefined })
)Gate the whole harness behind a config flag and remove it before publishing.
The Explorer MCP's only plays URN/base emotes, not scene files — it cannot test a . Use in-scene triggers (see unity-explorer-mcp for driving the client around them).
trigger_emote_emote.glb最快的测试工具是一排可点击的基础立方体—— + + ,设置足够大的 这样坐在椅子上也能点击——每个片段对应一个立方体,再加上一个停止立方体和一个遮罩切换立方体:
MeshRendererMeshColliderpointerEventsSystem.onPointerDownmaxDistancetypescript
pointerEventsSystem.onPointerDown(
{ entity: cube, opts: { button: InputAction.IA_POINTER, hoverText: label, maxDistance } },
() => void triggerSceneEmote({ src, loop: false, mask: upperBody ? AvatarMask.AM_UPPER_BODY : undefined })
)将整个测试工具放在配置开关后面,发布前移除。
Explorer MCP的 仅播放URN/基础表情,不播放场景文件——它无法测试 。使用场景内触发器(参见 unity-explorer-mcp 了解如何操控客户端访问这些触发器)。
trigger_emote_emote.glbCross-references
交叉引用
- player-avatar — /
triggerSceneEmote/stopEmote/AvatarEmoteCommand, theAvatarMaskrule, the permission, and freezing the player with_emote.glbduring a full-body emote.InputModifier - add-3d-models → — how to drive Blender at all (headless CLI vs MCP), plus general model export rules.
references/blender-authoring.md - animations-tweens — animations baked into props and models, and procedural motion.
Tween - npcs — animating NPCs and GLB NPCs.
AvatarShape - Official docs: creating emotes · rig features · avatar rig
- player-avatar — /
triggerSceneEmote/stopEmote/AvatarEmoteCommand、AvatarMask规则、权限,以及在全身表情期间用_emote.glb冻结玩家。InputModifier - add-3d-models → — 如何操作Blender(无头CLI vs MCP),以及通用模型导出规则。
references/blender-authoring.md - animations-tweens — 烘焙到道具和模型中的动画,以及程序化 运动。
Tween - npcs — 为 NPC和GLB NPC添加动画。
AvatarShape - 官方文档:创建表情 · 绑定功能 · Avatar绑定