animation自动生成
分类:包 · 清单:use "kernels/";
骨骼、驱动它的动画片段与跟随的网格:片段采样与混合、行走、瞄准、蒙皮。
A skeleton, the clips that pose it and the mesh that follows: sampling and blending clips, walking, aiming, and skinning by the joint palette.
Layer: Simulation. Uses: geometry, mesh.
use "animation.entpkg";Kernels
Section titled “Kernels”kernels/aim.ent— Aiming. Kernels:animation.aim@1.kernels/clip.ent— Clips. Kernels:animation.clock@1,animation.sample@1,animation.blend@1,animation.add@1.kernels/gait.ent— Walking. Kernels:animation.stride@1,animation.travel@1.kernels/skeleton.ent— A skeleton, the clips that pose it, and the mesh that follows.kernels/skin.ent— Skinning. Kernels:animation.palette@1,animation.apply@1,animation.place@1.
Graph presets
Section titled “Graph presets”graphs/pose.esn— One clip playing on one skeleton, as one node.
tests/ holds scenes and their replays, run on every backend:
aim.replay, clips.replay. Every Kernel of the package is reached by
one of them.
Used by the animation, voxel examples.
Kernel
Section titled “Kernel”| Kernel | 执行模式 | 简述 |
|---|---|---|
animation.add@1 |
map | A pose laid over another: what add does differently from rest is done to base, by weight. A clip authored as a difference — a flinch, a lean, a breath — plays over whatever the body is already doing, which is what a game blends on top of a walk. |
animation.aim@1 |
map | One joint turned to face a point, over whatever the poses already say: a head that follows what it looks at, an arm that reaches, a gun that tracks. The joint’s axis, in its own space (a bone from Blender runs along its y), is turned the shortest way onto the target, and that turn is laid over the pose the joint already had, so the twist the clip gives it stays; weight blends between the two. Every other joint passes through, so this sits between sampling and the palette and the chain below the joint follows it. |
animation.apply@1 |
map | The mesh in the pose the palette says: four joints a vertex, weighted. A node sized instances * count(mesh) poses a crowd out of one mesh, each instance reading its own block of the palette. |
animation.blend@1 |
map | Two poses of one skeleton, blended: a walk into a run, a turn laid over either. A Kernel or the graph decides mix, so it can move every frame. |
animation.clock@1 |
map | The clock a clip is read at, as a row of one second: the simple case, where a clip plays at its own speed from the start of the session. |
animation.palette@1 |
map | The palette: each joint’s local transform composed up the parent chain and taken through its inverse bind, which is the matrix a vertex bound to that joint is moved by. |
animation.place@1 |
map | Where each instance stands: one Pose a instance, applied to the mesh it posed. A crowd is this over animation.apply@1’s output. |
animation.sample@1 |
map | Every joint’s local transform at the moment the clock says, blended between the two frames it falls between. A clip ends where its rows end: repeat wraps round to the start, and otherwise the last frame holds. |
animation.stride@1 |
map | A traveling clip played in place: every joint as animation.sample@1 would pose it, looping every frames - 1 frames as the clip closes on itself, and the root with its travel along the ground axes taken out. What stays in the root is what is not travel — a walk’s bob, its sway on an axis ground leaves out — and the travel is what animation.travel@1 gives the scene to carry. |
animation.travel@1 |
map | How far a traveling clip’s root moved between two moments, was and at, one row an instance: the travel animation.stride@1 took out of the pose, for the scene to add to where the body stands. It is the difference of where the root had got to at each, so a scene that adds it every evaluation stands where the clip says whatever its frames are, loops and all. |
类型与结构体
Section titled “类型与结构体”| 名称 | 写法 |
|---|---|
Walk |
struct Walk { matrix: Mat4; joint: Int; } |
Joint |
struct Joint { parent: Int; bind: Mat4; } |
Pose |
struct Pose { at: Vec3; turn: Vec4; grow: Vec3; } |
Bound |
struct Bound { joints: [Int; 4]; weights: Vec4; } |
Skeleton |
type Skeleton = Rows<Joint>; |
Clip |
type Clip = Rows<Pose>; |
Palette |
type Palette = Rows<Mat4>; |
| 名称 | 接口 | 说明 |
|---|---|---|
pose |
input mesh: Rows<MeshPoint>input weights: Rows<Bound>input skeleton: Skeletoninput clip: Clipinput at: Rows<Float>param rate: Float = 30.0param repeat: Bool = trueparam depth: Int = 64output result <- posed.resultoutput palette <- palette.result |
One clip playing on one skeleton, as one node. Place it with node posed: graph “animation.entpkg/graphs/pose.esn” { mesh <- mesh; weights <- weights; skeleton <- skeleton; clip <- walk; at <- clock.result; rate = 30.0; } and hand posed.result to whatever projects it. Blending two clips wants the Kernels themselves: sample each, animation.blend@1, then animation.palette@1. |
Kernel 说明
Section titled “Kernel 说明”animation.add@1
Section titled “animation.add@1”A pose laid over another: what add does differently from rest is done to base, by weight. A clip authored as a difference — a flinch, a lean, a breath — plays over whatever the body is already doing, which is what a game blends on top of a walk.
rest is the frame the difference is measured from, which is the additive clip’s own first frame: sample it at zero.
| 执行模式 | map |
| 需要能力 | field.read, field.write |
| 输入 | base: Rows<Pose>, add: Rows<Pose>, rest: Rows<Pose>, weight: Rows<Float> |
| 参数 | — |
| 输出 | result: Rows<Pose> |
animation.aim@1
Section titled “animation.aim@1”One joint turned to face a point, over whatever the poses already say: a head that follows what it looks at, an arm that reaches, a gun that tracks. The joint’s axis, in its own space (a bone from Blender runs along its y), is turned the shortest way onto the target, and that turn is laid over the pose the joint already had, so the twist the clip gives it stays; weight blends between the two. Every other joint passes through, so this sits between sampling and the palette and the chain below the joint follows it.
target is in the skin’s space, one row an instance: a crowd sized instances * count(skeleton) has each instance look at its own.
| 执行模式 | map |
| 需要能力 | field.read, field.write |
| 输入 | poses: Rows<Pose>, skeleton: Rows<Joint>, target: Rows<Vec3>, weight: Rows<Float> |
| 参数 | joint: Int = 0, axis: Vec3 = [0.0, 1.0, 0.0], depth: Int = 64 |
| 输出 | result: Rows<Pose> |
| 源码 | packages/animation.entpkg/kernels/aim.ent |
animation.apply@1
Section titled “animation.apply@1”The mesh in the pose the palette says: four joints a vertex, weighted. A node sized instances * count(mesh) poses a crowd out of one mesh, each instance reading its own block of the palette.
A vertex bound to nothing — all four weights zero, which is what a model that mixes skinned and unskinned meshes writes — is left where it is.
| 执行模式 | map |
| 需要能力 | field.read, field.write |
| 输入 | mesh: Rows<MeshPoint>, weights: Rows<Bound>, palette: Rows<Mat4>, skeleton: Rows<Joint> |
| 参数 | — |
| 输出 | result: Rows<MeshPoint> |
animation.blend@1
Section titled “animation.blend@1”Two poses of one skeleton, blended: a walk into a run, a turn laid over either. A Kernel or the graph decides mix, so it can move every frame.
mix of one row is the whole skeleton. A row a joint is a mask: an upper body running while the legs walk is the same blend with ones down the arms and zeros down the legs.
| 执行模式 | map |
| 需要能力 | field.read, field.write |
| 输入 | first: Rows<Pose>, second: Rows<Pose>, mix: Rows<Float> |
| 参数 | — |
| 输出 | result: Rows<Pose> |
animation.clock@1
Section titled “animation.clock@1”The clock a clip is read at, as a row of one second: the simple case, where a clip plays at its own speed from the start of the session.
| 执行模式 | map |
| 需要能力 | field.write, time.read |
| 输入 | — |
| 参数 | speed: Float = 1.0 |
| 输出 | result: Rows<Float> |
animation.palette@1
Section titled “animation.palette@1”The palette: each joint’s local transform composed up the parent chain and taken through its inverse bind, which is the matrix a vertex bound to that joint is moved by.
| 执行模式 | map |
| 需要能力 | field.read, field.write |
| 输入 | poses: Rows<Pose>, skeleton: Rows<Joint> |
| 参数 | depth: Int = 64 |
| 输出 | result: Rows<Mat4> |
animation.place@1
Section titled “animation.place@1”Where each instance stands: one Pose a instance, applied to the mesh it posed. A crowd is this over animation.apply@1’s output.
| 执行模式 | map |
| 需要能力 | field.read, field.write |
| 输入 | mesh: Rows<MeshPoint>, places: Rows<Pose>, one: Rows<MeshPoint> |
| 参数 | — |
| 输出 | result: Rows<MeshPoint> |
animation.sample@1
Section titled “animation.sample@1”Every joint’s local transform at the moment the clock says, blended between the two frames it falls between. A clip ends where its rows end: repeat wraps round to the start, and otherwise the last frame holds.
A node sized instances * count(skeleton) poses a crowd instead of one: element e is joint e % joints of instance e / joints, and each instance reads its own row of at, so a hundred of them walk the same clip out of step. Sized for one — which is what a node with no domain of its own is — it is the same Kernel doing the same thing.
| 执行模式 | map |
| 需要能力 | field.read, field.write |
| 输入 | skeleton: Rows<Joint>, clip: Rows<Pose>, at: Rows<Float> |
| 参数 | rate: Float = 30.0, repeat: Bool = True |
| 输出 | result: Rows<Pose> |
animation.stride@1
Section titled “animation.stride@1”A traveling clip played in place: every joint as animation.sample@1 would pose it, looping every frames - 1 frames as the clip closes on itself, and the root with its travel along the ground axes taken out. What stays in the root is what is not travel — a walk’s bob, its sway on an axis ground leaves out — and the travel is what animation.travel@1 gives the scene to carry.
| 执行模式 | map |
| 需要能力 | field.read, field.write |
| 输入 | skeleton: Rows<Joint>, clip: Rows<Pose>, at: Rows<Float> |
| 参数 | rate: Float = 30.0, joint: Int = 0, ground: Vec3 = [1.0, 0.0, 1.0] |
| 输出 | result: Rows<Pose> |
| 源码 | packages/animation.entpkg/kernels/gait.ent |
animation.travel@1
Section titled “animation.travel@1”How far a traveling clip’s root moved between two moments, was and at, one row an instance: the travel animation.stride@1 took out of the pose, for the scene to add to where the body stands. It is the difference of where the root had got to at each, so a scene that adds it every evaluation stands where the clip says whatever its frames are, loops and all.
| 执行模式 | map |
| 需要能力 | field.read, field.write |
| 输入 | skeleton: Rows<Joint>, clip: Rows<Pose>, at: Rows<Float>, was: Rows<Float> |
| 参数 | rate: Float = 30.0, joint: Int = 0, ground: Vec3 = [1.0, 0.0, 1.0] |
| 输出 | result: Rows<Vec3> |
| 源码 | packages/animation.entpkg/kernels/gait.ent |
aim.replay, clips.replay

