@ikijs/editor 0.18.0 → 0.20.0
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/README.md +20 -16
- package/dist/index.d.mts +106 -34
- package/dist/index.d.ts +106 -34
- package/dist/index.js +376 -132
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +375 -130
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -62,6 +62,7 @@ __export(index_exports, {
|
|
|
62
62
|
createLayerSetMeasurer: () => createLayerSetMeasurer,
|
|
63
63
|
denseCoreOf: () => denseCoreOf,
|
|
64
64
|
detectAlphaBbox: () => detectAlphaBbox,
|
|
65
|
+
forearmPoseGeometry: () => forearmPoseGeometry,
|
|
65
66
|
foregroundSpan: () => foregroundSpan,
|
|
66
67
|
generateIkiFromLayerSet: () => generateIkiFromLayerSet,
|
|
67
68
|
headHalfOf: () => headHalfOf,
|
|
@@ -1641,7 +1642,13 @@ var ROW_RUN_ROLES = /* @__PURE__ */ new Set([
|
|
|
1641
1642
|
"hair_back",
|
|
1642
1643
|
"body",
|
|
1643
1644
|
"arm_L",
|
|
1644
|
-
"arm_R"
|
|
1645
|
+
"arm_R",
|
|
1646
|
+
"forearm_pose_L",
|
|
1647
|
+
"forearm_pose_R"
|
|
1648
|
+
]);
|
|
1649
|
+
var REST_HIDDEN_ROLES = /* @__PURE__ */ new Set([
|
|
1650
|
+
"forearm_pose_L",
|
|
1651
|
+
"forearm_pose_R"
|
|
1645
1652
|
]);
|
|
1646
1653
|
function createLayerSetMeasurer(canvas) {
|
|
1647
1654
|
for (const field of ["width", "height"]) {
|
|
@@ -1672,6 +1679,7 @@ function createLayerSetMeasurer(canvas) {
|
|
|
1672
1679
|
if (bbox === null) return null;
|
|
1673
1680
|
const rowLeft = new Int32Array(canvasH).fill(canvasW);
|
|
1674
1681
|
const rowRight = new Int32Array(canvasH).fill(-1);
|
|
1682
|
+
const hidden = REST_HIDDEN_ROLES.has(role);
|
|
1675
1683
|
const rowRuns = ROW_RUN_ROLES.has(role) ? [] : void 0;
|
|
1676
1684
|
for (let y = 0; y < canvasH; y++) {
|
|
1677
1685
|
let runs;
|
|
@@ -1687,14 +1695,14 @@ function createLayerSetMeasurer(canvas) {
|
|
|
1687
1695
|
runs.push(x);
|
|
1688
1696
|
inRun = on;
|
|
1689
1697
|
}
|
|
1690
|
-
if (!on) continue;
|
|
1698
|
+
if (!on || hidden) continue;
|
|
1691
1699
|
opaque[p] = 1;
|
|
1692
1700
|
if (x < rowLeft[y]) rowLeft[y] = x;
|
|
1693
1701
|
if (x > rowRight[y]) rowRight[y] = x;
|
|
1694
1702
|
}
|
|
1695
1703
|
if (runs !== void 0 && inRun) runs.push(canvasW);
|
|
1696
1704
|
}
|
|
1697
|
-
rowSpansByRole.push({ role, rowLeft, rowRight });
|
|
1705
|
+
if (!hidden) rowSpansByRole.push({ role, rowLeft, rowRight });
|
|
1698
1706
|
const layer = {
|
|
1699
1707
|
role,
|
|
1700
1708
|
fileName,
|
|
@@ -2754,7 +2762,11 @@ function headOwnBreath(hasBody) {
|
|
|
2754
2762
|
var ELBOW_AT = 0.42;
|
|
2755
2763
|
var CAP_ROWS = [0.1, 0.3];
|
|
2756
2764
|
var CAP_SEGMENTS = 12;
|
|
2757
|
-
var
|
|
2765
|
+
var CAP_INSET = 3;
|
|
2766
|
+
var capInset = (i) => Math.round(CAP_INSET * Math.min(1, Math.min(i, CAP_SEGMENTS - i) / 2));
|
|
2767
|
+
var CAP_RIM = 0.25;
|
|
2768
|
+
var ARM_RANGE = [-8, 32];
|
|
2769
|
+
var ELBOW_RANGE = [-10, 90];
|
|
2758
2770
|
var ARM_PARAMS = {
|
|
2759
2771
|
arm_L: { arm: import_format5.StandardParameter.ArmLeft, elbow: import_format5.StandardParameter.ElbowLeft },
|
|
2760
2772
|
arm_R: { arm: import_format5.StandardParameter.ArmRight, elbow: import_format5.StandardParameter.ElbowRight }
|
|
@@ -2762,49 +2774,67 @@ var ARM_PARAMS = {
|
|
|
2762
2774
|
var ARM_IDS = {
|
|
2763
2775
|
arm_L: {
|
|
2764
2776
|
forearm: "forearm_L",
|
|
2777
|
+
cap: "elbow_L",
|
|
2765
2778
|
armDeformer: "armDeformer_L",
|
|
2766
2779
|
forearmDeformer: "forearmDeformer_L"
|
|
2767
2780
|
},
|
|
2768
2781
|
arm_R: {
|
|
2769
2782
|
forearm: "forearm_R",
|
|
2783
|
+
cap: "elbow_R",
|
|
2770
2784
|
armDeformer: "armDeformer_R",
|
|
2771
2785
|
forearmDeformer: "forearmDeformer_R"
|
|
2772
2786
|
}
|
|
2773
2787
|
};
|
|
2774
|
-
function
|
|
2788
|
+
function endPivot(layer, end) {
|
|
2775
2789
|
const { bbox, canvasW, canvasH, rowRuns } = layer;
|
|
2776
|
-
const
|
|
2777
|
-
const
|
|
2790
|
+
const span = runSpan(layer);
|
|
2791
|
+
const from = (k) => end === "top" ? k : bbox.h - 1 - k;
|
|
2792
|
+
const painted = rowRuns?.flatMap((runs, k) => runs.length > 0 ? [k] : []) ?? [];
|
|
2793
|
+
const firstK = end === "top" ? painted[0] ?? 0 : painted.at(-1) ?? bbox.h - 1;
|
|
2794
|
+
const lo = Math.ceil(CAP_ROWS[0] * bbox.h);
|
|
2795
|
+
const hi = Math.max(lo, Math.floor(CAP_ROWS[1] * bbox.h));
|
|
2796
|
+
const widths = [];
|
|
2797
|
+
for (let k = lo; k <= hi; k++) {
|
|
2798
|
+
const [s2, e2] = span(from(k));
|
|
2799
|
+
widths.push(e2 - s2);
|
|
2800
|
+
}
|
|
2801
|
+
widths.sort((p, q) => p - q);
|
|
2802
|
+
const radius = widths[widths.length >> 1] / 2;
|
|
2803
|
+
const ks = end === "top" ? firstK + radius : firstK - radius;
|
|
2804
|
+
const [s, e] = span(Math.round(ks));
|
|
2805
|
+
return {
|
|
2806
|
+
point: {
|
|
2807
|
+
x: roundTo((s + e) / 2 - canvasW / 2, 0.01),
|
|
2808
|
+
y: roundTo(canvasH / 2 - (bbox.y + ks + 0.5), 0.01)
|
|
2809
|
+
},
|
|
2810
|
+
radius,
|
|
2811
|
+
row: ks
|
|
2812
|
+
};
|
|
2813
|
+
}
|
|
2814
|
+
function runSpan(layer) {
|
|
2815
|
+
const { bbox, rowRuns } = layer;
|
|
2816
|
+
return (k) => {
|
|
2778
2817
|
const runs = rowRuns?.[k] ?? [];
|
|
2779
2818
|
if (runs.length === 0) return [bbox.x, bbox.x + bbox.w];
|
|
2780
|
-
let [
|
|
2819
|
+
let [s, e] = [runs[0], runs[1]];
|
|
2781
2820
|
for (let i = 2; i < runs.length; i += 2) {
|
|
2782
|
-
if (runs[i + 1] - runs[i] >
|
|
2821
|
+
if (runs[i + 1] - runs[i] > e - s) [s, e] = [runs[i], runs[i + 1]];
|
|
2783
2822
|
}
|
|
2784
|
-
return [
|
|
2823
|
+
return [s, e];
|
|
2785
2824
|
};
|
|
2825
|
+
}
|
|
2826
|
+
function armGeometry(layer, bodyAxisX) {
|
|
2827
|
+
const { bbox, canvasW, canvasH, rowRuns } = layer;
|
|
2828
|
+
const b = boxOfLayer(layer);
|
|
2829
|
+
const span = runSpan(layer);
|
|
2786
2830
|
const centreX = (k) => {
|
|
2787
2831
|
const [s2, e2] = span(k);
|
|
2788
2832
|
return (s2 + e2) / 2 - canvasW / 2;
|
|
2789
2833
|
};
|
|
2790
2834
|
const rowY = (k) => canvasH / 2 - (bbox.y + k + 0.5);
|
|
2791
2835
|
const painted = rowRuns?.flatMap((runs, k) => runs.length > 0 ? [k] : []) ?? [];
|
|
2792
|
-
const first = painted[0] ?? 0;
|
|
2793
2836
|
const last = painted.at(-1) ?? bbox.h - 1;
|
|
2794
|
-
const
|
|
2795
|
-
const hi = Math.max(lo, Math.floor(CAP_ROWS[1] * bbox.h));
|
|
2796
|
-
const widths = [];
|
|
2797
|
-
for (let k = lo; k <= hi; k++) {
|
|
2798
|
-
const [s2, e2] = span(k);
|
|
2799
|
-
widths.push(e2 - s2);
|
|
2800
|
-
}
|
|
2801
|
-
widths.sort((p, q) => p - q);
|
|
2802
|
-
const ru = widths[widths.length >> 1] / 2;
|
|
2803
|
-
const ks = first + ru;
|
|
2804
|
-
const shoulder = {
|
|
2805
|
-
x: roundTo(centreX(Math.round(ks)), 0.01),
|
|
2806
|
-
y: roundTo(rowY(ks), 0.01)
|
|
2807
|
-
};
|
|
2837
|
+
const { point: shoulder, radius: ru, row: ks } = endPivot(layer, "top");
|
|
2808
2838
|
const ke = Math.round(ks + ELBOW_AT * (last - ks));
|
|
2809
2839
|
if (ke <= ks) {
|
|
2810
2840
|
throw new LayerGeometryError(
|
|
@@ -2819,11 +2849,30 @@ function armGeometry(layer, bodyAxisX) {
|
|
|
2819
2849
|
b.x1 - elbow.x,
|
|
2820
2850
|
b.y1 - elbow.y
|
|
2821
2851
|
);
|
|
2852
|
+
const inside = (x, y) => {
|
|
2853
|
+
const k = Math.floor(y) - bbox.y;
|
|
2854
|
+
if (k < 0 || k >= bbox.h) return false;
|
|
2855
|
+
const [rs, re] = span(k);
|
|
2856
|
+
return rs < x && x < re;
|
|
2857
|
+
};
|
|
2858
|
+
const capRays = Array.from({ length: CAP_SEGMENTS + 1 }, (_, i) => {
|
|
2859
|
+
const a = Math.PI * i / CAP_SEGMENTS;
|
|
2860
|
+
let t = 1;
|
|
2861
|
+
while (t <= capRadius + CAP_INSET && inside(
|
|
2862
|
+
elbow.x + canvasW / 2 + t * Math.cos(a),
|
|
2863
|
+
canvasH / 2 - elbow.y - t * Math.sin(a)
|
|
2864
|
+
)) {
|
|
2865
|
+
t++;
|
|
2866
|
+
}
|
|
2867
|
+
return Math.min(capRadius, Math.max(1, t - capInset(i)));
|
|
2868
|
+
});
|
|
2822
2869
|
return {
|
|
2823
2870
|
shoulder,
|
|
2824
2871
|
shoulderRadius: ru,
|
|
2825
2872
|
elbow,
|
|
2826
2873
|
capRadius,
|
|
2874
|
+
capRays,
|
|
2875
|
+
seamRun: [s - bbox.x, e - bbox.x],
|
|
2827
2876
|
side: shoulder.x > bodyAxisX ? 1 : -1
|
|
2828
2877
|
};
|
|
2829
2878
|
}
|
|
@@ -2833,84 +2882,188 @@ function meshOf(vertices, indices) {
|
|
|
2833
2882
|
);
|
|
2834
2883
|
return { vertices, uvs, indices };
|
|
2835
2884
|
}
|
|
2836
|
-
function armParts(role, layer, g, order) {
|
|
2885
|
+
function armParts(role, layer, g, order, poseSwitch) {
|
|
2837
2886
|
const b = boxOfLayer(layer);
|
|
2838
2887
|
const lx = (x) => roundTo((x - cx(b)) / bw(b), 1e-5);
|
|
2839
2888
|
const ly = (y) => roundTo((y - cy(b)) / bh(b), 1e-5);
|
|
2840
2889
|
const seam = ly(g.elbow.y);
|
|
2841
|
-
const band = (
|
|
2890
|
+
const band = (top2, bottom) => [
|
|
2842
2891
|
-0.5,
|
|
2843
|
-
|
|
2892
|
+
top2,
|
|
2844
2893
|
0.5,
|
|
2845
|
-
|
|
2894
|
+
top2,
|
|
2846
2895
|
-0.5,
|
|
2847
2896
|
bottom,
|
|
2848
2897
|
0.5,
|
|
2849
2898
|
bottom
|
|
2850
2899
|
];
|
|
2851
2900
|
const quad = [2, 3, 0, 0, 3, 1];
|
|
2852
|
-
const
|
|
2901
|
+
const rays = g.capRays.length;
|
|
2902
|
+
const top = (rays - 1) / 2;
|
|
2903
|
+
const at = (i, r) => {
|
|
2904
|
+
const a = Math.PI * i / (rays - 1);
|
|
2905
|
+
return [lx(g.elbow.x + r * Math.cos(a)), ly(g.elbow.y + r * Math.sin(a))];
|
|
2906
|
+
};
|
|
2907
|
+
const width = (i) => Math.min(CAP_RIM * g.capRadius, g.capRays[i] / 2);
|
|
2908
|
+
const ringRays = Array.from({ length: rays }, (_, i) => i);
|
|
2909
|
+
ringRays.splice(top, 0, top);
|
|
2910
|
+
const vertices = [lx(g.elbow.x), seam];
|
|
2911
|
+
for (let i = 0; i < rays; i++) {
|
|
2912
|
+
vertices.push(...at(i, g.capRays[i] - width(i)));
|
|
2913
|
+
}
|
|
2914
|
+
const ringInner = vertices.length / 2;
|
|
2915
|
+
for (const i of ringRays) vertices.push(...at(i, g.capRays[i] - width(i)));
|
|
2916
|
+
const ringOuter = vertices.length / 2;
|
|
2917
|
+
for (const i of ringRays) vertices.push(...at(i, g.capRays[i]));
|
|
2918
|
+
const { uvs } = meshOf(vertices, []);
|
|
2919
|
+
const col = (c) => roundTo(Math.min(Math.max(c + 0.5, 0.5), bw(b) - 0.5) / bw(b), 1e-5);
|
|
2920
|
+
const v = roundTo(0.5 - seam, 1e-5);
|
|
2921
|
+
ringRays.forEach((i, j) => {
|
|
2922
|
+
const right = j <= top;
|
|
2923
|
+
const outer = right ? g.seamRun[1] : g.seamRun[0] - 1;
|
|
2924
|
+
const step = right ? -width(i) : width(i);
|
|
2925
|
+
uvs[(ringInner + j) * 2] = col(outer + step);
|
|
2926
|
+
uvs[(ringInner + j) * 2 + 1] = v;
|
|
2927
|
+
uvs[(ringOuter + j) * 2] = col(outer);
|
|
2928
|
+
uvs[(ringOuter + j) * 2 + 1] = v;
|
|
2929
|
+
});
|
|
2853
2930
|
const fan = [];
|
|
2854
|
-
for (let i = 0; i
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
);
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
const part = (id, deformer, at, mesh) => ({
|
|
2931
|
+
for (let i = 0; i < rays - 1; i++) fan.push(0, 1 + i, 2 + i);
|
|
2932
|
+
const ring = [];
|
|
2933
|
+
for (let j = 0; j < ringRays.length - 1; j++) {
|
|
2934
|
+
if (j === top) continue;
|
|
2935
|
+
const [p, q] = [ringInner + j, ringOuter + j];
|
|
2936
|
+
ring.push(p, q, q + 1, p, q + 1, p + 1);
|
|
2937
|
+
}
|
|
2938
|
+
const part = (id, deformer, z, mesh, swaps = false) => ({
|
|
2863
2939
|
id,
|
|
2864
2940
|
color: [1, 1, 1, 1],
|
|
2865
2941
|
width: bw(b),
|
|
2866
2942
|
height: bh(b),
|
|
2867
2943
|
transform: { x: cx(b), y: cy(b) },
|
|
2868
|
-
order:
|
|
2944
|
+
order: z,
|
|
2869
2945
|
deformer,
|
|
2870
|
-
mesh
|
|
2946
|
+
mesh,
|
|
2947
|
+
...swaps && poseSwitch !== void 0 ? {
|
|
2948
|
+
bindings: [
|
|
2949
|
+
{
|
|
2950
|
+
parameter: poseSwitch,
|
|
2951
|
+
channel: "opacity",
|
|
2952
|
+
from: 1,
|
|
2953
|
+
to: 0
|
|
2954
|
+
}
|
|
2955
|
+
]
|
|
2956
|
+
} : {}
|
|
2871
2957
|
});
|
|
2872
2958
|
const ids = ARM_IDS[role];
|
|
2873
2959
|
return [
|
|
2874
|
-
part(
|
|
2960
|
+
part(
|
|
2961
|
+
ids.cap,
|
|
2962
|
+
ids.forearmDeformer,
|
|
2963
|
+
order,
|
|
2964
|
+
{
|
|
2965
|
+
vertices,
|
|
2966
|
+
uvs,
|
|
2967
|
+
indices: [...fan, ...ring]
|
|
2968
|
+
},
|
|
2969
|
+
true
|
|
2970
|
+
),
|
|
2971
|
+
part(role, ids.armDeformer, order + 1, meshOf(band(0.5, seam), quad)),
|
|
2875
2972
|
part(
|
|
2876
2973
|
ids.forearm,
|
|
2877
2974
|
ids.forearmDeformer,
|
|
2878
|
-
order +
|
|
2879
|
-
meshOf(
|
|
2975
|
+
order + 2,
|
|
2976
|
+
meshOf(band(seam, -0.5), quad),
|
|
2977
|
+
true
|
|
2880
2978
|
)
|
|
2881
2979
|
];
|
|
2882
2980
|
}
|
|
2981
|
+
var rotateBinding = (parameter, range, sign) => ({
|
|
2982
|
+
parameter,
|
|
2983
|
+
channel: "rotate",
|
|
2984
|
+
from: sign * range[0],
|
|
2985
|
+
to: sign * range[1]
|
|
2986
|
+
});
|
|
2883
2987
|
function armDeformers(role, g) {
|
|
2884
2988
|
const ids = ARM_IDS[role];
|
|
2885
2989
|
const params = ARM_PARAMS[role];
|
|
2886
|
-
const rotate = (parameter) => ({
|
|
2887
|
-
parameter,
|
|
2888
|
-
channel: "rotate",
|
|
2889
|
-
from: g.side * ARM_RANGE[0],
|
|
2890
|
-
to: g.side * ARM_RANGE[1]
|
|
2891
|
-
});
|
|
2892
2990
|
return [
|
|
2893
2991
|
{
|
|
2894
2992
|
id: ids.armDeformer,
|
|
2895
2993
|
parent: BODY_WARP_ID,
|
|
2896
2994
|
pivot: { ...g.shoulder },
|
|
2897
|
-
bindings: [
|
|
2995
|
+
bindings: [rotateBinding(params.arm, ARM_RANGE, g.side)]
|
|
2898
2996
|
},
|
|
2899
2997
|
{
|
|
2900
2998
|
id: ids.forearmDeformer,
|
|
2901
2999
|
parent: ids.armDeformer,
|
|
2902
3000
|
pivot: { ...g.elbow },
|
|
2903
|
-
bindings: [
|
|
3001
|
+
bindings: [rotateBinding(params.elbow, ELBOW_RANGE, -g.side)]
|
|
2904
3002
|
}
|
|
2905
3003
|
];
|
|
2906
3004
|
}
|
|
2907
3005
|
|
|
3006
|
+
// src/auto-rig/forearm-pose.ts
|
|
3007
|
+
var import_format6 = require("@ikijs/format");
|
|
3008
|
+
var ARM_OF_POSE = {
|
|
3009
|
+
forearm_pose_L: "arm_L",
|
|
3010
|
+
forearm_pose_R: "arm_R"
|
|
3011
|
+
};
|
|
3012
|
+
var POSE_OF_ARM = {
|
|
3013
|
+
arm_L: "forearm_pose_L",
|
|
3014
|
+
arm_R: "forearm_pose_R"
|
|
3015
|
+
};
|
|
3016
|
+
var POSE_PARAMS = {
|
|
3017
|
+
forearm_pose_L: { pose: import_format6.StandardParameter.ArmPoseLeft, angle: import_format6.StandardParameter.ArmPoseAngleLeft },
|
|
3018
|
+
forearm_pose_R: { pose: import_format6.StandardParameter.ArmPoseRight, angle: import_format6.StandardParameter.ArmPoseAngleRight }
|
|
3019
|
+
};
|
|
3020
|
+
var POSE_IDS = {
|
|
3021
|
+
forearm_pose_L: "armPoseDeformer_L",
|
|
3022
|
+
forearm_pose_R: "armPoseDeformer_R"
|
|
3023
|
+
};
|
|
3024
|
+
var POSE_ANGLE_RANGE = [-15, 15];
|
|
3025
|
+
function forearmPoseGeometry(layer) {
|
|
3026
|
+
const { point, radius } = endPivot(layer, "bottom");
|
|
3027
|
+
const first = layer.rowRuns?.findIndex((runs) => runs.length > 0) ?? -1;
|
|
3028
|
+
const k = first < 0 ? 0 : first;
|
|
3029
|
+
return {
|
|
3030
|
+
pivot: point,
|
|
3031
|
+
radius,
|
|
3032
|
+
top: roundTo(layer.canvasH / 2 - (layer.bbox.y + k + 0.5), 0.01)
|
|
3033
|
+
};
|
|
3034
|
+
}
|
|
3035
|
+
function forearmPosePart(role, layer, order) {
|
|
3036
|
+
const b = boxOfLayer(layer);
|
|
3037
|
+
return {
|
|
3038
|
+
id: role,
|
|
3039
|
+
color: [1, 1, 1, 1],
|
|
3040
|
+
width: bw(b),
|
|
3041
|
+
height: bh(b),
|
|
3042
|
+
transform: { x: cx(b), y: cy(b) },
|
|
3043
|
+
order,
|
|
3044
|
+
deformer: POSE_IDS[role],
|
|
3045
|
+
bindings: [
|
|
3046
|
+
{ parameter: POSE_PARAMS[role].pose, channel: "opacity", from: 0, to: 1 }
|
|
3047
|
+
]
|
|
3048
|
+
};
|
|
3049
|
+
}
|
|
3050
|
+
function forearmPoseDeformer(role, arm) {
|
|
3051
|
+
return {
|
|
3052
|
+
id: POSE_IDS[role],
|
|
3053
|
+
parent: ARM_IDS[ARM_OF_POSE[role]].armDeformer,
|
|
3054
|
+
pivot: { ...arm.elbow },
|
|
3055
|
+
bindings: [
|
|
3056
|
+
rotateBinding(POSE_PARAMS[role].angle, POSE_ANGLE_RANGE, -arm.side)
|
|
3057
|
+
]
|
|
3058
|
+
};
|
|
3059
|
+
}
|
|
3060
|
+
|
|
2908
3061
|
// src/auto-rig/roles.ts
|
|
2909
3062
|
var ROLE_TABLE = [
|
|
2910
3063
|
{ role: "hair_back", family: "hair_back" },
|
|
2911
3064
|
{ role: "body", family: "body" },
|
|
2912
|
-
{ role: "arm_L", family: "arm", parts: ["arm_L", "forearm_L"] },
|
|
2913
|
-
{ role: "arm_R", family: "arm", parts: ["arm_R", "forearm_R"] },
|
|
3065
|
+
{ role: "arm_L", family: "arm", parts: ["elbow_L", "arm_L", "forearm_L"] },
|
|
3066
|
+
{ role: "arm_R", family: "arm", parts: ["elbow_R", "arm_R", "forearm_R"] },
|
|
2914
3067
|
{ role: "face", family: "face", required: true },
|
|
2915
3068
|
{ role: "blush_L", family: "face" },
|
|
2916
3069
|
{ role: "blush_R", family: "face" },
|
|
@@ -2931,7 +3084,10 @@ var ROLE_TABLE = [
|
|
|
2931
3084
|
{ role: "lash_R", family: "eye_R" },
|
|
2932
3085
|
{ role: "brow_L", family: "brow_L" },
|
|
2933
3086
|
{ role: "brow_R", family: "brow_R" },
|
|
2934
|
-
{ role: "hair_front", family: "hair_front" }
|
|
3087
|
+
{ role: "hair_front", family: "hair_front" },
|
|
3088
|
+
// Drawn above the face and the hair: a raised hand passes them.
|
|
3089
|
+
{ role: "forearm_pose_L", family: "forearm_pose" },
|
|
3090
|
+
{ role: "forearm_pose_R", family: "forearm_pose" }
|
|
2935
3091
|
];
|
|
2936
3092
|
var REQUIRED_ROLES = ROLE_TABLE.filter(
|
|
2937
3093
|
(r) => r.required
|
|
@@ -2971,6 +3127,16 @@ function checkArmsHaveBody(roles) {
|
|
|
2971
3127
|
);
|
|
2972
3128
|
}
|
|
2973
3129
|
}
|
|
3130
|
+
function checkPosesHaveArms(roles) {
|
|
3131
|
+
const has = new Set(roles);
|
|
3132
|
+
for (const side of ["L", "R"]) {
|
|
3133
|
+
if (has.has(`forearm_pose_${side}`) && !has.has(`arm_${side}`)) {
|
|
3134
|
+
throw new Error(
|
|
3135
|
+
`auto-rig: forearm_pose_${side} needs an arm_${side} layer (a pose forearm hangs from its arm's elbow)`
|
|
3136
|
+
);
|
|
3137
|
+
}
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
2974
3140
|
function parseLayerRoles(fileNames) {
|
|
2975
3141
|
const seen = /* @__PURE__ */ new Map();
|
|
2976
3142
|
const out = [];
|
|
@@ -2997,36 +3163,37 @@ function parseLayerRoles(fileNames) {
|
|
|
2997
3163
|
);
|
|
2998
3164
|
}
|
|
2999
3165
|
checkArmsHaveBody(seen.keys());
|
|
3166
|
+
checkPosesHaveArms(seen.keys());
|
|
3000
3167
|
return out;
|
|
3001
3168
|
}
|
|
3002
3169
|
|
|
3003
3170
|
// src/auto-rig/generate.ts
|
|
3004
|
-
var
|
|
3171
|
+
var import_format9 = require("@ikijs/format");
|
|
3005
3172
|
|
|
3006
3173
|
// src/auto-rig/animations.ts
|
|
3007
|
-
var
|
|
3174
|
+
var import_format7 = require("@ikijs/format");
|
|
3008
3175
|
function browsY(y) {
|
|
3009
3176
|
return [
|
|
3010
|
-
{ parameter:
|
|
3011
|
-
{ parameter:
|
|
3177
|
+
{ parameter: import_format7.StandardParameter.BrowLeftY, value: y, blend: "add" },
|
|
3178
|
+
{ parameter: import_format7.StandardParameter.BrowRightY, value: y, blend: "add" }
|
|
3012
3179
|
];
|
|
3013
3180
|
}
|
|
3014
3181
|
function browsTilt(innerDown) {
|
|
3015
3182
|
return [
|
|
3016
|
-
{ parameter:
|
|
3017
|
-
{ parameter:
|
|
3183
|
+
{ parameter: import_format7.StandardParameter.BrowLeftAngle, value: innerDown, blend: "add" },
|
|
3184
|
+
{ parameter: import_format7.StandardParameter.BrowRightAngle, value: -innerDown, blend: "add" }
|
|
3018
3185
|
];
|
|
3019
3186
|
}
|
|
3020
3187
|
function cheek(value) {
|
|
3021
|
-
return { parameter:
|
|
3188
|
+
return { parameter: import_format7.StandardParameter.Cheek, value, blend: "add" };
|
|
3022
3189
|
}
|
|
3023
|
-
var BROWS = [
|
|
3190
|
+
var BROWS = [import_format7.StandardParameter.BrowLeftY, import_format7.StandardParameter.BrowRightY, import_format7.StandardParameter.BrowLeftAngle, import_format7.StandardParameter.BrowRightAngle];
|
|
3024
3191
|
var EXPRESSIONS = [
|
|
3025
3192
|
{
|
|
3026
3193
|
id: "smile",
|
|
3027
3194
|
description: "Smiling and pleased: warm, friendly, content. For greetings, thanks, agreement and gentle happiness.",
|
|
3028
3195
|
parameters: [
|
|
3029
|
-
{ parameter:
|
|
3196
|
+
{ parameter: import_format7.StandardParameter.MouthForm, value: 1, blend: "add" },
|
|
3030
3197
|
...browsY(0.25),
|
|
3031
3198
|
cheek(0.4)
|
|
3032
3199
|
]
|
|
@@ -3035,10 +3202,10 @@ var EXPRESSIONS = [
|
|
|
3035
3202
|
id: "laugh",
|
|
3036
3203
|
description: "Laughing, eyes shut and mouth open: delighted, amused. For jokes, playfulness and big joy.",
|
|
3037
3204
|
parameters: [
|
|
3038
|
-
{ parameter:
|
|
3039
|
-
{ parameter:
|
|
3040
|
-
{ parameter:
|
|
3041
|
-
{ parameter:
|
|
3205
|
+
{ parameter: import_format7.StandardParameter.EyeOpenLeft, value: 0, blend: "multiply" },
|
|
3206
|
+
{ parameter: import_format7.StandardParameter.EyeOpenRight, value: 0, blend: "multiply" },
|
|
3207
|
+
{ parameter: import_format7.StandardParameter.MouthForm, value: 1, blend: "add" },
|
|
3208
|
+
{ parameter: import_format7.StandardParameter.MouthOpen, value: 0.8, blend: "overwrite" },
|
|
3042
3209
|
...browsY(0.4),
|
|
3043
3210
|
cheek(0.65)
|
|
3044
3211
|
]
|
|
@@ -3050,7 +3217,7 @@ var EXPRESSIONS = [
|
|
|
3050
3217
|
parameters: [
|
|
3051
3218
|
...browsY(-0.5),
|
|
3052
3219
|
...browsTilt(0.8),
|
|
3053
|
-
{ parameter:
|
|
3220
|
+
{ parameter: import_format7.StandardParameter.MouthForm, value: -0.9, blend: "add" }
|
|
3054
3221
|
]
|
|
3055
3222
|
},
|
|
3056
3223
|
{
|
|
@@ -3060,7 +3227,7 @@ var EXPRESSIONS = [
|
|
|
3060
3227
|
parameters: [
|
|
3061
3228
|
...browsY(0.35),
|
|
3062
3229
|
...browsTilt(-0.8),
|
|
3063
|
-
{ parameter:
|
|
3230
|
+
{ parameter: import_format7.StandardParameter.MouthForm, value: -0.8, blend: "add" }
|
|
3064
3231
|
]
|
|
3065
3232
|
},
|
|
3066
3233
|
{
|
|
@@ -3068,18 +3235,18 @@ var EXPRESSIONS = [
|
|
|
3068
3235
|
description: "Surprised, mouth dropped open: startled, amazed. For shock, sudden news or disbelief.",
|
|
3069
3236
|
parameters: [
|
|
3070
3237
|
...browsY(0.8),
|
|
3071
|
-
{ parameter:
|
|
3238
|
+
{ parameter: import_format7.StandardParameter.MouthOpen, value: 0.9, blend: "overwrite" }
|
|
3072
3239
|
]
|
|
3073
3240
|
},
|
|
3074
3241
|
{
|
|
3075
3242
|
id: "shy",
|
|
3076
3243
|
description: "Shy or embarrassed: bashful, flustered. For being praised, teased or caught off guard.",
|
|
3077
|
-
needs: [
|
|
3244
|
+
needs: [import_format7.StandardParameter.Cheek],
|
|
3078
3245
|
parameters: [
|
|
3079
3246
|
cheek(1),
|
|
3080
3247
|
// Gaze down.
|
|
3081
|
-
{ parameter:
|
|
3082
|
-
{ parameter:
|
|
3248
|
+
{ parameter: import_format7.StandardParameter.EyeballY, value: -0.65, blend: "add" },
|
|
3249
|
+
{ parameter: import_format7.StandardParameter.MouthForm, value: 0.4, blend: "add" },
|
|
3083
3250
|
...browsTilt(-0.25)
|
|
3084
3251
|
]
|
|
3085
3252
|
}
|
|
@@ -3092,14 +3259,14 @@ function defaultExpressions(declared) {
|
|
|
3092
3259
|
parameters: e.parameters.filter((t) => declared.has(t.parameter))
|
|
3093
3260
|
}));
|
|
3094
3261
|
}
|
|
3095
|
-
var
|
|
3262
|
+
var HEAD_MOTIONS = {
|
|
3096
3263
|
Nod: [
|
|
3097
3264
|
{
|
|
3098
3265
|
description: "Nods yes: agreement, acknowledgement, understanding.",
|
|
3099
3266
|
duration: 1,
|
|
3100
3267
|
curves: [
|
|
3101
3268
|
{
|
|
3102
|
-
parameter:
|
|
3269
|
+
parameter: import_format7.StandardParameter.AngleY,
|
|
3103
3270
|
keys: [
|
|
3104
3271
|
[0, 0],
|
|
3105
3272
|
[0.3, -18],
|
|
@@ -3120,7 +3287,7 @@ var DEFAULT_MOTIONS = {
|
|
|
3120
3287
|
fadeIn: 0.15,
|
|
3121
3288
|
curves: [
|
|
3122
3289
|
{
|
|
3123
|
-
parameter:
|
|
3290
|
+
parameter: import_format7.StandardParameter.AngleX,
|
|
3124
3291
|
keys: [
|
|
3125
3292
|
[0, 0],
|
|
3126
3293
|
[0.2, -18],
|
|
@@ -3139,7 +3306,7 @@ var DEFAULT_MOTIONS = {
|
|
|
3139
3306
|
duration: 1.4,
|
|
3140
3307
|
curves: [
|
|
3141
3308
|
{
|
|
3142
|
-
parameter:
|
|
3309
|
+
parameter: import_format7.StandardParameter.AngleZ,
|
|
3143
3310
|
keys: [
|
|
3144
3311
|
[0, 0],
|
|
3145
3312
|
[0.35, 20],
|
|
@@ -3151,6 +3318,55 @@ var DEFAULT_MOTIONS = {
|
|
|
3151
3318
|
}
|
|
3152
3319
|
]
|
|
3153
3320
|
};
|
|
3321
|
+
var WAVE = {
|
|
3322
|
+
Wave: [
|
|
3323
|
+
{
|
|
3324
|
+
description: "Waves hello with the right hand: greeting, goodbye, getting attention.",
|
|
3325
|
+
duration: 2.2,
|
|
3326
|
+
fadeIn: 0.15,
|
|
3327
|
+
fadeOut: 0.15,
|
|
3328
|
+
curves: [
|
|
3329
|
+
{
|
|
3330
|
+
parameter: import_format7.StandardParameter.ArmPoseRight,
|
|
3331
|
+
interpolation: "linear",
|
|
3332
|
+
keys: [
|
|
3333
|
+
[0, 0],
|
|
3334
|
+
[0.15, 1],
|
|
3335
|
+
[2.05, 1],
|
|
3336
|
+
[2.2, 0]
|
|
3337
|
+
]
|
|
3338
|
+
},
|
|
3339
|
+
{
|
|
3340
|
+
parameter: import_format7.StandardParameter.ArmRight,
|
|
3341
|
+
keys: [
|
|
3342
|
+
[0, 0],
|
|
3343
|
+
[0.4, 10],
|
|
3344
|
+
[1.8, 10],
|
|
3345
|
+
[2.2, 0]
|
|
3346
|
+
]
|
|
3347
|
+
},
|
|
3348
|
+
{
|
|
3349
|
+
parameter: import_format7.StandardParameter.ArmPoseAngleRight,
|
|
3350
|
+
keys: [
|
|
3351
|
+
[0, 0],
|
|
3352
|
+
[0.5, 0],
|
|
3353
|
+
[0.7, 12],
|
|
3354
|
+
[1, -12],
|
|
3355
|
+
[1.3, 12],
|
|
3356
|
+
[1.7, 0],
|
|
3357
|
+
[2.2, 0]
|
|
3358
|
+
]
|
|
3359
|
+
}
|
|
3360
|
+
]
|
|
3361
|
+
}
|
|
3362
|
+
]
|
|
3363
|
+
};
|
|
3364
|
+
function defaultMotions(declared) {
|
|
3365
|
+
const waves = [import_format7.StandardParameter.ArmRight, import_format7.StandardParameter.ArmPoseRight, import_format7.StandardParameter.ArmPoseAngleRight].every(
|
|
3366
|
+
(id) => declared.has(id)
|
|
3367
|
+
);
|
|
3368
|
+
return waves ? { ...HEAD_MOTIONS, ...WAVE } : HEAD_MOTIONS;
|
|
3369
|
+
}
|
|
3154
3370
|
|
|
3155
3371
|
// src/auto-rig/checks.ts
|
|
3156
3372
|
var finite = (v) => typeof v === "number" && Number.isFinite(v);
|
|
@@ -3256,6 +3472,7 @@ function checkLayers(layers, canvas) {
|
|
|
3256
3472
|
throw new Error(`auto-rig: missing required role(s) ${missing.join(", ")}`);
|
|
3257
3473
|
}
|
|
3258
3474
|
checkArmsHaveBody(seen);
|
|
3475
|
+
checkPosesHaveArms(seen);
|
|
3259
3476
|
}
|
|
3260
3477
|
function checkHeadEdges(edges, byRole) {
|
|
3261
3478
|
if (edges === void 0) return;
|
|
@@ -3373,7 +3590,7 @@ function checkStrandEdges(strand, irises, hair) {
|
|
|
3373
3590
|
}
|
|
3374
3591
|
|
|
3375
3592
|
// src/auto-rig/context.ts
|
|
3376
|
-
var
|
|
3593
|
+
var import_format8 = require("@ikijs/format");
|
|
3377
3594
|
|
|
3378
3595
|
// src/auto-rig/head.ts
|
|
3379
3596
|
function outerEdge(runs, axisX, side) {
|
|
@@ -4405,6 +4622,7 @@ function familyField(m, family) {
|
|
|
4405
4622
|
return hairField(m, m.hairBack, NOD.hairBack);
|
|
4406
4623
|
case "body":
|
|
4407
4624
|
case "arm":
|
|
4625
|
+
case "forearm_pose":
|
|
4408
4626
|
return () => [0, 0];
|
|
4409
4627
|
}
|
|
4410
4628
|
}
|
|
@@ -4504,7 +4722,7 @@ function renderedLander(turn, parts, grids, from = /* @__PURE__ */ new Map()) {
|
|
|
4504
4722
|
const family = roleSpec(role).family;
|
|
4505
4723
|
const part = parts.find((p) => p.id === role);
|
|
4506
4724
|
const g = grids.get(family);
|
|
4507
|
-
const warp = part?.warps?.find((w) => w.parameter ===
|
|
4725
|
+
const warp = part?.warps?.find((w) => w.parameter === import_format8.StandardParameter.AngleX);
|
|
4508
4726
|
if (part === void 0 || part.mesh === void 0 || !g && !warp) {
|
|
4509
4727
|
return x + field(role)(x, y, ax, 0)[0];
|
|
4510
4728
|
}
|
|
@@ -5240,6 +5458,7 @@ var WARP_ID = {
|
|
|
5240
5458
|
};
|
|
5241
5459
|
var isGridFamily = (f) => f in WARP_ID;
|
|
5242
5460
|
var isArm = (spec) => spec.family === "arm";
|
|
5461
|
+
var isPose = (spec) => spec.family === "forearm_pose";
|
|
5243
5462
|
var GRID_PAD = 6;
|
|
5244
5463
|
function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
5245
5464
|
checkLayers(layers, canvas);
|
|
@@ -5308,11 +5527,22 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
|
5308
5527
|
const layer = byRole.get(spec.role);
|
|
5309
5528
|
if (layer === void 0) continue;
|
|
5310
5529
|
if (isArm(spec)) {
|
|
5530
|
+
const pose = POSE_OF_ARM[spec.role];
|
|
5311
5531
|
parts.push(
|
|
5312
|
-
...armParts(
|
|
5532
|
+
...armParts(
|
|
5533
|
+
spec.role,
|
|
5534
|
+
layer,
|
|
5535
|
+
arms.get(spec.role),
|
|
5536
|
+
parts.length,
|
|
5537
|
+
has(pose) ? POSE_PARAMS[pose].pose : void 0
|
|
5538
|
+
)
|
|
5313
5539
|
);
|
|
5314
5540
|
continue;
|
|
5315
5541
|
}
|
|
5542
|
+
if (isPose(spec)) {
|
|
5543
|
+
parts.push(forearmPosePart(spec.role, layer, parts.length));
|
|
5544
|
+
continue;
|
|
5545
|
+
}
|
|
5316
5546
|
const built = buildPart(
|
|
5317
5547
|
spec,
|
|
5318
5548
|
boxOfLayer(layer),
|
|
@@ -5365,7 +5595,7 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
|
5365
5595
|
part.mesh = bodyWarp.mesh;
|
|
5366
5596
|
continue;
|
|
5367
5597
|
}
|
|
5368
|
-
if (family === "arm") continue;
|
|
5598
|
+
if (family === "arm" || family === "forearm_pose") continue;
|
|
5369
5599
|
part.deformer = "headDeformer";
|
|
5370
5600
|
if (part.mesh === void 0) continue;
|
|
5371
5601
|
const own = familyField(turn, family);
|
|
@@ -5377,17 +5607,17 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
|
5377
5607
|
}
|
|
5378
5608
|
const parameters = declareParameters(new Set(byRole.keys()));
|
|
5379
5609
|
const model = {
|
|
5380
|
-
version:
|
|
5610
|
+
version: import_format9.IKI_FORMAT_VERSION,
|
|
5381
5611
|
name: "auto-rigged",
|
|
5382
5612
|
canvas: { width: canvas.width, height: canvas.height },
|
|
5383
5613
|
parameters,
|
|
5384
5614
|
parts,
|
|
5385
|
-
deformers: deformers(frame, grids, bodyWarp?.deformer, arms),
|
|
5615
|
+
deformers: deformers(frame, grids, bodyWarp?.deformer, arms, byRole),
|
|
5386
5616
|
...has("hair_front") ? { physics: hairPhysics() } : {},
|
|
5387
5617
|
expressions: defaultExpressions(new Set(parameters.map((p) => p.id))),
|
|
5388
|
-
motions:
|
|
5618
|
+
motions: defaultMotions(new Set(parameters.map((p) => p.id)))
|
|
5389
5619
|
};
|
|
5390
|
-
const valid = (0,
|
|
5620
|
+
const valid = (0, import_format9.parseIkiModel)(model);
|
|
5391
5621
|
if (hasNose && options.onTurnSolved) {
|
|
5392
5622
|
options.onTurnSolved(
|
|
5393
5623
|
turnReport(
|
|
@@ -5402,14 +5632,14 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
|
5402
5632
|
function turnWarps(mesh, b, fieldOf) {
|
|
5403
5633
|
return [
|
|
5404
5634
|
localWarp(
|
|
5405
|
-
|
|
5635
|
+
import_format9.StandardParameter.AngleX,
|
|
5406
5636
|
mesh,
|
|
5407
5637
|
b,
|
|
5408
5638
|
X_STOPS,
|
|
5409
5639
|
([x, y], v, i) => v === 0 ? [0, 0] : [fieldOf(i)(x, y, v, 0)[0], 0]
|
|
5410
5640
|
),
|
|
5411
5641
|
localWarp(
|
|
5412
|
-
|
|
5642
|
+
import_format9.StandardParameter.AngleY,
|
|
5413
5643
|
mesh,
|
|
5414
5644
|
b,
|
|
5415
5645
|
Y_STOPS,
|
|
@@ -5457,7 +5687,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
5457
5687
|
}
|
|
5458
5688
|
if (mesh !== void 0) part.mesh = mesh;
|
|
5459
5689
|
const side = spec.role.endsWith("_L") ? "L" : "R";
|
|
5460
|
-
const eyeOpen = side === "L" ?
|
|
5690
|
+
const eyeOpen = side === "L" ? import_format9.StandardParameter.EyeOpenLeft : import_format9.StandardParameter.EyeOpenRight;
|
|
5461
5691
|
const hh = frame.hh;
|
|
5462
5692
|
switch (spec.role) {
|
|
5463
5693
|
case "face":
|
|
@@ -5472,7 +5702,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
5472
5702
|
headOwnRoll(byRole.has("body"))
|
|
5473
5703
|
),
|
|
5474
5704
|
localWarp(
|
|
5475
|
-
|
|
5705
|
+
import_format9.StandardParameter.Breath,
|
|
5476
5706
|
mesh,
|
|
5477
5707
|
b,
|
|
5478
5708
|
[0, 1],
|
|
@@ -5519,8 +5749,8 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
5519
5749
|
if (byRole.has("mouth_open")) {
|
|
5520
5750
|
warps.push(mouthWiden(mesh, b));
|
|
5521
5751
|
bindings.push(
|
|
5522
|
-
{ parameter:
|
|
5523
|
-
{ parameter:
|
|
5752
|
+
{ parameter: import_format9.StandardParameter.MouthOpen, channel: "opacity", from: 1, to: 0 },
|
|
5753
|
+
{ parameter: import_format9.StandardParameter.MouthOpen, channel: "opacity", from: 1, to: 0 }
|
|
5524
5754
|
);
|
|
5525
5755
|
extra = [(AMPLITUDE.mouthOpenWidth - 1) * (bw(b) / 2), 0];
|
|
5526
5756
|
} else {
|
|
@@ -5530,19 +5760,19 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
5530
5760
|
);
|
|
5531
5761
|
bindings.push(
|
|
5532
5762
|
{
|
|
5533
|
-
parameter:
|
|
5763
|
+
parameter: import_format9.StandardParameter.MouthOpen,
|
|
5534
5764
|
channel: "scaleY",
|
|
5535
5765
|
from: 0,
|
|
5536
5766
|
to: roundTo(grow, 0.01)
|
|
5537
5767
|
},
|
|
5538
5768
|
{
|
|
5539
|
-
parameter:
|
|
5769
|
+
parameter: import_format9.StandardParameter.MouthOpen,
|
|
5540
5770
|
channel: "scaleX",
|
|
5541
5771
|
from: 0,
|
|
5542
5772
|
to: roundTo(AMPLITUDE.mouthOpenWidth - 1, 0.01)
|
|
5543
5773
|
},
|
|
5544
5774
|
{
|
|
5545
|
-
parameter:
|
|
5775
|
+
parameter: import_format9.StandardParameter.MouthOpen,
|
|
5546
5776
|
channel: "translateY",
|
|
5547
5777
|
from: 0,
|
|
5548
5778
|
to: -roundTo(grow * bh(b) / 2, 0.01)
|
|
@@ -5554,7 +5784,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
5554
5784
|
case "mouth_open":
|
|
5555
5785
|
warps.push(mouthForm(mesh, b), mouthOpenGrow(mesh, b));
|
|
5556
5786
|
bindings.push({
|
|
5557
|
-
parameter:
|
|
5787
|
+
parameter: import_format9.StandardParameter.MouthOpen,
|
|
5558
5788
|
channel: "opacity",
|
|
5559
5789
|
from: 0,
|
|
5560
5790
|
to: 1
|
|
@@ -5564,7 +5794,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
5564
5794
|
case "blush_L":
|
|
5565
5795
|
case "blush_R":
|
|
5566
5796
|
bindings.push({
|
|
5567
|
-
parameter:
|
|
5797
|
+
parameter: import_format9.StandardParameter.Cheek,
|
|
5568
5798
|
channel: "opacity",
|
|
5569
5799
|
from: AMPLITUDE.blushRest,
|
|
5570
5800
|
to: 1
|
|
@@ -5575,8 +5805,8 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
5575
5805
|
if (byRole.has("hair_front")) {
|
|
5576
5806
|
const amp = style.sway * AMPLITUDE.sway * hh;
|
|
5577
5807
|
warps.push(
|
|
5578
|
-
hairSway(
|
|
5579
|
-
hairSway(
|
|
5808
|
+
hairSway(import_format9.StandardParameter.HairSwayX, mesh, b, amp),
|
|
5809
|
+
hairSway(import_format9.StandardParameter.HairSwayZ, mesh, b, amp)
|
|
5580
5810
|
);
|
|
5581
5811
|
}
|
|
5582
5812
|
warps.push(tiltHang(mesh, b, pivot, hairHangWeight(frame.chinY, b.y0)));
|
|
@@ -5649,10 +5879,14 @@ function meshScale(role, frame) {
|
|
|
5649
5879
|
return Infinity;
|
|
5650
5880
|
}
|
|
5651
5881
|
}
|
|
5652
|
-
function deformers(frame, grids, bodyWarp, arms) {
|
|
5882
|
+
function deformers(frame, grids, bodyWarp, arms, byRole) {
|
|
5653
5883
|
const out = [];
|
|
5654
5884
|
if (bodyWarp !== void 0) out.push(bodyWarp);
|
|
5655
5885
|
for (const [role, g] of arms) out.push(...armDeformers(role, g));
|
|
5886
|
+
for (const [role, arm] of arms) {
|
|
5887
|
+
const pose = POSE_OF_ARM[role];
|
|
5888
|
+
if (byRole.has(pose)) out.push(forearmPoseDeformer(pose, arm));
|
|
5889
|
+
}
|
|
5656
5890
|
const hasBody = bodyWarp !== void 0;
|
|
5657
5891
|
const roll = headOwnRoll(hasBody);
|
|
5658
5892
|
out.push({
|
|
@@ -5661,9 +5895,9 @@ function deformers(frame, grids, bodyWarp, arms) {
|
|
|
5661
5895
|
pivot: { x: roundTo(frame.axisX, 0.01), y: roundTo(frame.chinY, 0.01) },
|
|
5662
5896
|
bindings: [
|
|
5663
5897
|
// AngleZ is clockwise-positive (Live2D's); a rotation is CCW-positive.
|
|
5664
|
-
{ parameter:
|
|
5898
|
+
{ parameter: import_format9.StandardParameter.AngleZ, channel: "rotate", from: roll, to: -roll },
|
|
5665
5899
|
{
|
|
5666
|
-
parameter:
|
|
5900
|
+
parameter: import_format9.StandardParameter.Breath,
|
|
5667
5901
|
channel: "translateY",
|
|
5668
5902
|
from: 0,
|
|
5669
5903
|
to: roundTo(headOwnBreath(hasBody) * frame.hh, 0.01)
|
|
@@ -5681,8 +5915,8 @@ function deformers(frame, grids, bodyWarp, arms) {
|
|
|
5681
5915
|
points: g.lattice.points
|
|
5682
5916
|
},
|
|
5683
5917
|
warp2d: {
|
|
5684
|
-
parameter:
|
|
5685
|
-
parameterY:
|
|
5918
|
+
parameter: import_format9.StandardParameter.AngleX,
|
|
5919
|
+
parameterY: import_format9.StandardParameter.AngleY,
|
|
5686
5920
|
valuesX: X_STOPS,
|
|
5687
5921
|
valuesY: Y_STOPS,
|
|
5688
5922
|
keyforms2d: g.keyforms.map((offsets) => ({ offsets }))
|
|
@@ -5695,16 +5929,16 @@ function hairPhysics() {
|
|
|
5695
5929
|
return [
|
|
5696
5930
|
{
|
|
5697
5931
|
id: "hairSway",
|
|
5698
|
-
input: { parameter:
|
|
5699
|
-
output: { parameter:
|
|
5932
|
+
input: { parameter: import_format9.StandardParameter.AngleX, weight: 1 },
|
|
5933
|
+
output: { parameter: import_format9.StandardParameter.HairSwayX, scale: 5 },
|
|
5700
5934
|
mass: 1,
|
|
5701
5935
|
stiffness: 30,
|
|
5702
5936
|
damping: 3
|
|
5703
5937
|
},
|
|
5704
5938
|
{
|
|
5705
5939
|
id: "hairTilt",
|
|
5706
|
-
input: { parameter:
|
|
5707
|
-
output: { parameter:
|
|
5940
|
+
input: { parameter: import_format9.StandardParameter.AngleZ, weight: 1 },
|
|
5941
|
+
output: { parameter: import_format9.StandardParameter.HairSwayZ, scale: 8 },
|
|
5708
5942
|
mass: 1,
|
|
5709
5943
|
stiffness: 25,
|
|
5710
5944
|
damping: 2.5
|
|
@@ -5714,46 +5948,55 @@ function hairPhysics() {
|
|
|
5714
5948
|
function declareParameters(roles) {
|
|
5715
5949
|
const out = [];
|
|
5716
5950
|
const add = (id, name, min, max, def) => out.push({ id, name, min, max, default: def });
|
|
5717
|
-
add(
|
|
5718
|
-
add(
|
|
5719
|
-
add(
|
|
5951
|
+
add(import_format9.StandardParameter.AngleX, "Head Angle", -30, 30, 0);
|
|
5952
|
+
add(import_format9.StandardParameter.AngleY, "Head Angle Y", -30, 30, 0);
|
|
5953
|
+
add(import_format9.StandardParameter.AngleZ, "Head Angle Z", -30, 30, 0);
|
|
5720
5954
|
if (roles.has("body")) {
|
|
5721
|
-
add(
|
|
5722
|
-
add(
|
|
5723
|
-
add(
|
|
5955
|
+
add(import_format9.StandardParameter.BodyAngleX, "Body Angle X", -10, 10, 0);
|
|
5956
|
+
add(import_format9.StandardParameter.BodyAngleY, "Body Angle Y", -10, 10, 0);
|
|
5957
|
+
add(import_format9.StandardParameter.BodyAngleZ, "Body Angle Z", -10, 10, 0);
|
|
5724
5958
|
}
|
|
5959
|
+
const addPose = (side, pose, angle) => {
|
|
5960
|
+
add(pose, `Arm Pose ${side}`, 0, 1, 0);
|
|
5961
|
+
add(angle, `Arm Pose Angle ${side}`, ...POSE_ANGLE_RANGE, 0);
|
|
5962
|
+
};
|
|
5725
5963
|
const [armMin, armMax] = ARM_RANGE;
|
|
5964
|
+
const [elbowMin, elbowMax] = ELBOW_RANGE;
|
|
5726
5965
|
if (roles.has("arm_L")) {
|
|
5727
|
-
add(
|
|
5728
|
-
add(
|
|
5966
|
+
add(import_format9.StandardParameter.ArmLeft, "Arm L", armMin, armMax, 0);
|
|
5967
|
+
add(import_format9.StandardParameter.ElbowLeft, "Elbow L", elbowMin, elbowMax, 0);
|
|
5968
|
+
if (roles.has("forearm_pose_L"))
|
|
5969
|
+
addPose("L", import_format9.StandardParameter.ArmPoseLeft, import_format9.StandardParameter.ArmPoseAngleLeft);
|
|
5729
5970
|
}
|
|
5730
5971
|
if (roles.has("arm_R")) {
|
|
5731
|
-
add(
|
|
5732
|
-
add(
|
|
5972
|
+
add(import_format9.StandardParameter.ArmRight, "Arm R", armMin, armMax, 0);
|
|
5973
|
+
add(import_format9.StandardParameter.ElbowRight, "Elbow R", elbowMin, elbowMax, 0);
|
|
5974
|
+
if (roles.has("forearm_pose_R"))
|
|
5975
|
+
addPose("R", import_format9.StandardParameter.ArmPoseRight, import_format9.StandardParameter.ArmPoseAngleRight);
|
|
5733
5976
|
}
|
|
5734
|
-
add(
|
|
5735
|
-
add(
|
|
5977
|
+
add(import_format9.StandardParameter.EyeOpenLeft, "Eye L", 0, 1, 1);
|
|
5978
|
+
add(import_format9.StandardParameter.EyeOpenRight, "Eye R", 0, 1, 1);
|
|
5736
5979
|
if ([...roles].some((r) => /^(iris|pupil|highlight)_/.test(r))) {
|
|
5737
|
-
add(
|
|
5738
|
-
add(
|
|
5980
|
+
add(import_format9.StandardParameter.EyeballX, "Gaze X", -1, 1, 0);
|
|
5981
|
+
add(import_format9.StandardParameter.EyeballY, "Gaze Y", -1, 1, 0);
|
|
5739
5982
|
}
|
|
5740
|
-
add(
|
|
5741
|
-
add(
|
|
5983
|
+
add(import_format9.StandardParameter.MouthOpen, "Mouth Open", 0, 1, 0);
|
|
5984
|
+
add(import_format9.StandardParameter.MouthForm, "Mouth Form", -1, 1, 0);
|
|
5742
5985
|
if (roles.has("brow_L")) {
|
|
5743
|
-
add(
|
|
5744
|
-
add(
|
|
5986
|
+
add(import_format9.StandardParameter.BrowLeftY, "Brow L Y", -1, 1, 0);
|
|
5987
|
+
add(import_format9.StandardParameter.BrowLeftAngle, "Brow L Angle", -1, 1, 0);
|
|
5745
5988
|
}
|
|
5746
5989
|
if (roles.has("brow_R")) {
|
|
5747
|
-
add(
|
|
5748
|
-
add(
|
|
5990
|
+
add(import_format9.StandardParameter.BrowRightY, "Brow R Y", -1, 1, 0);
|
|
5991
|
+
add(import_format9.StandardParameter.BrowRightAngle, "Brow R Angle", -1, 1, 0);
|
|
5749
5992
|
}
|
|
5750
5993
|
if (roles.has("blush_L") || roles.has("blush_R")) {
|
|
5751
|
-
add(
|
|
5994
|
+
add(import_format9.StandardParameter.Cheek, "Cheek", 0, 1, 0);
|
|
5752
5995
|
}
|
|
5753
|
-
add(
|
|
5996
|
+
add(import_format9.StandardParameter.Breath, "Breath", 0, 1, 0);
|
|
5754
5997
|
if (roles.has("hair_front")) {
|
|
5755
|
-
add(
|
|
5756
|
-
add(
|
|
5998
|
+
add(import_format9.StandardParameter.HairSwayX, "Hair Sway X", -SWAY_RANGE, SWAY_RANGE, 0);
|
|
5999
|
+
add(import_format9.StandardParameter.HairSwayZ, "Hair Sway Z", -SWAY_RANGE, SWAY_RANGE, 0);
|
|
5757
6000
|
}
|
|
5758
6001
|
return out;
|
|
5759
6002
|
}
|
|
@@ -5801,6 +6044,7 @@ function declareParameters(roles) {
|
|
|
5801
6044
|
createLayerSetMeasurer,
|
|
5802
6045
|
denseCoreOf,
|
|
5803
6046
|
detectAlphaBbox,
|
|
6047
|
+
forearmPoseGeometry,
|
|
5804
6048
|
foregroundSpan,
|
|
5805
6049
|
generateIkiFromLayerSet,
|
|
5806
6050
|
headHalfOf,
|