@volter/blender-engine 0.1.133 → 0.1.135
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/browser/protocol.ts +0 -9
- package/browser/rna.ts +29 -86
- package/browser/runtime.ts +0 -16
- package/browser/session.py +471 -190
- package/browser/three/blender-runtime-armature.ts +74 -0
- package/browser/three/blender-runtime-skeleton.ts +206 -0
- package/browser/three/blender-runtime-view.ts +132 -7
- package/browser/worker.ts +0 -7
- package/package.json +1 -1
- package/wasm/BUNDLE.json +11 -11
- package/wasm/blender_browser.js +1 -1
- package/wasm/blender_browser.wasm.br +0 -0
package/browser/protocol.ts
CHANGED
|
@@ -68,20 +68,11 @@ export type WorkerRequest =
|
|
|
68
68
|
* Given no `object`, the view layer's active object answers. READ ONLY:
|
|
69
69
|
* pinning, unwrapping and selecting are edits. */
|
|
70
70
|
| { id: number; op: 'uv-layout'; object?: string; uvLayer?: string }
|
|
71
|
-
/** ONE MESH'S SKIN BINDING (`session.py`'s `rna_rig`) — the armature's bones
|
|
72
|
-
* with their rest AND bind matrices, plus up to four weighted influences
|
|
73
|
-
* per Blender vertex as base64 typed-array bytes. The BIND pose is the
|
|
74
|
-
* pose the exported columns were evaluated at, which is what lets three.js
|
|
75
|
-
* own playback without Blender's frame ever moving. READ ONLY. */
|
|
76
|
-
| { id: number; op: 'rig'; object?: string }
|
|
77
71
|
/** ONE ACTION AS A THREE.JS CLIP (`session.py`'s `rna_action_clip`) — per
|
|
78
72
|
* bone, the LOCAL transform at every integer frame of the action's range,
|
|
79
73
|
* plus the scene's frame range/fps and the summary row's key columns.
|
|
80
74
|
* READ ONLY: keying, moving a key and setting a range are edits. */
|
|
81
75
|
| { id: number; op: 'action-clip'; object?: string; bake?: boolean; action?: string }
|
|
82
|
-
/** EVERY ARMATURE AND THE ACTIONS THAT CAN PLAY ON IT (`session.py`'s `rna_armature_actions`):
|
|
83
|
-
* each action that animates one of its pose bones, assigned or not. READ ONLY. */
|
|
84
|
-
| { id: number; op: 'armature-actions' }
|
|
85
76
|
/** ONE RESTRICTION COLUMN, written (`session.py`'s `outliner_set`). A column
|
|
86
77
|
* Blender draws on no row of that type is refused by name. */
|
|
87
78
|
| { id: number; op: 'outliner-set'; path: string; column: string; value: boolean }
|
package/browser/rna.ts
CHANGED
|
@@ -528,95 +528,29 @@ export interface BlenderUvLayout {
|
|
|
528
528
|
}
|
|
529
529
|
|
|
530
530
|
/**
|
|
531
|
-
* ONE
|
|
532
|
-
* `
|
|
533
|
-
*
|
|
534
|
-
* WE VISUALIZE WITH THREE.JS, NOT BLENDER (owner rule, 2026-09-20). Blender
|
|
535
|
-
* holds the animation as DATA; three.js plays it. This door and
|
|
536
|
-
* {@link BlenderActionClip} are the whole of what crosses to make that true —
|
|
537
|
-
* once per rig, rather than a depsgraph evaluation and a re-export per frame.
|
|
538
|
-
*
|
|
539
|
-
* THE BIND POSE IS `pose`, NOT `rest`, and that is the load-bearing fact: the
|
|
540
|
-
* export door runs with `evaluate: True`, so the mesh columns the presenter
|
|
541
|
-
* holds are the mesh ALREADY DEFORMED at Blender's current frame. A skeleton
|
|
542
|
-
* bound in that same pose makes the skinning an identity there, so the picture
|
|
543
|
-
* at the bind frame is exactly the frame Blender presented — and Blender's
|
|
544
|
-
* `frame_current` never has to move again for playback.
|
|
545
|
-
*
|
|
546
|
-
* THE INDICES ARE BLENDER VERTEX INDICES. `DrawArrays.sourceVertex` maps a
|
|
547
|
-
* drawn vertex back to its Blender one, and the presenter expands these arrays
|
|
548
|
-
* through it (`blender-runtime-skin.ts`) exactly as I4's weight ramp does.
|
|
531
|
+
* ONE F-CURVE of {@link BlenderActionClip}, whole: one component (`index`) of one of a bone's
|
|
532
|
+
* channels (`location`, `rotation_quaternion` as w,x,y,z, `rotation_euler`, `rotation_axis_angle`
|
|
533
|
+
* as angle,x,y,z, `scale`), with everything `fcurve_eval_keyframes` reads to evaluate it.
|
|
549
534
|
*/
|
|
550
|
-
export interface
|
|
551
|
-
readonly
|
|
552
|
-
readonly
|
|
553
|
-
|
|
554
|
-
* row-major as four rows. Diagnostic here; the bind is `pose`. */
|
|
555
|
-
readonly rest: readonly (readonly [number, number, number, number])[];
|
|
556
|
-
/** `PoseBone.matrix` (`pchan->pose_mat`), the same matrix I4's bone overlay
|
|
557
|
-
* draws — the BIND pose, in the armature object's space. */
|
|
558
|
-
readonly pose: readonly (readonly [number, number, number, number])[];
|
|
559
|
-
readonly length: number;
|
|
560
|
-
readonly deform: boolean;
|
|
561
|
-
readonly connected: boolean;
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
export interface BlenderRigBinding {
|
|
565
|
-
readonly object: string | null;
|
|
566
|
-
readonly mesh?: string;
|
|
567
|
-
readonly armature: string | null;
|
|
568
|
-
readonly armatureData?: string;
|
|
569
|
-
readonly bones: readonly BlenderRigBone[];
|
|
570
|
-
readonly vertexCount: number;
|
|
571
|
-
/** `scene.frame_current` when the binding was read — the frame the exported
|
|
572
|
-
* columns, and therefore the bind pose, belong to. */
|
|
573
|
-
readonly frame?: number;
|
|
574
|
-
readonly mode?: string;
|
|
575
|
-
/** Bones whose pose is a SOLVER's rather than their channels'. The clip is
|
|
576
|
-
* derived from the F-Curves alone, so a constrained bone's playback cannot
|
|
577
|
-
* reproduce Blender's own answer; the view names them instead of drifting. */
|
|
578
|
-
readonly constrainedBones?: readonly string[];
|
|
579
|
-
/** Uint16, `vertexCount * 4`. */
|
|
580
|
-
readonly skinIndexBase64?: string;
|
|
581
|
-
/** Float32, `vertexCount * 4`, each vertex's four normalized to sum to one. */
|
|
582
|
-
readonly skinWeightBase64?: string;
|
|
583
|
-
readonly maxInfluences?: number;
|
|
584
|
-
readonly truncatedVertices?: number;
|
|
585
|
-
readonly unweightedVertices?: number;
|
|
586
|
-
readonly unmappedGroups?: readonly string[];
|
|
587
|
-
/** Why there is no binding, when there is none. Never a silent empty. */
|
|
588
|
-
readonly reason?: string;
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
/** EVERY SKIN BINDING THE SCENE NEEDS, which is the PRESENTER's question: a
|
|
592
|
-
* presented frame carries every object at once and the presenter has to know
|
|
593
|
-
* which of its meshes are `THREE.SkinnedMesh`es before it builds them. With
|
|
594
|
-
* `named` set, the list is that one mesh. */
|
|
595
|
-
export interface BlenderRig {
|
|
596
|
-
/** `scene.frame_current` when the bindings were read — the frame the
|
|
597
|
-
* exported columns, and therefore every bind pose here, belong to. */
|
|
598
|
-
readonly frame: number;
|
|
599
|
-
readonly named: string | null;
|
|
600
|
-
readonly rigs: readonly BlenderRigBinding[];
|
|
535
|
+
export interface BlenderClipTrack extends BlenderClipCurve {
|
|
536
|
+
readonly bone: string;
|
|
537
|
+
readonly property: 'location' | 'rotation_quaternion' | 'rotation_euler' | 'rotation_axis_angle' | 'scale';
|
|
538
|
+
readonly index: number;
|
|
601
539
|
}
|
|
602
540
|
|
|
603
|
-
/**
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
*/
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
readonly
|
|
614
|
-
|
|
615
|
-
readonly
|
|
616
|
-
/** Float32 seconds, `count` of them, zero at `clipStart`. */
|
|
617
|
-
readonly timeBase64: string;
|
|
618
|
-
/** Float32, `count * stride`. */
|
|
619
|
-
readonly valueBase64: string;
|
|
541
|
+
/** An F-Curve's body: everything Blender evaluates it from, wherever it lives. */
|
|
542
|
+
export interface BlenderClipCurve {
|
|
543
|
+
/** `FCurve.extrapolation`: `CONSTANT` or `LINEAR`. */
|
|
544
|
+
readonly extrapolation: string;
|
|
545
|
+
/** Per key, how the segment after it interpolates: 0 constant, 1 linear, 2 Bezier. */
|
|
546
|
+
readonly interpolation: readonly number[];
|
|
547
|
+
/** Float32, six per key: `co`, `handle_left`, `handle_right` (frame, value each). */
|
|
548
|
+
readonly keysBase64: string;
|
|
549
|
+
/** A Cycles modifier: [mode before, cycles before, mode after, cycles after]; mode 0 none,
|
|
550
|
+
* 1 repeat, 2 repeat with offset, 3 mirror. */
|
|
551
|
+
readonly cycles?: readonly [number, number, number, number];
|
|
552
|
+
/** What this curve does in Blender that is not played (an easing type, another modifier). */
|
|
553
|
+
readonly unsupported?: readonly string[];
|
|
620
554
|
}
|
|
621
555
|
|
|
622
556
|
/** One column of the Timeline's summary row: a frame at which SOMETHING is
|
|
@@ -689,9 +623,18 @@ export interface BlenderActionClip {
|
|
|
689
623
|
readonly tracks: readonly BlenderClipTrack[];
|
|
690
624
|
readonly clipStart?: number;
|
|
691
625
|
readonly clipEnd?: number;
|
|
626
|
+
/** The range Blender places the action over NLA strips in: its keys, null on a side a Cycles
|
|
627
|
+
* modifier repeats into. */
|
|
628
|
+
readonly keysStart?: number | null;
|
|
629
|
+
readonly keysEnd?: number | null;
|
|
630
|
+
/** Blender repeats it past its range (Cycles modifiers on its curves, or `use_cyclic`). */
|
|
631
|
+
readonly cyclic?: boolean;
|
|
692
632
|
readonly duration?: number;
|
|
693
633
|
readonly sampled?: number;
|
|
694
634
|
/** Bones the action names that the armature does not have. */
|
|
695
635
|
readonly unplayedBones?: readonly string[];
|
|
636
|
+
/** What the action keys besides bone channels (the object's own transform, a property),
|
|
637
|
+
* which plays only in Blender. */
|
|
638
|
+
readonly unsupported?: readonly string[];
|
|
696
639
|
readonly reason?: string;
|
|
697
640
|
}
|
package/browser/runtime.ts
CHANGED
|
@@ -21,7 +21,6 @@ import type {
|
|
|
21
21
|
BlenderNodeTree,
|
|
22
22
|
BlenderOutlinerTree,
|
|
23
23
|
BlenderOutlinerWrite,
|
|
24
|
-
BlenderRig,
|
|
25
24
|
BlenderRnaContext,
|
|
26
25
|
BlenderRnaView,
|
|
27
26
|
BlenderRnaWrite,
|
|
@@ -408,16 +407,6 @@ export class BlenderRuntime {
|
|
|
408
407
|
})) as BlenderUvLayout;
|
|
409
408
|
}
|
|
410
409
|
|
|
411
|
-
/** ONE MESH'S SKIN BINDING (`./rna.ts`, `BlenderRig`) — the armature's
|
|
412
|
-
* bones and the per-vertex influences a `THREE.SkinnedMesh` needs. Given no
|
|
413
|
-
* `object`, the view layer's ACTIVE mesh answers. */
|
|
414
|
-
async rig(options?: { object?: string }): Promise<BlenderRig> {
|
|
415
|
-
await this.#ready();
|
|
416
|
-
return (await this.#request({
|
|
417
|
-
op: 'rig',
|
|
418
|
-
...(options?.object === undefined ? {} : { object: options.object }),
|
|
419
|
-
})) as BlenderRig;
|
|
420
|
-
}
|
|
421
410
|
|
|
422
411
|
/** ONE ACTION AS A THREE.JS CLIP (`./rna.ts`, `BlenderActionClip`). `bake:
|
|
423
412
|
* false` answers the header and the summary row's key columns without the
|
|
@@ -433,11 +422,6 @@ export class BlenderRuntime {
|
|
|
433
422
|
})) as BlenderActionClip;
|
|
434
423
|
}
|
|
435
424
|
|
|
436
|
-
/** Every armature and the actions that can play on it, assigned or not (a game's clip library). */
|
|
437
|
-
async armatureActions(): Promise<{ armatures: { armature: string; current: string | null; actions: string[]; keys?: string }[]; scene?: { frameCurrent: number; frameStart: number; frameEnd: number; fps: number } }> {
|
|
438
|
-
await this.#ready();
|
|
439
|
-
return (await this.#request({ op: 'armature-actions' })) as { armatures: { armature: string; current: string | null; actions: string[]; keys?: string }[]; scene?: { frameCurrent: number; frameStart: number; frameEnd: number; fps: number } };
|
|
440
|
-
}
|
|
441
425
|
|
|
442
426
|
/** Write ONE restriction column (the eye, the render camera, a collection's
|
|
443
427
|
* Exclude). A column Blender draws on no row of that type is refused by
|