@ikijs/editor 0.19.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 +17 -13
- package/dist/index.d.mts +63 -14
- package/dist/index.d.ts +63 -14
- package/dist/index.js +305 -119
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +304 -117
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1565,7 +1565,13 @@ var ROW_RUN_ROLES = /* @__PURE__ */ new Set([
|
|
|
1565
1565
|
"hair_back",
|
|
1566
1566
|
"body",
|
|
1567
1567
|
"arm_L",
|
|
1568
|
-
"arm_R"
|
|
1568
|
+
"arm_R",
|
|
1569
|
+
"forearm_pose_L",
|
|
1570
|
+
"forearm_pose_R"
|
|
1571
|
+
]);
|
|
1572
|
+
var REST_HIDDEN_ROLES = /* @__PURE__ */ new Set([
|
|
1573
|
+
"forearm_pose_L",
|
|
1574
|
+
"forearm_pose_R"
|
|
1569
1575
|
]);
|
|
1570
1576
|
function createLayerSetMeasurer(canvas) {
|
|
1571
1577
|
for (const field of ["width", "height"]) {
|
|
@@ -1596,6 +1602,7 @@ function createLayerSetMeasurer(canvas) {
|
|
|
1596
1602
|
if (bbox === null) return null;
|
|
1597
1603
|
const rowLeft = new Int32Array(canvasH).fill(canvasW);
|
|
1598
1604
|
const rowRight = new Int32Array(canvasH).fill(-1);
|
|
1605
|
+
const hidden = REST_HIDDEN_ROLES.has(role);
|
|
1599
1606
|
const rowRuns = ROW_RUN_ROLES.has(role) ? [] : void 0;
|
|
1600
1607
|
for (let y = 0; y < canvasH; y++) {
|
|
1601
1608
|
let runs;
|
|
@@ -1611,14 +1618,14 @@ function createLayerSetMeasurer(canvas) {
|
|
|
1611
1618
|
runs.push(x);
|
|
1612
1619
|
inRun = on;
|
|
1613
1620
|
}
|
|
1614
|
-
if (!on) continue;
|
|
1621
|
+
if (!on || hidden) continue;
|
|
1615
1622
|
opaque[p] = 1;
|
|
1616
1623
|
if (x < rowLeft[y]) rowLeft[y] = x;
|
|
1617
1624
|
if (x > rowRight[y]) rowRight[y] = x;
|
|
1618
1625
|
}
|
|
1619
1626
|
if (runs !== void 0 && inRun) runs.push(canvasW);
|
|
1620
1627
|
}
|
|
1621
|
-
rowSpansByRole.push({ role, rowLeft, rowRight });
|
|
1628
|
+
if (!hidden) rowSpansByRole.push({ role, rowLeft, rowRight });
|
|
1622
1629
|
const layer = {
|
|
1623
1630
|
role,
|
|
1624
1631
|
fileName,
|
|
@@ -2707,40 +2714,56 @@ var ARM_IDS = {
|
|
|
2707
2714
|
forearmDeformer: "forearmDeformer_R"
|
|
2708
2715
|
}
|
|
2709
2716
|
};
|
|
2710
|
-
function
|
|
2717
|
+
function endPivot(layer, end) {
|
|
2711
2718
|
const { bbox, canvasW, canvasH, rowRuns } = layer;
|
|
2712
|
-
const
|
|
2713
|
-
const
|
|
2719
|
+
const span = runSpan(layer);
|
|
2720
|
+
const from = (k) => end === "top" ? k : bbox.h - 1 - k;
|
|
2721
|
+
const painted = rowRuns?.flatMap((runs, k) => runs.length > 0 ? [k] : []) ?? [];
|
|
2722
|
+
const firstK = end === "top" ? painted[0] ?? 0 : painted.at(-1) ?? bbox.h - 1;
|
|
2723
|
+
const lo = Math.ceil(CAP_ROWS[0] * bbox.h);
|
|
2724
|
+
const hi = Math.max(lo, Math.floor(CAP_ROWS[1] * bbox.h));
|
|
2725
|
+
const widths = [];
|
|
2726
|
+
for (let k = lo; k <= hi; k++) {
|
|
2727
|
+
const [s2, e2] = span(from(k));
|
|
2728
|
+
widths.push(e2 - s2);
|
|
2729
|
+
}
|
|
2730
|
+
widths.sort((p, q) => p - q);
|
|
2731
|
+
const radius = widths[widths.length >> 1] / 2;
|
|
2732
|
+
const ks = end === "top" ? firstK + radius : firstK - radius;
|
|
2733
|
+
const [s, e] = span(Math.round(ks));
|
|
2734
|
+
return {
|
|
2735
|
+
point: {
|
|
2736
|
+
x: roundTo((s + e) / 2 - canvasW / 2, 0.01),
|
|
2737
|
+
y: roundTo(canvasH / 2 - (bbox.y + ks + 0.5), 0.01)
|
|
2738
|
+
},
|
|
2739
|
+
radius,
|
|
2740
|
+
row: ks
|
|
2741
|
+
};
|
|
2742
|
+
}
|
|
2743
|
+
function runSpan(layer) {
|
|
2744
|
+
const { bbox, rowRuns } = layer;
|
|
2745
|
+
return (k) => {
|
|
2714
2746
|
const runs = rowRuns?.[k] ?? [];
|
|
2715
2747
|
if (runs.length === 0) return [bbox.x, bbox.x + bbox.w];
|
|
2716
|
-
let [
|
|
2748
|
+
let [s, e] = [runs[0], runs[1]];
|
|
2717
2749
|
for (let i = 2; i < runs.length; i += 2) {
|
|
2718
|
-
if (runs[i + 1] - runs[i] >
|
|
2750
|
+
if (runs[i + 1] - runs[i] > e - s) [s, e] = [runs[i], runs[i + 1]];
|
|
2719
2751
|
}
|
|
2720
|
-
return [
|
|
2752
|
+
return [s, e];
|
|
2721
2753
|
};
|
|
2754
|
+
}
|
|
2755
|
+
function armGeometry(layer, bodyAxisX) {
|
|
2756
|
+
const { bbox, canvasW, canvasH, rowRuns } = layer;
|
|
2757
|
+
const b = boxOfLayer(layer);
|
|
2758
|
+
const span = runSpan(layer);
|
|
2722
2759
|
const centreX = (k) => {
|
|
2723
2760
|
const [s2, e2] = span(k);
|
|
2724
2761
|
return (s2 + e2) / 2 - canvasW / 2;
|
|
2725
2762
|
};
|
|
2726
2763
|
const rowY = (k) => canvasH / 2 - (bbox.y + k + 0.5);
|
|
2727
2764
|
const painted = rowRuns?.flatMap((runs, k) => runs.length > 0 ? [k] : []) ?? [];
|
|
2728
|
-
const first = painted[0] ?? 0;
|
|
2729
2765
|
const last = painted.at(-1) ?? bbox.h - 1;
|
|
2730
|
-
const
|
|
2731
|
-
const hi = Math.max(lo, Math.floor(CAP_ROWS[1] * bbox.h));
|
|
2732
|
-
const widths = [];
|
|
2733
|
-
for (let k = lo; k <= hi; k++) {
|
|
2734
|
-
const [s2, e2] = span(k);
|
|
2735
|
-
widths.push(e2 - s2);
|
|
2736
|
-
}
|
|
2737
|
-
widths.sort((p, q) => p - q);
|
|
2738
|
-
const ru = widths[widths.length >> 1] / 2;
|
|
2739
|
-
const ks = first + ru;
|
|
2740
|
-
const shoulder = {
|
|
2741
|
-
x: roundTo(centreX(Math.round(ks)), 0.01),
|
|
2742
|
-
y: roundTo(rowY(ks), 0.01)
|
|
2743
|
-
};
|
|
2766
|
+
const { point: shoulder, radius: ru, row: ks } = endPivot(layer, "top");
|
|
2744
2767
|
const ke = Math.round(ks + ELBOW_AT * (last - ks));
|
|
2745
2768
|
if (ke <= ks) {
|
|
2746
2769
|
throw new LayerGeometryError(
|
|
@@ -2788,7 +2811,7 @@ function meshOf(vertices, indices) {
|
|
|
2788
2811
|
);
|
|
2789
2812
|
return { vertices, uvs, indices };
|
|
2790
2813
|
}
|
|
2791
|
-
function armParts(role, layer, g, order) {
|
|
2814
|
+
function armParts(role, layer, g, order, poseSwitch) {
|
|
2792
2815
|
const b = boxOfLayer(layer);
|
|
2793
2816
|
const lx = (x) => roundTo((x - cx(b)) / bw(b), 1e-5);
|
|
2794
2817
|
const ly = (y) => roundTo((y - cy(b)) / bh(b), 1e-5);
|
|
@@ -2841,7 +2864,7 @@ function armParts(role, layer, g, order) {
|
|
|
2841
2864
|
const [p, q] = [ringInner + j, ringOuter + j];
|
|
2842
2865
|
ring.push(p, q, q + 1, p, q + 1, p + 1);
|
|
2843
2866
|
}
|
|
2844
|
-
const part = (id, deformer, z, mesh) => ({
|
|
2867
|
+
const part = (id, deformer, z, mesh, swaps = false) => ({
|
|
2845
2868
|
id,
|
|
2846
2869
|
color: [1, 1, 1, 1],
|
|
2847
2870
|
width: bw(b),
|
|
@@ -2849,49 +2872,123 @@ function armParts(role, layer, g, order) {
|
|
|
2849
2872
|
transform: { x: cx(b), y: cy(b) },
|
|
2850
2873
|
order: z,
|
|
2851
2874
|
deformer,
|
|
2852
|
-
mesh
|
|
2875
|
+
mesh,
|
|
2876
|
+
...swaps && poseSwitch !== void 0 ? {
|
|
2877
|
+
bindings: [
|
|
2878
|
+
{
|
|
2879
|
+
parameter: poseSwitch,
|
|
2880
|
+
channel: "opacity",
|
|
2881
|
+
from: 1,
|
|
2882
|
+
to: 0
|
|
2883
|
+
}
|
|
2884
|
+
]
|
|
2885
|
+
} : {}
|
|
2853
2886
|
});
|
|
2854
2887
|
const ids = ARM_IDS[role];
|
|
2855
2888
|
return [
|
|
2856
|
-
part(
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2889
|
+
part(
|
|
2890
|
+
ids.cap,
|
|
2891
|
+
ids.forearmDeformer,
|
|
2892
|
+
order,
|
|
2893
|
+
{
|
|
2894
|
+
vertices,
|
|
2895
|
+
uvs,
|
|
2896
|
+
indices: [...fan, ...ring]
|
|
2897
|
+
},
|
|
2898
|
+
true
|
|
2899
|
+
),
|
|
2861
2900
|
part(role, ids.armDeformer, order + 1, meshOf(band(0.5, seam), quad)),
|
|
2862
2901
|
part(
|
|
2863
2902
|
ids.forearm,
|
|
2864
2903
|
ids.forearmDeformer,
|
|
2865
2904
|
order + 2,
|
|
2866
|
-
meshOf(band(seam, -0.5), quad)
|
|
2905
|
+
meshOf(band(seam, -0.5), quad),
|
|
2906
|
+
true
|
|
2867
2907
|
)
|
|
2868
2908
|
];
|
|
2869
2909
|
}
|
|
2910
|
+
var rotateBinding = (parameter, range, sign) => ({
|
|
2911
|
+
parameter,
|
|
2912
|
+
channel: "rotate",
|
|
2913
|
+
from: sign * range[0],
|
|
2914
|
+
to: sign * range[1]
|
|
2915
|
+
});
|
|
2870
2916
|
function armDeformers(role, g) {
|
|
2871
2917
|
const ids = ARM_IDS[role];
|
|
2872
2918
|
const params = ARM_PARAMS[role];
|
|
2873
|
-
const rotate = (parameter, range, sign) => ({
|
|
2874
|
-
parameter,
|
|
2875
|
-
channel: "rotate",
|
|
2876
|
-
from: sign * range[0],
|
|
2877
|
-
to: sign * range[1]
|
|
2878
|
-
});
|
|
2879
2919
|
return [
|
|
2880
2920
|
{
|
|
2881
2921
|
id: ids.armDeformer,
|
|
2882
2922
|
parent: BODY_WARP_ID,
|
|
2883
2923
|
pivot: { ...g.shoulder },
|
|
2884
|
-
bindings: [
|
|
2924
|
+
bindings: [rotateBinding(params.arm, ARM_RANGE, g.side)]
|
|
2885
2925
|
},
|
|
2886
2926
|
{
|
|
2887
2927
|
id: ids.forearmDeformer,
|
|
2888
2928
|
parent: ids.armDeformer,
|
|
2889
2929
|
pivot: { ...g.elbow },
|
|
2890
|
-
bindings: [
|
|
2930
|
+
bindings: [rotateBinding(params.elbow, ELBOW_RANGE, -g.side)]
|
|
2891
2931
|
}
|
|
2892
2932
|
];
|
|
2893
2933
|
}
|
|
2894
2934
|
|
|
2935
|
+
// src/auto-rig/forearm-pose.ts
|
|
2936
|
+
import {
|
|
2937
|
+
StandardParameter as P4
|
|
2938
|
+
} from "@ikijs/format";
|
|
2939
|
+
var ARM_OF_POSE = {
|
|
2940
|
+
forearm_pose_L: "arm_L",
|
|
2941
|
+
forearm_pose_R: "arm_R"
|
|
2942
|
+
};
|
|
2943
|
+
var POSE_OF_ARM = {
|
|
2944
|
+
arm_L: "forearm_pose_L",
|
|
2945
|
+
arm_R: "forearm_pose_R"
|
|
2946
|
+
};
|
|
2947
|
+
var POSE_PARAMS = {
|
|
2948
|
+
forearm_pose_L: { pose: P4.ArmPoseLeft, angle: P4.ArmPoseAngleLeft },
|
|
2949
|
+
forearm_pose_R: { pose: P4.ArmPoseRight, angle: P4.ArmPoseAngleRight }
|
|
2950
|
+
};
|
|
2951
|
+
var POSE_IDS = {
|
|
2952
|
+
forearm_pose_L: "armPoseDeformer_L",
|
|
2953
|
+
forearm_pose_R: "armPoseDeformer_R"
|
|
2954
|
+
};
|
|
2955
|
+
var POSE_ANGLE_RANGE = [-15, 15];
|
|
2956
|
+
function forearmPoseGeometry(layer) {
|
|
2957
|
+
const { point, radius } = endPivot(layer, "bottom");
|
|
2958
|
+
const first = layer.rowRuns?.findIndex((runs) => runs.length > 0) ?? -1;
|
|
2959
|
+
const k = first < 0 ? 0 : first;
|
|
2960
|
+
return {
|
|
2961
|
+
pivot: point,
|
|
2962
|
+
radius,
|
|
2963
|
+
top: roundTo(layer.canvasH / 2 - (layer.bbox.y + k + 0.5), 0.01)
|
|
2964
|
+
};
|
|
2965
|
+
}
|
|
2966
|
+
function forearmPosePart(role, layer, order) {
|
|
2967
|
+
const b = boxOfLayer(layer);
|
|
2968
|
+
return {
|
|
2969
|
+
id: role,
|
|
2970
|
+
color: [1, 1, 1, 1],
|
|
2971
|
+
width: bw(b),
|
|
2972
|
+
height: bh(b),
|
|
2973
|
+
transform: { x: cx(b), y: cy(b) },
|
|
2974
|
+
order,
|
|
2975
|
+
deformer: POSE_IDS[role],
|
|
2976
|
+
bindings: [
|
|
2977
|
+
{ parameter: POSE_PARAMS[role].pose, channel: "opacity", from: 0, to: 1 }
|
|
2978
|
+
]
|
|
2979
|
+
};
|
|
2980
|
+
}
|
|
2981
|
+
function forearmPoseDeformer(role, arm) {
|
|
2982
|
+
return {
|
|
2983
|
+
id: POSE_IDS[role],
|
|
2984
|
+
parent: ARM_IDS[ARM_OF_POSE[role]].armDeformer,
|
|
2985
|
+
pivot: { ...arm.elbow },
|
|
2986
|
+
bindings: [
|
|
2987
|
+
rotateBinding(POSE_PARAMS[role].angle, POSE_ANGLE_RANGE, -arm.side)
|
|
2988
|
+
]
|
|
2989
|
+
};
|
|
2990
|
+
}
|
|
2991
|
+
|
|
2895
2992
|
// src/auto-rig/roles.ts
|
|
2896
2993
|
var ROLE_TABLE = [
|
|
2897
2994
|
{ role: "hair_back", family: "hair_back" },
|
|
@@ -2918,7 +3015,10 @@ var ROLE_TABLE = [
|
|
|
2918
3015
|
{ role: "lash_R", family: "eye_R" },
|
|
2919
3016
|
{ role: "brow_L", family: "brow_L" },
|
|
2920
3017
|
{ role: "brow_R", family: "brow_R" },
|
|
2921
|
-
{ role: "hair_front", family: "hair_front" }
|
|
3018
|
+
{ role: "hair_front", family: "hair_front" },
|
|
3019
|
+
// Drawn above the face and the hair: a raised hand passes them.
|
|
3020
|
+
{ role: "forearm_pose_L", family: "forearm_pose" },
|
|
3021
|
+
{ role: "forearm_pose_R", family: "forearm_pose" }
|
|
2922
3022
|
];
|
|
2923
3023
|
var REQUIRED_ROLES = ROLE_TABLE.filter(
|
|
2924
3024
|
(r) => r.required
|
|
@@ -2958,6 +3058,16 @@ function checkArmsHaveBody(roles) {
|
|
|
2958
3058
|
);
|
|
2959
3059
|
}
|
|
2960
3060
|
}
|
|
3061
|
+
function checkPosesHaveArms(roles) {
|
|
3062
|
+
const has = new Set(roles);
|
|
3063
|
+
for (const side of ["L", "R"]) {
|
|
3064
|
+
if (has.has(`forearm_pose_${side}`) && !has.has(`arm_${side}`)) {
|
|
3065
|
+
throw new Error(
|
|
3066
|
+
`auto-rig: forearm_pose_${side} needs an arm_${side} layer (a pose forearm hangs from its arm's elbow)`
|
|
3067
|
+
);
|
|
3068
|
+
}
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
2961
3071
|
function parseLayerRoles(fileNames) {
|
|
2962
3072
|
const seen = /* @__PURE__ */ new Map();
|
|
2963
3073
|
const out = [];
|
|
@@ -2984,42 +3094,43 @@ function parseLayerRoles(fileNames) {
|
|
|
2984
3094
|
);
|
|
2985
3095
|
}
|
|
2986
3096
|
checkArmsHaveBody(seen.keys());
|
|
3097
|
+
checkPosesHaveArms(seen.keys());
|
|
2987
3098
|
return out;
|
|
2988
3099
|
}
|
|
2989
3100
|
|
|
2990
3101
|
// src/auto-rig/generate.ts
|
|
2991
3102
|
import {
|
|
2992
3103
|
IKI_FORMAT_VERSION as IKI_FORMAT_VERSION2,
|
|
2993
|
-
StandardParameter as
|
|
3104
|
+
StandardParameter as P7,
|
|
2994
3105
|
parseIkiModel as parseIkiModel3
|
|
2995
3106
|
} from "@ikijs/format";
|
|
2996
3107
|
|
|
2997
3108
|
// src/auto-rig/animations.ts
|
|
2998
3109
|
import {
|
|
2999
|
-
StandardParameter as
|
|
3110
|
+
StandardParameter as P5
|
|
3000
3111
|
} from "@ikijs/format";
|
|
3001
3112
|
function browsY(y) {
|
|
3002
3113
|
return [
|
|
3003
|
-
{ parameter:
|
|
3004
|
-
{ parameter:
|
|
3114
|
+
{ parameter: P5.BrowLeftY, value: y, blend: "add" },
|
|
3115
|
+
{ parameter: P5.BrowRightY, value: y, blend: "add" }
|
|
3005
3116
|
];
|
|
3006
3117
|
}
|
|
3007
3118
|
function browsTilt(innerDown) {
|
|
3008
3119
|
return [
|
|
3009
|
-
{ parameter:
|
|
3010
|
-
{ parameter:
|
|
3120
|
+
{ parameter: P5.BrowLeftAngle, value: innerDown, blend: "add" },
|
|
3121
|
+
{ parameter: P5.BrowRightAngle, value: -innerDown, blend: "add" }
|
|
3011
3122
|
];
|
|
3012
3123
|
}
|
|
3013
3124
|
function cheek(value) {
|
|
3014
|
-
return { parameter:
|
|
3125
|
+
return { parameter: P5.Cheek, value, blend: "add" };
|
|
3015
3126
|
}
|
|
3016
|
-
var BROWS = [
|
|
3127
|
+
var BROWS = [P5.BrowLeftY, P5.BrowRightY, P5.BrowLeftAngle, P5.BrowRightAngle];
|
|
3017
3128
|
var EXPRESSIONS = [
|
|
3018
3129
|
{
|
|
3019
3130
|
id: "smile",
|
|
3020
3131
|
description: "Smiling and pleased: warm, friendly, content. For greetings, thanks, agreement and gentle happiness.",
|
|
3021
3132
|
parameters: [
|
|
3022
|
-
{ parameter:
|
|
3133
|
+
{ parameter: P5.MouthForm, value: 1, blend: "add" },
|
|
3023
3134
|
...browsY(0.25),
|
|
3024
3135
|
cheek(0.4)
|
|
3025
3136
|
]
|
|
@@ -3028,10 +3139,10 @@ var EXPRESSIONS = [
|
|
|
3028
3139
|
id: "laugh",
|
|
3029
3140
|
description: "Laughing, eyes shut and mouth open: delighted, amused. For jokes, playfulness and big joy.",
|
|
3030
3141
|
parameters: [
|
|
3031
|
-
{ parameter:
|
|
3032
|
-
{ parameter:
|
|
3033
|
-
{ parameter:
|
|
3034
|
-
{ parameter:
|
|
3142
|
+
{ parameter: P5.EyeOpenLeft, value: 0, blend: "multiply" },
|
|
3143
|
+
{ parameter: P5.EyeOpenRight, value: 0, blend: "multiply" },
|
|
3144
|
+
{ parameter: P5.MouthForm, value: 1, blend: "add" },
|
|
3145
|
+
{ parameter: P5.MouthOpen, value: 0.8, blend: "overwrite" },
|
|
3035
3146
|
...browsY(0.4),
|
|
3036
3147
|
cheek(0.65)
|
|
3037
3148
|
]
|
|
@@ -3043,7 +3154,7 @@ var EXPRESSIONS = [
|
|
|
3043
3154
|
parameters: [
|
|
3044
3155
|
...browsY(-0.5),
|
|
3045
3156
|
...browsTilt(0.8),
|
|
3046
|
-
{ parameter:
|
|
3157
|
+
{ parameter: P5.MouthForm, value: -0.9, blend: "add" }
|
|
3047
3158
|
]
|
|
3048
3159
|
},
|
|
3049
3160
|
{
|
|
@@ -3053,7 +3164,7 @@ var EXPRESSIONS = [
|
|
|
3053
3164
|
parameters: [
|
|
3054
3165
|
...browsY(0.35),
|
|
3055
3166
|
...browsTilt(-0.8),
|
|
3056
|
-
{ parameter:
|
|
3167
|
+
{ parameter: P5.MouthForm, value: -0.8, blend: "add" }
|
|
3057
3168
|
]
|
|
3058
3169
|
},
|
|
3059
3170
|
{
|
|
@@ -3061,18 +3172,18 @@ var EXPRESSIONS = [
|
|
|
3061
3172
|
description: "Surprised, mouth dropped open: startled, amazed. For shock, sudden news or disbelief.",
|
|
3062
3173
|
parameters: [
|
|
3063
3174
|
...browsY(0.8),
|
|
3064
|
-
{ parameter:
|
|
3175
|
+
{ parameter: P5.MouthOpen, value: 0.9, blend: "overwrite" }
|
|
3065
3176
|
]
|
|
3066
3177
|
},
|
|
3067
3178
|
{
|
|
3068
3179
|
id: "shy",
|
|
3069
3180
|
description: "Shy or embarrassed: bashful, flustered. For being praised, teased or caught off guard.",
|
|
3070
|
-
needs: [
|
|
3181
|
+
needs: [P5.Cheek],
|
|
3071
3182
|
parameters: [
|
|
3072
3183
|
cheek(1),
|
|
3073
3184
|
// Gaze down.
|
|
3074
|
-
{ parameter:
|
|
3075
|
-
{ parameter:
|
|
3185
|
+
{ parameter: P5.EyeballY, value: -0.65, blend: "add" },
|
|
3186
|
+
{ parameter: P5.MouthForm, value: 0.4, blend: "add" },
|
|
3076
3187
|
...browsTilt(-0.25)
|
|
3077
3188
|
]
|
|
3078
3189
|
}
|
|
@@ -3085,14 +3196,14 @@ function defaultExpressions(declared) {
|
|
|
3085
3196
|
parameters: e.parameters.filter((t) => declared.has(t.parameter))
|
|
3086
3197
|
}));
|
|
3087
3198
|
}
|
|
3088
|
-
var
|
|
3199
|
+
var HEAD_MOTIONS = {
|
|
3089
3200
|
Nod: [
|
|
3090
3201
|
{
|
|
3091
3202
|
description: "Nods yes: agreement, acknowledgement, understanding.",
|
|
3092
3203
|
duration: 1,
|
|
3093
3204
|
curves: [
|
|
3094
3205
|
{
|
|
3095
|
-
parameter:
|
|
3206
|
+
parameter: P5.AngleY,
|
|
3096
3207
|
keys: [
|
|
3097
3208
|
[0, 0],
|
|
3098
3209
|
[0.3, -18],
|
|
@@ -3113,7 +3224,7 @@ var DEFAULT_MOTIONS = {
|
|
|
3113
3224
|
fadeIn: 0.15,
|
|
3114
3225
|
curves: [
|
|
3115
3226
|
{
|
|
3116
|
-
parameter:
|
|
3227
|
+
parameter: P5.AngleX,
|
|
3117
3228
|
keys: [
|
|
3118
3229
|
[0, 0],
|
|
3119
3230
|
[0.2, -18],
|
|
@@ -3132,7 +3243,7 @@ var DEFAULT_MOTIONS = {
|
|
|
3132
3243
|
duration: 1.4,
|
|
3133
3244
|
curves: [
|
|
3134
3245
|
{
|
|
3135
|
-
parameter:
|
|
3246
|
+
parameter: P5.AngleZ,
|
|
3136
3247
|
keys: [
|
|
3137
3248
|
[0, 0],
|
|
3138
3249
|
[0.35, 20],
|
|
@@ -3144,6 +3255,55 @@ var DEFAULT_MOTIONS = {
|
|
|
3144
3255
|
}
|
|
3145
3256
|
]
|
|
3146
3257
|
};
|
|
3258
|
+
var WAVE = {
|
|
3259
|
+
Wave: [
|
|
3260
|
+
{
|
|
3261
|
+
description: "Waves hello with the right hand: greeting, goodbye, getting attention.",
|
|
3262
|
+
duration: 2.2,
|
|
3263
|
+
fadeIn: 0.15,
|
|
3264
|
+
fadeOut: 0.15,
|
|
3265
|
+
curves: [
|
|
3266
|
+
{
|
|
3267
|
+
parameter: P5.ArmPoseRight,
|
|
3268
|
+
interpolation: "linear",
|
|
3269
|
+
keys: [
|
|
3270
|
+
[0, 0],
|
|
3271
|
+
[0.15, 1],
|
|
3272
|
+
[2.05, 1],
|
|
3273
|
+
[2.2, 0]
|
|
3274
|
+
]
|
|
3275
|
+
},
|
|
3276
|
+
{
|
|
3277
|
+
parameter: P5.ArmRight,
|
|
3278
|
+
keys: [
|
|
3279
|
+
[0, 0],
|
|
3280
|
+
[0.4, 10],
|
|
3281
|
+
[1.8, 10],
|
|
3282
|
+
[2.2, 0]
|
|
3283
|
+
]
|
|
3284
|
+
},
|
|
3285
|
+
{
|
|
3286
|
+
parameter: P5.ArmPoseAngleRight,
|
|
3287
|
+
keys: [
|
|
3288
|
+
[0, 0],
|
|
3289
|
+
[0.5, 0],
|
|
3290
|
+
[0.7, 12],
|
|
3291
|
+
[1, -12],
|
|
3292
|
+
[1.3, 12],
|
|
3293
|
+
[1.7, 0],
|
|
3294
|
+
[2.2, 0]
|
|
3295
|
+
]
|
|
3296
|
+
}
|
|
3297
|
+
]
|
|
3298
|
+
}
|
|
3299
|
+
]
|
|
3300
|
+
};
|
|
3301
|
+
function defaultMotions(declared) {
|
|
3302
|
+
const waves = [P5.ArmRight, P5.ArmPoseRight, P5.ArmPoseAngleRight].every(
|
|
3303
|
+
(id) => declared.has(id)
|
|
3304
|
+
);
|
|
3305
|
+
return waves ? { ...HEAD_MOTIONS, ...WAVE } : HEAD_MOTIONS;
|
|
3306
|
+
}
|
|
3147
3307
|
|
|
3148
3308
|
// src/auto-rig/checks.ts
|
|
3149
3309
|
var finite = (v) => typeof v === "number" && Number.isFinite(v);
|
|
@@ -3249,6 +3409,7 @@ function checkLayers(layers, canvas) {
|
|
|
3249
3409
|
throw new Error(`auto-rig: missing required role(s) ${missing.join(", ")}`);
|
|
3250
3410
|
}
|
|
3251
3411
|
checkArmsHaveBody(seen);
|
|
3412
|
+
checkPosesHaveArms(seen);
|
|
3252
3413
|
}
|
|
3253
3414
|
function checkHeadEdges(edges, byRole) {
|
|
3254
3415
|
if (edges === void 0) return;
|
|
@@ -3366,7 +3527,7 @@ function checkStrandEdges(strand, irises, hair) {
|
|
|
3366
3527
|
}
|
|
3367
3528
|
|
|
3368
3529
|
// src/auto-rig/context.ts
|
|
3369
|
-
import { StandardParameter as
|
|
3530
|
+
import { StandardParameter as P6 } from "@ikijs/format";
|
|
3370
3531
|
|
|
3371
3532
|
// src/auto-rig/head.ts
|
|
3372
3533
|
function outerEdge(runs, axisX, side) {
|
|
@@ -4398,6 +4559,7 @@ function familyField(m, family) {
|
|
|
4398
4559
|
return hairField(m, m.hairBack, NOD.hairBack);
|
|
4399
4560
|
case "body":
|
|
4400
4561
|
case "arm":
|
|
4562
|
+
case "forearm_pose":
|
|
4401
4563
|
return () => [0, 0];
|
|
4402
4564
|
}
|
|
4403
4565
|
}
|
|
@@ -4497,7 +4659,7 @@ function renderedLander(turn, parts, grids, from = /* @__PURE__ */ new Map()) {
|
|
|
4497
4659
|
const family = roleSpec(role).family;
|
|
4498
4660
|
const part = parts.find((p) => p.id === role);
|
|
4499
4661
|
const g = grids.get(family);
|
|
4500
|
-
const warp = part?.warps?.find((w) => w.parameter ===
|
|
4662
|
+
const warp = part?.warps?.find((w) => w.parameter === P6.AngleX);
|
|
4501
4663
|
if (part === void 0 || part.mesh === void 0 || !g && !warp) {
|
|
4502
4664
|
return x + field(role)(x, y, ax, 0)[0];
|
|
4503
4665
|
}
|
|
@@ -5233,6 +5395,7 @@ var WARP_ID = {
|
|
|
5233
5395
|
};
|
|
5234
5396
|
var isGridFamily = (f) => f in WARP_ID;
|
|
5235
5397
|
var isArm = (spec) => spec.family === "arm";
|
|
5398
|
+
var isPose = (spec) => spec.family === "forearm_pose";
|
|
5236
5399
|
var GRID_PAD = 6;
|
|
5237
5400
|
function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
5238
5401
|
checkLayers(layers, canvas);
|
|
@@ -5301,11 +5464,22 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
|
5301
5464
|
const layer = byRole.get(spec.role);
|
|
5302
5465
|
if (layer === void 0) continue;
|
|
5303
5466
|
if (isArm(spec)) {
|
|
5467
|
+
const pose = POSE_OF_ARM[spec.role];
|
|
5304
5468
|
parts.push(
|
|
5305
|
-
...armParts(
|
|
5469
|
+
...armParts(
|
|
5470
|
+
spec.role,
|
|
5471
|
+
layer,
|
|
5472
|
+
arms.get(spec.role),
|
|
5473
|
+
parts.length,
|
|
5474
|
+
has(pose) ? POSE_PARAMS[pose].pose : void 0
|
|
5475
|
+
)
|
|
5306
5476
|
);
|
|
5307
5477
|
continue;
|
|
5308
5478
|
}
|
|
5479
|
+
if (isPose(spec)) {
|
|
5480
|
+
parts.push(forearmPosePart(spec.role, layer, parts.length));
|
|
5481
|
+
continue;
|
|
5482
|
+
}
|
|
5309
5483
|
const built = buildPart(
|
|
5310
5484
|
spec,
|
|
5311
5485
|
boxOfLayer(layer),
|
|
@@ -5358,7 +5532,7 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
|
5358
5532
|
part.mesh = bodyWarp.mesh;
|
|
5359
5533
|
continue;
|
|
5360
5534
|
}
|
|
5361
|
-
if (family === "arm") continue;
|
|
5535
|
+
if (family === "arm" || family === "forearm_pose") continue;
|
|
5362
5536
|
part.deformer = "headDeformer";
|
|
5363
5537
|
if (part.mesh === void 0) continue;
|
|
5364
5538
|
const own = familyField(turn, family);
|
|
@@ -5375,10 +5549,10 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
|
5375
5549
|
canvas: { width: canvas.width, height: canvas.height },
|
|
5376
5550
|
parameters,
|
|
5377
5551
|
parts,
|
|
5378
|
-
deformers: deformers(frame, grids, bodyWarp?.deformer, arms),
|
|
5552
|
+
deformers: deformers(frame, grids, bodyWarp?.deformer, arms, byRole),
|
|
5379
5553
|
...has("hair_front") ? { physics: hairPhysics() } : {},
|
|
5380
5554
|
expressions: defaultExpressions(new Set(parameters.map((p) => p.id))),
|
|
5381
|
-
motions:
|
|
5555
|
+
motions: defaultMotions(new Set(parameters.map((p) => p.id)))
|
|
5382
5556
|
};
|
|
5383
5557
|
const valid = parseIkiModel3(model);
|
|
5384
5558
|
if (hasNose && options.onTurnSolved) {
|
|
@@ -5395,14 +5569,14 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
|
5395
5569
|
function turnWarps(mesh, b, fieldOf) {
|
|
5396
5570
|
return [
|
|
5397
5571
|
localWarp(
|
|
5398
|
-
|
|
5572
|
+
P7.AngleX,
|
|
5399
5573
|
mesh,
|
|
5400
5574
|
b,
|
|
5401
5575
|
X_STOPS,
|
|
5402
5576
|
([x, y], v, i) => v === 0 ? [0, 0] : [fieldOf(i)(x, y, v, 0)[0], 0]
|
|
5403
5577
|
),
|
|
5404
5578
|
localWarp(
|
|
5405
|
-
|
|
5579
|
+
P7.AngleY,
|
|
5406
5580
|
mesh,
|
|
5407
5581
|
b,
|
|
5408
5582
|
Y_STOPS,
|
|
@@ -5450,7 +5624,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
5450
5624
|
}
|
|
5451
5625
|
if (mesh !== void 0) part.mesh = mesh;
|
|
5452
5626
|
const side = spec.role.endsWith("_L") ? "L" : "R";
|
|
5453
|
-
const eyeOpen = side === "L" ?
|
|
5627
|
+
const eyeOpen = side === "L" ? P7.EyeOpenLeft : P7.EyeOpenRight;
|
|
5454
5628
|
const hh = frame.hh;
|
|
5455
5629
|
switch (spec.role) {
|
|
5456
5630
|
case "face":
|
|
@@ -5465,7 +5639,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
5465
5639
|
headOwnRoll(byRole.has("body"))
|
|
5466
5640
|
),
|
|
5467
5641
|
localWarp(
|
|
5468
|
-
|
|
5642
|
+
P7.Breath,
|
|
5469
5643
|
mesh,
|
|
5470
5644
|
b,
|
|
5471
5645
|
[0, 1],
|
|
@@ -5512,8 +5686,8 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
5512
5686
|
if (byRole.has("mouth_open")) {
|
|
5513
5687
|
warps.push(mouthWiden(mesh, b));
|
|
5514
5688
|
bindings.push(
|
|
5515
|
-
{ parameter:
|
|
5516
|
-
{ parameter:
|
|
5689
|
+
{ parameter: P7.MouthOpen, channel: "opacity", from: 1, to: 0 },
|
|
5690
|
+
{ parameter: P7.MouthOpen, channel: "opacity", from: 1, to: 0 }
|
|
5517
5691
|
);
|
|
5518
5692
|
extra = [(AMPLITUDE.mouthOpenWidth - 1) * (bw(b) / 2), 0];
|
|
5519
5693
|
} else {
|
|
@@ -5523,19 +5697,19 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
5523
5697
|
);
|
|
5524
5698
|
bindings.push(
|
|
5525
5699
|
{
|
|
5526
|
-
parameter:
|
|
5700
|
+
parameter: P7.MouthOpen,
|
|
5527
5701
|
channel: "scaleY",
|
|
5528
5702
|
from: 0,
|
|
5529
5703
|
to: roundTo(grow, 0.01)
|
|
5530
5704
|
},
|
|
5531
5705
|
{
|
|
5532
|
-
parameter:
|
|
5706
|
+
parameter: P7.MouthOpen,
|
|
5533
5707
|
channel: "scaleX",
|
|
5534
5708
|
from: 0,
|
|
5535
5709
|
to: roundTo(AMPLITUDE.mouthOpenWidth - 1, 0.01)
|
|
5536
5710
|
},
|
|
5537
5711
|
{
|
|
5538
|
-
parameter:
|
|
5712
|
+
parameter: P7.MouthOpen,
|
|
5539
5713
|
channel: "translateY",
|
|
5540
5714
|
from: 0,
|
|
5541
5715
|
to: -roundTo(grow * bh(b) / 2, 0.01)
|
|
@@ -5547,7 +5721,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
5547
5721
|
case "mouth_open":
|
|
5548
5722
|
warps.push(mouthForm(mesh, b), mouthOpenGrow(mesh, b));
|
|
5549
5723
|
bindings.push({
|
|
5550
|
-
parameter:
|
|
5724
|
+
parameter: P7.MouthOpen,
|
|
5551
5725
|
channel: "opacity",
|
|
5552
5726
|
from: 0,
|
|
5553
5727
|
to: 1
|
|
@@ -5557,7 +5731,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
5557
5731
|
case "blush_L":
|
|
5558
5732
|
case "blush_R":
|
|
5559
5733
|
bindings.push({
|
|
5560
|
-
parameter:
|
|
5734
|
+
parameter: P7.Cheek,
|
|
5561
5735
|
channel: "opacity",
|
|
5562
5736
|
from: AMPLITUDE.blushRest,
|
|
5563
5737
|
to: 1
|
|
@@ -5568,8 +5742,8 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
5568
5742
|
if (byRole.has("hair_front")) {
|
|
5569
5743
|
const amp = style.sway * AMPLITUDE.sway * hh;
|
|
5570
5744
|
warps.push(
|
|
5571
|
-
hairSway(
|
|
5572
|
-
hairSway(
|
|
5745
|
+
hairSway(P7.HairSwayX, mesh, b, amp),
|
|
5746
|
+
hairSway(P7.HairSwayZ, mesh, b, amp)
|
|
5573
5747
|
);
|
|
5574
5748
|
}
|
|
5575
5749
|
warps.push(tiltHang(mesh, b, pivot, hairHangWeight(frame.chinY, b.y0)));
|
|
@@ -5642,10 +5816,14 @@ function meshScale(role, frame) {
|
|
|
5642
5816
|
return Infinity;
|
|
5643
5817
|
}
|
|
5644
5818
|
}
|
|
5645
|
-
function deformers(frame, grids, bodyWarp, arms) {
|
|
5819
|
+
function deformers(frame, grids, bodyWarp, arms, byRole) {
|
|
5646
5820
|
const out = [];
|
|
5647
5821
|
if (bodyWarp !== void 0) out.push(bodyWarp);
|
|
5648
5822
|
for (const [role, g] of arms) out.push(...armDeformers(role, g));
|
|
5823
|
+
for (const [role, arm] of arms) {
|
|
5824
|
+
const pose = POSE_OF_ARM[role];
|
|
5825
|
+
if (byRole.has(pose)) out.push(forearmPoseDeformer(pose, arm));
|
|
5826
|
+
}
|
|
5649
5827
|
const hasBody = bodyWarp !== void 0;
|
|
5650
5828
|
const roll = headOwnRoll(hasBody);
|
|
5651
5829
|
out.push({
|
|
@@ -5654,9 +5832,9 @@ function deformers(frame, grids, bodyWarp, arms) {
|
|
|
5654
5832
|
pivot: { x: roundTo(frame.axisX, 0.01), y: roundTo(frame.chinY, 0.01) },
|
|
5655
5833
|
bindings: [
|
|
5656
5834
|
// AngleZ is clockwise-positive (Live2D's); a rotation is CCW-positive.
|
|
5657
|
-
{ parameter:
|
|
5835
|
+
{ parameter: P7.AngleZ, channel: "rotate", from: roll, to: -roll },
|
|
5658
5836
|
{
|
|
5659
|
-
parameter:
|
|
5837
|
+
parameter: P7.Breath,
|
|
5660
5838
|
channel: "translateY",
|
|
5661
5839
|
from: 0,
|
|
5662
5840
|
to: roundTo(headOwnBreath(hasBody) * frame.hh, 0.01)
|
|
@@ -5674,8 +5852,8 @@ function deformers(frame, grids, bodyWarp, arms) {
|
|
|
5674
5852
|
points: g.lattice.points
|
|
5675
5853
|
},
|
|
5676
5854
|
warp2d: {
|
|
5677
|
-
parameter:
|
|
5678
|
-
parameterY:
|
|
5855
|
+
parameter: P7.AngleX,
|
|
5856
|
+
parameterY: P7.AngleY,
|
|
5679
5857
|
valuesX: X_STOPS,
|
|
5680
5858
|
valuesY: Y_STOPS,
|
|
5681
5859
|
keyforms2d: g.keyforms.map((offsets) => ({ offsets }))
|
|
@@ -5688,16 +5866,16 @@ function hairPhysics() {
|
|
|
5688
5866
|
return [
|
|
5689
5867
|
{
|
|
5690
5868
|
id: "hairSway",
|
|
5691
|
-
input: { parameter:
|
|
5692
|
-
output: { parameter:
|
|
5869
|
+
input: { parameter: P7.AngleX, weight: 1 },
|
|
5870
|
+
output: { parameter: P7.HairSwayX, scale: 5 },
|
|
5693
5871
|
mass: 1,
|
|
5694
5872
|
stiffness: 30,
|
|
5695
5873
|
damping: 3
|
|
5696
5874
|
},
|
|
5697
5875
|
{
|
|
5698
5876
|
id: "hairTilt",
|
|
5699
|
-
input: { parameter:
|
|
5700
|
-
output: { parameter:
|
|
5877
|
+
input: { parameter: P7.AngleZ, weight: 1 },
|
|
5878
|
+
output: { parameter: P7.HairSwayZ, scale: 8 },
|
|
5701
5879
|
mass: 1,
|
|
5702
5880
|
stiffness: 25,
|
|
5703
5881
|
damping: 2.5
|
|
@@ -5707,47 +5885,55 @@ function hairPhysics() {
|
|
|
5707
5885
|
function declareParameters(roles) {
|
|
5708
5886
|
const out = [];
|
|
5709
5887
|
const add = (id, name, min, max, def) => out.push({ id, name, min, max, default: def });
|
|
5710
|
-
add(
|
|
5711
|
-
add(
|
|
5712
|
-
add(
|
|
5888
|
+
add(P7.AngleX, "Head Angle", -30, 30, 0);
|
|
5889
|
+
add(P7.AngleY, "Head Angle Y", -30, 30, 0);
|
|
5890
|
+
add(P7.AngleZ, "Head Angle Z", -30, 30, 0);
|
|
5713
5891
|
if (roles.has("body")) {
|
|
5714
|
-
add(
|
|
5715
|
-
add(
|
|
5716
|
-
add(
|
|
5892
|
+
add(P7.BodyAngleX, "Body Angle X", -10, 10, 0);
|
|
5893
|
+
add(P7.BodyAngleY, "Body Angle Y", -10, 10, 0);
|
|
5894
|
+
add(P7.BodyAngleZ, "Body Angle Z", -10, 10, 0);
|
|
5717
5895
|
}
|
|
5896
|
+
const addPose = (side, pose, angle) => {
|
|
5897
|
+
add(pose, `Arm Pose ${side}`, 0, 1, 0);
|
|
5898
|
+
add(angle, `Arm Pose Angle ${side}`, ...POSE_ANGLE_RANGE, 0);
|
|
5899
|
+
};
|
|
5718
5900
|
const [armMin, armMax] = ARM_RANGE;
|
|
5719
5901
|
const [elbowMin, elbowMax] = ELBOW_RANGE;
|
|
5720
5902
|
if (roles.has("arm_L")) {
|
|
5721
|
-
add(
|
|
5722
|
-
add(
|
|
5903
|
+
add(P7.ArmLeft, "Arm L", armMin, armMax, 0);
|
|
5904
|
+
add(P7.ElbowLeft, "Elbow L", elbowMin, elbowMax, 0);
|
|
5905
|
+
if (roles.has("forearm_pose_L"))
|
|
5906
|
+
addPose("L", P7.ArmPoseLeft, P7.ArmPoseAngleLeft);
|
|
5723
5907
|
}
|
|
5724
5908
|
if (roles.has("arm_R")) {
|
|
5725
|
-
add(
|
|
5726
|
-
add(
|
|
5909
|
+
add(P7.ArmRight, "Arm R", armMin, armMax, 0);
|
|
5910
|
+
add(P7.ElbowRight, "Elbow R", elbowMin, elbowMax, 0);
|
|
5911
|
+
if (roles.has("forearm_pose_R"))
|
|
5912
|
+
addPose("R", P7.ArmPoseRight, P7.ArmPoseAngleRight);
|
|
5727
5913
|
}
|
|
5728
|
-
add(
|
|
5729
|
-
add(
|
|
5914
|
+
add(P7.EyeOpenLeft, "Eye L", 0, 1, 1);
|
|
5915
|
+
add(P7.EyeOpenRight, "Eye R", 0, 1, 1);
|
|
5730
5916
|
if ([...roles].some((r) => /^(iris|pupil|highlight)_/.test(r))) {
|
|
5731
|
-
add(
|
|
5732
|
-
add(
|
|
5917
|
+
add(P7.EyeballX, "Gaze X", -1, 1, 0);
|
|
5918
|
+
add(P7.EyeballY, "Gaze Y", -1, 1, 0);
|
|
5733
5919
|
}
|
|
5734
|
-
add(
|
|
5735
|
-
add(
|
|
5920
|
+
add(P7.MouthOpen, "Mouth Open", 0, 1, 0);
|
|
5921
|
+
add(P7.MouthForm, "Mouth Form", -1, 1, 0);
|
|
5736
5922
|
if (roles.has("brow_L")) {
|
|
5737
|
-
add(
|
|
5738
|
-
add(
|
|
5923
|
+
add(P7.BrowLeftY, "Brow L Y", -1, 1, 0);
|
|
5924
|
+
add(P7.BrowLeftAngle, "Brow L Angle", -1, 1, 0);
|
|
5739
5925
|
}
|
|
5740
5926
|
if (roles.has("brow_R")) {
|
|
5741
|
-
add(
|
|
5742
|
-
add(
|
|
5927
|
+
add(P7.BrowRightY, "Brow R Y", -1, 1, 0);
|
|
5928
|
+
add(P7.BrowRightAngle, "Brow R Angle", -1, 1, 0);
|
|
5743
5929
|
}
|
|
5744
5930
|
if (roles.has("blush_L") || roles.has("blush_R")) {
|
|
5745
|
-
add(
|
|
5931
|
+
add(P7.Cheek, "Cheek", 0, 1, 0);
|
|
5746
5932
|
}
|
|
5747
|
-
add(
|
|
5933
|
+
add(P7.Breath, "Breath", 0, 1, 0);
|
|
5748
5934
|
if (roles.has("hair_front")) {
|
|
5749
|
-
add(
|
|
5750
|
-
add(
|
|
5935
|
+
add(P7.HairSwayX, "Hair Sway X", -SWAY_RANGE, SWAY_RANGE, 0);
|
|
5936
|
+
add(P7.HairSwayZ, "Hair Sway Z", -SWAY_RANGE, SWAY_RANGE, 0);
|
|
5751
5937
|
}
|
|
5752
5938
|
return out;
|
|
5753
5939
|
}
|
|
@@ -5794,6 +5980,7 @@ export {
|
|
|
5794
5980
|
createLayerSetMeasurer,
|
|
5795
5981
|
denseCoreOf,
|
|
5796
5982
|
detectAlphaBbox,
|
|
5983
|
+
forearmPoseGeometry,
|
|
5797
5984
|
foregroundSpan,
|
|
5798
5985
|
generateIkiFromLayerSet,
|
|
5799
5986
|
headHalfOf,
|