@ikijs/editor 0.14.0 → 0.16.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 +6 -1
- package/dist/index.d.mts +9 -4
- package/dist/index.d.ts +9 -4
- package/dist/index.js +236 -56
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +236 -54
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -447,11 +447,24 @@ function validateDeformerReparent(deformers2, deformerId, newParentId) {
|
|
|
447
447
|
`deformers."${deformerId}".parent "${newParentId}" is not a declared deformer`
|
|
448
448
|
);
|
|
449
449
|
}
|
|
450
|
-
if (kindOf(parent) === "warp") {
|
|
450
|
+
if (kindOf(parent) === "warp" && kindOf(target) === "warp") {
|
|
451
451
|
throw new Error(
|
|
452
|
-
`deformers."${deformerId}".parent "${newParentId}" must be a matrix deformer (warp deformers cannot be
|
|
452
|
+
`deformers."${deformerId}".parent "${newParentId}" must be a matrix deformer (warp deformers cannot be nested under a warp deformer)`
|
|
453
453
|
);
|
|
454
454
|
}
|
|
455
|
+
if (parent.kind === "warp" && target.kind !== "warp") {
|
|
456
|
+
const { pivot } = target;
|
|
457
|
+
const { cols, rows, points } = parent.grid;
|
|
458
|
+
const xMin = points[0];
|
|
459
|
+
const xMax = points[2 * cols];
|
|
460
|
+
const yMax = points[1];
|
|
461
|
+
const yMin = points[rows * (cols + 1) * 2 + 1];
|
|
462
|
+
if (pivot.x < xMin || pivot.x > xMax || pivot.y < yMin || pivot.y > yMax) {
|
|
463
|
+
throw new Error(
|
|
464
|
+
`deformers."${deformerId}".pivot (${pivot.x}, ${pivot.y}) lies outside its warp parent "${newParentId}" rest grid x ${xMin}..${xMax}, y ${yMin}..${yMax}`
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
455
468
|
const parentOf = /* @__PURE__ */ new Map();
|
|
456
469
|
for (const d of deformers2) {
|
|
457
470
|
if (d.parent !== void 0) parentOf.set(d.id, d.parent);
|
|
@@ -1910,7 +1923,8 @@ var PROFILE_VALUES = {
|
|
|
1910
1923
|
mouthWiden: 1.2,
|
|
1911
1924
|
brow: 0.15,
|
|
1912
1925
|
breath: 0.03,
|
|
1913
|
-
sway: 0.08
|
|
1926
|
+
sway: 0.08,
|
|
1927
|
+
blushRest: 0.4
|
|
1914
1928
|
};
|
|
1915
1929
|
function deriveProfile(v) {
|
|
1916
1930
|
const farLead = v.lead * (1 - v.fore / 2);
|
|
@@ -1997,6 +2011,8 @@ function deriveProfile(v) {
|
|
|
1997
2011
|
breathHead: v.breath * 2 / 3,
|
|
1998
2012
|
/** Hair tip travel at full sway (±20), hh. */
|
|
1999
2013
|
sway: v.sway,
|
|
2014
|
+
/** The blush's opacity at Cheek 0; at Cheek 1 it is as drawn. */
|
|
2015
|
+
blushRest: v.blushRest,
|
|
2000
2016
|
/** The neck under the face reaches this far above the jaw, hh — what the
|
|
2001
2017
|
* chin uncovers as it slides off it: half again the chin's full-turn
|
|
2002
2018
|
* slide, to the next 0.05. */
|
|
@@ -2116,10 +2132,161 @@ function parseLayerRoles(fileNames) {
|
|
|
2116
2132
|
// src/auto-rig/generate.ts
|
|
2117
2133
|
import {
|
|
2118
2134
|
IKI_FORMAT_VERSION as IKI_FORMAT_VERSION2,
|
|
2119
|
-
StandardParameter as
|
|
2135
|
+
StandardParameter as P4,
|
|
2120
2136
|
parseIkiModel as parseIkiModel3
|
|
2121
2137
|
} from "@ikijs/format";
|
|
2122
2138
|
|
|
2139
|
+
// src/auto-rig/animations.ts
|
|
2140
|
+
import {
|
|
2141
|
+
StandardParameter as P
|
|
2142
|
+
} from "@ikijs/format";
|
|
2143
|
+
function browsY(y) {
|
|
2144
|
+
return [
|
|
2145
|
+
{ parameter: P.BrowLeftY, value: y, blend: "add" },
|
|
2146
|
+
{ parameter: P.BrowRightY, value: y, blend: "add" }
|
|
2147
|
+
];
|
|
2148
|
+
}
|
|
2149
|
+
function browsTilt(innerDown) {
|
|
2150
|
+
return [
|
|
2151
|
+
{ parameter: P.BrowLeftAngle, value: innerDown, blend: "add" },
|
|
2152
|
+
{ parameter: P.BrowRightAngle, value: -innerDown, blend: "add" }
|
|
2153
|
+
];
|
|
2154
|
+
}
|
|
2155
|
+
function cheek(value) {
|
|
2156
|
+
return { parameter: P.Cheek, value, blend: "add" };
|
|
2157
|
+
}
|
|
2158
|
+
var BROWS = [P.BrowLeftY, P.BrowRightY, P.BrowLeftAngle, P.BrowRightAngle];
|
|
2159
|
+
var EXPRESSIONS = [
|
|
2160
|
+
{
|
|
2161
|
+
id: "smile",
|
|
2162
|
+
description: "Smiling and pleased: warm, friendly, content. For greetings, thanks, agreement and gentle happiness.",
|
|
2163
|
+
parameters: [
|
|
2164
|
+
{ parameter: P.MouthForm, value: 1, blend: "add" },
|
|
2165
|
+
...browsY(0.25),
|
|
2166
|
+
cheek(0.4)
|
|
2167
|
+
]
|
|
2168
|
+
},
|
|
2169
|
+
{
|
|
2170
|
+
id: "laugh",
|
|
2171
|
+
description: "Laughing, eyes shut and mouth open: delighted, amused. For jokes, playfulness and big joy.",
|
|
2172
|
+
parameters: [
|
|
2173
|
+
{ parameter: P.EyeOpenLeft, value: 0, blend: "multiply" },
|
|
2174
|
+
{ parameter: P.EyeOpenRight, value: 0, blend: "multiply" },
|
|
2175
|
+
{ parameter: P.MouthForm, value: 1, blend: "add" },
|
|
2176
|
+
{ parameter: P.MouthOpen, value: 0.8, blend: "overwrite" },
|
|
2177
|
+
...browsY(0.4),
|
|
2178
|
+
cheek(0.65)
|
|
2179
|
+
]
|
|
2180
|
+
},
|
|
2181
|
+
{
|
|
2182
|
+
id: "angry",
|
|
2183
|
+
description: "Angry or annoyed, frowning. For irritation, frustration, indignation or scolding.",
|
|
2184
|
+
needs: BROWS,
|
|
2185
|
+
parameters: [
|
|
2186
|
+
...browsY(-0.5),
|
|
2187
|
+
...browsTilt(0.8),
|
|
2188
|
+
{ parameter: P.MouthForm, value: -0.9, blend: "add" }
|
|
2189
|
+
]
|
|
2190
|
+
},
|
|
2191
|
+
{
|
|
2192
|
+
id: "sad",
|
|
2193
|
+
description: "Sad or disappointed, downcast. For sorrow, regret, apology or sympathy.",
|
|
2194
|
+
needs: BROWS,
|
|
2195
|
+
parameters: [
|
|
2196
|
+
...browsY(0.35),
|
|
2197
|
+
...browsTilt(-0.8),
|
|
2198
|
+
{ parameter: P.MouthForm, value: -0.8, blend: "add" }
|
|
2199
|
+
]
|
|
2200
|
+
},
|
|
2201
|
+
{
|
|
2202
|
+
id: "surprised",
|
|
2203
|
+
description: "Surprised, mouth dropped open: startled, amazed. For shock, sudden news or disbelief.",
|
|
2204
|
+
parameters: [
|
|
2205
|
+
...browsY(0.8),
|
|
2206
|
+
{ parameter: P.MouthOpen, value: 0.9, blend: "overwrite" }
|
|
2207
|
+
]
|
|
2208
|
+
},
|
|
2209
|
+
{
|
|
2210
|
+
id: "shy",
|
|
2211
|
+
description: "Shy or embarrassed: bashful, flustered. For being praised, teased or caught off guard.",
|
|
2212
|
+
needs: [P.Cheek],
|
|
2213
|
+
parameters: [
|
|
2214
|
+
cheek(1),
|
|
2215
|
+
// Gaze down.
|
|
2216
|
+
{ parameter: P.EyeballY, value: -0.65, blend: "add" },
|
|
2217
|
+
{ parameter: P.MouthForm, value: 0.4, blend: "add" },
|
|
2218
|
+
...browsTilt(-0.25)
|
|
2219
|
+
]
|
|
2220
|
+
}
|
|
2221
|
+
];
|
|
2222
|
+
function defaultExpressions(declared) {
|
|
2223
|
+
return EXPRESSIONS.filter(
|
|
2224
|
+
(e) => e.needs === void 0 || e.needs.some((id) => declared.has(id))
|
|
2225
|
+
).map(({ needs: _needs, ...e }) => ({
|
|
2226
|
+
...e,
|
|
2227
|
+
parameters: e.parameters.filter((t) => declared.has(t.parameter))
|
|
2228
|
+
}));
|
|
2229
|
+
}
|
|
2230
|
+
var DEFAULT_MOTIONS = {
|
|
2231
|
+
Nod: [
|
|
2232
|
+
{
|
|
2233
|
+
description: "Nods yes: agreement, acknowledgement, understanding.",
|
|
2234
|
+
duration: 1,
|
|
2235
|
+
curves: [
|
|
2236
|
+
{
|
|
2237
|
+
parameter: P.AngleY,
|
|
2238
|
+
keys: [
|
|
2239
|
+
[0, 0],
|
|
2240
|
+
[0.3, -18],
|
|
2241
|
+
[0.6, 4],
|
|
2242
|
+
[0.8, -1],
|
|
2243
|
+
[1, 0]
|
|
2244
|
+
]
|
|
2245
|
+
}
|
|
2246
|
+
]
|
|
2247
|
+
}
|
|
2248
|
+
],
|
|
2249
|
+
Shake: [
|
|
2250
|
+
{
|
|
2251
|
+
description: "Shakes the head no: disagreement, refusal, disbelief.",
|
|
2252
|
+
duration: 1.2,
|
|
2253
|
+
// The first swing peaks at 0.2 s, which the default fade would still
|
|
2254
|
+
// be damping.
|
|
2255
|
+
fadeIn: 0.15,
|
|
2256
|
+
curves: [
|
|
2257
|
+
{
|
|
2258
|
+
parameter: P.AngleX,
|
|
2259
|
+
keys: [
|
|
2260
|
+
[0, 0],
|
|
2261
|
+
[0.2, -18],
|
|
2262
|
+
[0.45, 18],
|
|
2263
|
+
[0.7, -16],
|
|
2264
|
+
[0.95, 10],
|
|
2265
|
+
[1.2, 0]
|
|
2266
|
+
]
|
|
2267
|
+
}
|
|
2268
|
+
]
|
|
2269
|
+
}
|
|
2270
|
+
],
|
|
2271
|
+
Tilt: [
|
|
2272
|
+
{
|
|
2273
|
+
description: "Tilts the head to one side and back: curiosity, puzzlement, a question.",
|
|
2274
|
+
duration: 1.4,
|
|
2275
|
+
curves: [
|
|
2276
|
+
{
|
|
2277
|
+
parameter: P.AngleZ,
|
|
2278
|
+
keys: [
|
|
2279
|
+
[0, 0],
|
|
2280
|
+
[0.35, 20],
|
|
2281
|
+
[1, 20],
|
|
2282
|
+
[1.4, 0]
|
|
2283
|
+
]
|
|
2284
|
+
}
|
|
2285
|
+
]
|
|
2286
|
+
}
|
|
2287
|
+
]
|
|
2288
|
+
};
|
|
2289
|
+
|
|
2123
2290
|
// src/auto-rig/layout.ts
|
|
2124
2291
|
function boxOfLayer(layer) {
|
|
2125
2292
|
return boxOfPixels(layer.bbox, layer.canvasW, layer.canvasH);
|
|
@@ -2413,7 +2580,7 @@ function checkStrandEdges(strand, irises, hair) {
|
|
|
2413
2580
|
}
|
|
2414
2581
|
|
|
2415
2582
|
// src/auto-rig/context.ts
|
|
2416
|
-
import { StandardParameter as
|
|
2583
|
+
import { StandardParameter as P2 } from "@ikijs/format";
|
|
2417
2584
|
|
|
2418
2585
|
// src/auto-rig/grid.ts
|
|
2419
2586
|
var X_STOPS = [-30, 0, 30];
|
|
@@ -3629,7 +3796,7 @@ function renderedLander(turn, parts, grids, from = /* @__PURE__ */ new Map()) {
|
|
|
3629
3796
|
const family = roleSpec(role).family;
|
|
3630
3797
|
const part = parts.find((p) => p.id === role);
|
|
3631
3798
|
const g = grids.get(family);
|
|
3632
|
-
const warp = part?.warps?.find((w) => w.parameter ===
|
|
3799
|
+
const warp = part?.warps?.find((w) => w.parameter === P2.AngleX);
|
|
3633
3800
|
if (part === void 0 || part.mesh === void 0 || !g && !warp) {
|
|
3634
3801
|
return x + field(role)(x, y, ax, 0)[0];
|
|
3635
3802
|
}
|
|
@@ -4340,7 +4507,7 @@ function buildTurn(frame, landmarks, q) {
|
|
|
4340
4507
|
|
|
4341
4508
|
// src/auto-rig/drivers.ts
|
|
4342
4509
|
import {
|
|
4343
|
-
StandardParameter as
|
|
4510
|
+
StandardParameter as P3
|
|
4344
4511
|
} from "@ikijs/format";
|
|
4345
4512
|
var SWAY_RANGE = 20;
|
|
4346
4513
|
var SWAY_CURVE = 1.4;
|
|
@@ -4419,13 +4586,13 @@ function gazeBindings(irisW, share = 1) {
|
|
|
4419
4586
|
const gy = AMPLITUDE.gazeY * irisW * share;
|
|
4420
4587
|
return [
|
|
4421
4588
|
{
|
|
4422
|
-
parameter:
|
|
4589
|
+
parameter: P3.EyeballX,
|
|
4423
4590
|
channel: "translateX",
|
|
4424
4591
|
from: -round1(gx),
|
|
4425
4592
|
to: round1(gx)
|
|
4426
4593
|
},
|
|
4427
4594
|
{
|
|
4428
|
-
parameter:
|
|
4595
|
+
parameter: P3.EyeballY,
|
|
4429
4596
|
channel: "translateY",
|
|
4430
4597
|
from: -round1(gy),
|
|
4431
4598
|
to: round1(gy)
|
|
@@ -4439,8 +4606,8 @@ function browReach(hh) {
|
|
|
4439
4606
|
return AMPLITUDE.brow * hh;
|
|
4440
4607
|
}
|
|
4441
4608
|
function browBindings(side, reach) {
|
|
4442
|
-
const y = side === "L" ?
|
|
4443
|
-
const a = side === "L" ?
|
|
4609
|
+
const y = side === "L" ? P3.BrowLeftY : P3.BrowRightY;
|
|
4610
|
+
const a = side === "L" ? P3.BrowLeftAngle : P3.BrowRightAngle;
|
|
4444
4611
|
return [
|
|
4445
4612
|
{
|
|
4446
4613
|
parameter: y,
|
|
@@ -4456,7 +4623,7 @@ function mouthForm(mesh, box) {
|
|
|
4456
4623
|
const a = 0.3 * bh(box);
|
|
4457
4624
|
const c = cx(box);
|
|
4458
4625
|
const half = bw(box) / 2;
|
|
4459
|
-
return localWarp(
|
|
4626
|
+
return localWarp(P3.MouthForm, mesh, box, [-1, 0, 1], ([x], v) => {
|
|
4460
4627
|
if (v === 0) return [0, 0];
|
|
4461
4628
|
const u = (x - c) / half;
|
|
4462
4629
|
const widen = v > 0 ? 0.05 : 0.03;
|
|
@@ -4466,7 +4633,7 @@ function mouthForm(mesh, box) {
|
|
|
4466
4633
|
function mouthOpenGrow(mesh, box) {
|
|
4467
4634
|
const c = cx(box);
|
|
4468
4635
|
return localWarp(
|
|
4469
|
-
|
|
4636
|
+
P3.MouthOpen,
|
|
4470
4637
|
mesh,
|
|
4471
4638
|
box,
|
|
4472
4639
|
[0, 1],
|
|
@@ -4475,7 +4642,7 @@ function mouthOpenGrow(mesh, box) {
|
|
|
4475
4642
|
}
|
|
4476
4643
|
function mouthWiden(mesh, box) {
|
|
4477
4644
|
const c = cx(box);
|
|
4478
|
-
return localWarp(
|
|
4645
|
+
return localWarp(P3.MouthOpen, mesh, box, [0, 1], ([x], v) => [
|
|
4479
4646
|
v * (AMPLITUDE.mouthOpenWidth - 1) * (x - c),
|
|
4480
4647
|
0
|
|
4481
4648
|
]);
|
|
@@ -4493,7 +4660,7 @@ function hairSway(param, mesh, box, amp) {
|
|
|
4493
4660
|
);
|
|
4494
4661
|
}
|
|
4495
4662
|
function tiltHang(mesh, box, pivot, weight) {
|
|
4496
|
-
return localWarp(
|
|
4663
|
+
return localWarp(P3.AngleZ, mesh, box, Z_STOPS, ([x, y], v, i) => {
|
|
4497
4664
|
const g = weight(y, i);
|
|
4498
4665
|
if (g === 0 || v === 0) return [0, 0];
|
|
4499
4666
|
const a = -g * rollOf(v);
|
|
@@ -4646,14 +4813,17 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
|
4646
4813
|
...part.warps ?? []
|
|
4647
4814
|
];
|
|
4648
4815
|
}
|
|
4816
|
+
const parameters = declareParameters(new Set(byRole.keys()));
|
|
4649
4817
|
const model = {
|
|
4650
4818
|
version: IKI_FORMAT_VERSION2,
|
|
4651
4819
|
name: "auto-rigged",
|
|
4652
4820
|
canvas: { width: canvas.width, height: canvas.height },
|
|
4653
|
-
parameters
|
|
4821
|
+
parameters,
|
|
4654
4822
|
parts,
|
|
4655
4823
|
deformers: deformers(frame, grids, has("body") ? box("body") : void 0),
|
|
4656
|
-
...has("hair_front") ? { physics: hairPhysics() } : {}
|
|
4824
|
+
...has("hair_front") ? { physics: hairPhysics() } : {},
|
|
4825
|
+
expressions: defaultExpressions(new Set(parameters.map((p) => p.id))),
|
|
4826
|
+
motions: DEFAULT_MOTIONS
|
|
4657
4827
|
};
|
|
4658
4828
|
const valid = parseIkiModel3(model);
|
|
4659
4829
|
if (hasNose && options.onTurnSolved) {
|
|
@@ -4670,14 +4840,14 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
|
4670
4840
|
function turnWarps(mesh, b, fieldOf) {
|
|
4671
4841
|
return [
|
|
4672
4842
|
localWarp(
|
|
4673
|
-
|
|
4843
|
+
P4.AngleX,
|
|
4674
4844
|
mesh,
|
|
4675
4845
|
b,
|
|
4676
4846
|
X_STOPS,
|
|
4677
4847
|
([x, y], v, i) => v === 0 ? [0, 0] : [fieldOf(i)(x, y, v, 0)[0], 0]
|
|
4678
4848
|
),
|
|
4679
4849
|
localWarp(
|
|
4680
|
-
|
|
4850
|
+
P4.AngleY,
|
|
4681
4851
|
mesh,
|
|
4682
4852
|
b,
|
|
4683
4853
|
Y_STOPS,
|
|
@@ -4725,7 +4895,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
4725
4895
|
}
|
|
4726
4896
|
if (mesh !== void 0) part.mesh = mesh;
|
|
4727
4897
|
const side = spec.role.endsWith("_L") ? "L" : "R";
|
|
4728
|
-
const eyeOpen = side === "L" ?
|
|
4898
|
+
const eyeOpen = side === "L" ? P4.EyeOpenLeft : P4.EyeOpenRight;
|
|
4729
4899
|
const hh = frame.hh;
|
|
4730
4900
|
switch (spec.role) {
|
|
4731
4901
|
case "face":
|
|
@@ -4734,7 +4904,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
4734
4904
|
warps.push(
|
|
4735
4905
|
tiltHang(mesh, b, pivot, (_y, i) => isNeck[i] ? 1 : 0),
|
|
4736
4906
|
localWarp(
|
|
4737
|
-
|
|
4907
|
+
P4.Breath,
|
|
4738
4908
|
mesh,
|
|
4739
4909
|
b,
|
|
4740
4910
|
[0, 1],
|
|
@@ -4781,8 +4951,8 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
4781
4951
|
if (byRole.has("mouth_open")) {
|
|
4782
4952
|
warps.push(mouthWiden(mesh, b));
|
|
4783
4953
|
bindings.push(
|
|
4784
|
-
{ parameter:
|
|
4785
|
-
{ parameter:
|
|
4954
|
+
{ parameter: P4.MouthOpen, channel: "opacity", from: 1, to: 0 },
|
|
4955
|
+
{ parameter: P4.MouthOpen, channel: "opacity", from: 1, to: 0 }
|
|
4786
4956
|
);
|
|
4787
4957
|
extra = [(AMPLITUDE.mouthOpenWidth - 1) * (bw(b) / 2), 0];
|
|
4788
4958
|
} else {
|
|
@@ -4792,19 +4962,19 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
4792
4962
|
);
|
|
4793
4963
|
bindings.push(
|
|
4794
4964
|
{
|
|
4795
|
-
parameter:
|
|
4965
|
+
parameter: P4.MouthOpen,
|
|
4796
4966
|
channel: "scaleY",
|
|
4797
4967
|
from: 0,
|
|
4798
4968
|
to: roundTo(grow, 0.01)
|
|
4799
4969
|
},
|
|
4800
4970
|
{
|
|
4801
|
-
parameter:
|
|
4971
|
+
parameter: P4.MouthOpen,
|
|
4802
4972
|
channel: "scaleX",
|
|
4803
4973
|
from: 0,
|
|
4804
4974
|
to: roundTo(AMPLITUDE.mouthOpenWidth - 1, 0.01)
|
|
4805
4975
|
},
|
|
4806
4976
|
{
|
|
4807
|
-
parameter:
|
|
4977
|
+
parameter: P4.MouthOpen,
|
|
4808
4978
|
channel: "translateY",
|
|
4809
4979
|
from: 0,
|
|
4810
4980
|
to: -roundTo(grow * bh(b) / 2, 0.01)
|
|
@@ -4816,20 +4986,29 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
4816
4986
|
case "mouth_open":
|
|
4817
4987
|
warps.push(mouthForm(mesh, b), mouthOpenGrow(mesh, b));
|
|
4818
4988
|
bindings.push({
|
|
4819
|
-
parameter:
|
|
4989
|
+
parameter: P4.MouthOpen,
|
|
4820
4990
|
channel: "opacity",
|
|
4821
4991
|
from: 0,
|
|
4822
4992
|
to: 1
|
|
4823
4993
|
});
|
|
4824
4994
|
extra = [(AMPLITUDE.mouthOpenWidth - 1) * (bw(b) / 2), 0];
|
|
4825
4995
|
break;
|
|
4996
|
+
case "blush_L":
|
|
4997
|
+
case "blush_R":
|
|
4998
|
+
bindings.push({
|
|
4999
|
+
parameter: P4.Cheek,
|
|
5000
|
+
channel: "opacity",
|
|
5001
|
+
from: AMPLITUDE.blushRest,
|
|
5002
|
+
to: 1
|
|
5003
|
+
});
|
|
5004
|
+
break;
|
|
4826
5005
|
case "hair_front":
|
|
4827
5006
|
case "hair_back":
|
|
4828
5007
|
if (byRole.has("hair_front")) {
|
|
4829
5008
|
const amp = style.sway * AMPLITUDE.sway * hh;
|
|
4830
5009
|
warps.push(
|
|
4831
|
-
hairSway(
|
|
4832
|
-
hairSway(
|
|
5010
|
+
hairSway(P4.HairSwayX, mesh, b, amp),
|
|
5011
|
+
hairSway(P4.HairSwayZ, mesh, b, amp)
|
|
4833
5012
|
);
|
|
4834
5013
|
}
|
|
4835
5014
|
warps.push(tiltHang(mesh, b, pivot, hairHangWeight(frame.chinY, b.y0)));
|
|
@@ -4910,7 +5089,7 @@ function deformers(frame, grids, body) {
|
|
|
4910
5089
|
pivot: { x: roundTo(cx(body), 0.01), y: roundTo(body.y1, 0.01) },
|
|
4911
5090
|
bindings: [
|
|
4912
5091
|
{
|
|
4913
|
-
parameter:
|
|
5092
|
+
parameter: P4.Breath,
|
|
4914
5093
|
channel: "translateY",
|
|
4915
5094
|
from: 0,
|
|
4916
5095
|
to: roundTo(AMPLITUDE.breathBody * frame.hh, 0.01)
|
|
@@ -4923,9 +5102,9 @@ function deformers(frame, grids, body) {
|
|
|
4923
5102
|
pivot: { x: roundTo(frame.axisX, 0.01), y: roundTo(frame.chinY, 0.01) },
|
|
4924
5103
|
bindings: [
|
|
4925
5104
|
// AngleZ is clockwise-positive (Live2D's); a rotation is CCW-positive.
|
|
4926
|
-
{ parameter:
|
|
5105
|
+
{ parameter: P4.AngleZ, channel: "rotate", from: ROLL_DEG, to: -ROLL_DEG },
|
|
4927
5106
|
{
|
|
4928
|
-
parameter:
|
|
5107
|
+
parameter: P4.Breath,
|
|
4929
5108
|
channel: "translateY",
|
|
4930
5109
|
from: 0,
|
|
4931
5110
|
to: roundTo(AMPLITUDE.breathHead * frame.hh, 0.01)
|
|
@@ -4943,8 +5122,8 @@ function deformers(frame, grids, body) {
|
|
|
4943
5122
|
points: g.lattice.points
|
|
4944
5123
|
},
|
|
4945
5124
|
warp2d: {
|
|
4946
|
-
parameter:
|
|
4947
|
-
parameterY:
|
|
5125
|
+
parameter: P4.AngleX,
|
|
5126
|
+
parameterY: P4.AngleY,
|
|
4948
5127
|
valuesX: X_STOPS,
|
|
4949
5128
|
valuesY: Y_STOPS,
|
|
4950
5129
|
keyforms2d: g.keyforms.map((offsets) => ({ offsets }))
|
|
@@ -4957,16 +5136,16 @@ function hairPhysics() {
|
|
|
4957
5136
|
return [
|
|
4958
5137
|
{
|
|
4959
5138
|
id: "hairSway",
|
|
4960
|
-
input: { parameter:
|
|
4961
|
-
output: { parameter:
|
|
5139
|
+
input: { parameter: P4.AngleX, weight: 1 },
|
|
5140
|
+
output: { parameter: P4.HairSwayX, scale: 5 },
|
|
4962
5141
|
mass: 1,
|
|
4963
5142
|
stiffness: 30,
|
|
4964
5143
|
damping: 3
|
|
4965
5144
|
},
|
|
4966
5145
|
{
|
|
4967
5146
|
id: "hairTilt",
|
|
4968
|
-
input: { parameter:
|
|
4969
|
-
output: { parameter:
|
|
5147
|
+
input: { parameter: P4.AngleZ, weight: 1 },
|
|
5148
|
+
output: { parameter: P4.HairSwayZ, scale: 8 },
|
|
4970
5149
|
mass: 1,
|
|
4971
5150
|
stiffness: 25,
|
|
4972
5151
|
damping: 2.5
|
|
@@ -4976,29 +5155,32 @@ function hairPhysics() {
|
|
|
4976
5155
|
function declareParameters(roles) {
|
|
4977
5156
|
const out = [];
|
|
4978
5157
|
const add = (id, name, min, max, def) => out.push({ id, name, min, max, default: def });
|
|
4979
|
-
add(
|
|
4980
|
-
add(
|
|
4981
|
-
add(
|
|
4982
|
-
add(
|
|
4983
|
-
add(
|
|
5158
|
+
add(P4.AngleX, "Head Angle", -30, 30, 0);
|
|
5159
|
+
add(P4.AngleY, "Head Angle Y", -30, 30, 0);
|
|
5160
|
+
add(P4.AngleZ, "Head Angle Z", -30, 30, 0);
|
|
5161
|
+
add(P4.EyeOpenLeft, "Eye L", 0, 1, 1);
|
|
5162
|
+
add(P4.EyeOpenRight, "Eye R", 0, 1, 1);
|
|
4984
5163
|
if ([...roles].some((r) => /^(iris|pupil|highlight)_/.test(r))) {
|
|
4985
|
-
add(
|
|
4986
|
-
add(
|
|
5164
|
+
add(P4.EyeballX, "Gaze X", -1, 1, 0);
|
|
5165
|
+
add(P4.EyeballY, "Gaze Y", -1, 1, 0);
|
|
4987
5166
|
}
|
|
4988
|
-
add(
|
|
4989
|
-
add(
|
|
5167
|
+
add(P4.MouthOpen, "Mouth Open", 0, 1, 0);
|
|
5168
|
+
add(P4.MouthForm, "Mouth Form", -1, 1, 0);
|
|
4990
5169
|
if (roles.has("brow_L")) {
|
|
4991
|
-
add(
|
|
4992
|
-
add(
|
|
5170
|
+
add(P4.BrowLeftY, "Brow L Y", -1, 1, 0);
|
|
5171
|
+
add(P4.BrowLeftAngle, "Brow L Angle", -1, 1, 0);
|
|
4993
5172
|
}
|
|
4994
5173
|
if (roles.has("brow_R")) {
|
|
4995
|
-
add(
|
|
4996
|
-
add(
|
|
5174
|
+
add(P4.BrowRightY, "Brow R Y", -1, 1, 0);
|
|
5175
|
+
add(P4.BrowRightAngle, "Brow R Angle", -1, 1, 0);
|
|
5176
|
+
}
|
|
5177
|
+
if (roles.has("blush_L") || roles.has("blush_R")) {
|
|
5178
|
+
add(P4.Cheek, "Cheek", 0, 1, 0);
|
|
4997
5179
|
}
|
|
4998
|
-
add(
|
|
5180
|
+
add(P4.Breath, "Breath", 0, 1, 0);
|
|
4999
5181
|
if (roles.has("hair_front")) {
|
|
5000
|
-
add(
|
|
5001
|
-
add(
|
|
5182
|
+
add(P4.HairSwayX, "Hair Sway X", -SWAY_RANGE, SWAY_RANGE, 0);
|
|
5183
|
+
add(P4.HairSwayZ, "Hair Sway Z", -SWAY_RANGE, SWAY_RANGE, 0);
|
|
5002
5184
|
}
|
|
5003
5185
|
return out;
|
|
5004
5186
|
}
|