@ikijs/editor 0.31.0 → 0.32.1
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 +3 -2
- package/dist/index.d.mts +23 -8
- package/dist/index.d.ts +23 -8
- package/dist/index.js +152 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +152 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -78,7 +78,7 @@ edge further outside the back hair painted behind it than the nod alone does —
|
|
|
78
78
|
and the back hair stays behind; the neck and the
|
|
79
79
|
ears the face layer paints are cut off into islands of the plate's own mesh,
|
|
80
80
|
drawn behind the head — the neck stays (only the chin's shade slides across
|
|
81
|
-
it), the ears lag the face, the far one
|
|
81
|
+
it), the ears lag the face, the far one held while the head slides partly over it (about half of an ear of the default size). AngleZ rolls the head 14° about the chin.
|
|
82
82
|
A `body` rides a body warp that breathes, follows the head's turn and tilt a
|
|
83
83
|
little and turns on `ParamBodyAngleX/Y/Z`, its legs planted, and the head
|
|
84
84
|
hangs from it. `arm_L` / `arm_R`, each a whole arm drawn hanging with its
|
|
@@ -102,7 +102,8 @@ hair sway), validated against `RIG_PLAN_FIELDS`. `options.patches` adds displace
|
|
|
102
102
|
stops (`RigPatch`), replayed on every rig and reported through
|
|
103
103
|
`options.onPatchesApplied`; a refused op throws `PatchError`. `options.customParts` adds parts the
|
|
104
104
|
auto-rigger has no role for (`CustomPart`: `id`, `layer`, `anchor`, `tie`,
|
|
105
|
-
`after`
|
|
105
|
+
`after`, and `occlusion`: roles whose parts hide it by an amount keyed on a
|
|
106
|
+
parameter), unrigged on `headDeformer` with a plain mesh and drawn after the
|
|
106
107
|
`after` role's last part; the rest of the model is as without them but for
|
|
107
108
|
the `order` of every part after an inserted one (a set rigged without
|
|
108
109
|
`customParts` is byte-identical), and a malformed entry throws
|
package/dist/index.d.mts
CHANGED
|
@@ -251,10 +251,11 @@ declare class AddDeformer implements EditCommand {
|
|
|
251
251
|
* visually predictable.
|
|
252
252
|
*
|
|
253
253
|
* No `parseIkiModel` pre-check is needed: removing an element from an already-
|
|
254
|
-
* valid model cannot introduce a structural violation — EXCEPT for
|
|
255
|
-
* references
|
|
256
|
-
* delete a part still used as another part's `clip.masks`
|
|
257
|
-
* so it can never leave a dangling
|
|
254
|
+
* valid model cannot introduce a structural violation — EXCEPT for the part→part
|
|
255
|
+
* references in the contract: `clip.masks` and `occlusion.by`. `apply` refuses to
|
|
256
|
+
* delete a part still used as another part's `clip.masks` or `occlusion.by`
|
|
257
|
+
* entry (guards below), so it can never leave a dangling ref that would fail
|
|
258
|
+
* `toIkiModel()`.
|
|
258
259
|
*
|
|
259
260
|
* Texture-reference safety (package invariant): `apply` refuses to delete a
|
|
260
261
|
* part that still carries `part.texture`. Texture/atlas state is non-undoable
|
|
@@ -1081,6 +1082,19 @@ interface CustomPart {
|
|
|
1081
1082
|
/** The art does not bend (a hairpin, a ribbon): a bake that bends it more
|
|
1082
1083
|
* than 0.0025 face widths at a stop is refused (`BakeError`). */
|
|
1083
1084
|
rigid?: boolean;
|
|
1085
|
+
/** Hide the part where the parts of these roles cover it, by an amount keyed on a
|
|
1086
|
+
* parameter (`IkiPart.occlusion`). `by` lists roles of the set: the
|
|
1087
|
+
* generator writes the part ids those roles yield. The parameter is one
|
|
1088
|
+
* the model declares and not a physics output; the stops follow the
|
|
1089
|
+
* format's rules. */
|
|
1090
|
+
occlusion?: {
|
|
1091
|
+
by: string[];
|
|
1092
|
+
parameter: string;
|
|
1093
|
+
stops: {
|
|
1094
|
+
value: number;
|
|
1095
|
+
amount: number;
|
|
1096
|
+
}[];
|
|
1097
|
+
};
|
|
1084
1098
|
}
|
|
1085
1099
|
/** A `customParts` entry that is malformed or misses the layer set. Its
|
|
1086
1100
|
* message starts `customParts[i].<field>` (`customParts` alone for a
|
|
@@ -1917,10 +1931,11 @@ declare function validateDeformerReparent(deformers: IkiDeformer[], deformerId:
|
|
|
1917
1931
|
* `toIkiModel()` refuses.
|
|
1918
1932
|
*
|
|
1919
1933
|
* Note: there is no validatePartDelete here, but NOT because parts are
|
|
1920
|
-
* unreferenced — `clip.masks`
|
|
1921
|
-
* closer to the edits that could break it: `DeletePart`
|
|
1922
|
-
* part still used as a mask
|
|
1923
|
-
* one (
|
|
1934
|
+
* unreferenced — `clip.masks` and `occlusion.by` name parts by id. That
|
|
1935
|
+
* invariant is enforced closer to the edits that could break it: `DeletePart`
|
|
1936
|
+
* refuses to remove a part still used as a mask or an occluder, and
|
|
1937
|
+
* `SetPartMesh` refuses to strip the mesh off one (both must be mesh parts).
|
|
1938
|
+
* No command creates or edits `clip` or `occlusion`.
|
|
1924
1939
|
*/
|
|
1925
1940
|
declare function validateDeformerDelete(deformers: IkiDeformer[], parts: IkiPart[], physicsChains: IkiPhysicsChain[], deformerId: string): void;
|
|
1926
1941
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -251,10 +251,11 @@ declare class AddDeformer implements EditCommand {
|
|
|
251
251
|
* visually predictable.
|
|
252
252
|
*
|
|
253
253
|
* No `parseIkiModel` pre-check is needed: removing an element from an already-
|
|
254
|
-
* valid model cannot introduce a structural violation — EXCEPT for
|
|
255
|
-
* references
|
|
256
|
-
* delete a part still used as another part's `clip.masks`
|
|
257
|
-
* so it can never leave a dangling
|
|
254
|
+
* valid model cannot introduce a structural violation — EXCEPT for the part→part
|
|
255
|
+
* references in the contract: `clip.masks` and `occlusion.by`. `apply` refuses to
|
|
256
|
+
* delete a part still used as another part's `clip.masks` or `occlusion.by`
|
|
257
|
+
* entry (guards below), so it can never leave a dangling ref that would fail
|
|
258
|
+
* `toIkiModel()`.
|
|
258
259
|
*
|
|
259
260
|
* Texture-reference safety (package invariant): `apply` refuses to delete a
|
|
260
261
|
* part that still carries `part.texture`. Texture/atlas state is non-undoable
|
|
@@ -1081,6 +1082,19 @@ interface CustomPart {
|
|
|
1081
1082
|
/** The art does not bend (a hairpin, a ribbon): a bake that bends it more
|
|
1082
1083
|
* than 0.0025 face widths at a stop is refused (`BakeError`). */
|
|
1083
1084
|
rigid?: boolean;
|
|
1085
|
+
/** Hide the part where the parts of these roles cover it, by an amount keyed on a
|
|
1086
|
+
* parameter (`IkiPart.occlusion`). `by` lists roles of the set: the
|
|
1087
|
+
* generator writes the part ids those roles yield. The parameter is one
|
|
1088
|
+
* the model declares and not a physics output; the stops follow the
|
|
1089
|
+
* format's rules. */
|
|
1090
|
+
occlusion?: {
|
|
1091
|
+
by: string[];
|
|
1092
|
+
parameter: string;
|
|
1093
|
+
stops: {
|
|
1094
|
+
value: number;
|
|
1095
|
+
amount: number;
|
|
1096
|
+
}[];
|
|
1097
|
+
};
|
|
1084
1098
|
}
|
|
1085
1099
|
/** A `customParts` entry that is malformed or misses the layer set. Its
|
|
1086
1100
|
* message starts `customParts[i].<field>` (`customParts` alone for a
|
|
@@ -1917,10 +1931,11 @@ declare function validateDeformerReparent(deformers: IkiDeformer[], deformerId:
|
|
|
1917
1931
|
* `toIkiModel()` refuses.
|
|
1918
1932
|
*
|
|
1919
1933
|
* Note: there is no validatePartDelete here, but NOT because parts are
|
|
1920
|
-
* unreferenced — `clip.masks`
|
|
1921
|
-
* closer to the edits that could break it: `DeletePart`
|
|
1922
|
-
* part still used as a mask
|
|
1923
|
-
* one (
|
|
1934
|
+
* unreferenced — `clip.masks` and `occlusion.by` name parts by id. That
|
|
1935
|
+
* invariant is enforced closer to the edits that could break it: `DeletePart`
|
|
1936
|
+
* refuses to remove a part still used as a mask or an occluder, and
|
|
1937
|
+
* `SetPartMesh` refuses to strip the mesh off one (both must be mesh parts).
|
|
1938
|
+
* No command creates or edits `clip` or `occlusion`.
|
|
1924
1939
|
*/
|
|
1925
1940
|
declare function validateDeformerDelete(deformers: IkiDeformer[], parts: IkiPart[], physicsChains: IkiPhysicsChain[], deformerId: string): void;
|
|
1926
1941
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1115,6 +1115,14 @@ var DeletePart = class {
|
|
|
1115
1115
|
`parts."${this.partId}": cannot delete \u2014 used as a clip mask by part "${masker.id}"; remove its clip first`
|
|
1116
1116
|
);
|
|
1117
1117
|
}
|
|
1118
|
+
const occluded = parts.find(
|
|
1119
|
+
(p) => p.id !== this.partId && p.occlusion?.by.includes(this.partId)
|
|
1120
|
+
);
|
|
1121
|
+
if (occluded) {
|
|
1122
|
+
throw new Error(
|
|
1123
|
+
`parts."${this.partId}": cannot delete \u2014 used as an occluder by part "${occluded.id}"; remove its occlusion first`
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1118
1126
|
const i = parts.indexOf(part);
|
|
1119
1127
|
if (!this.captured) {
|
|
1120
1128
|
this.removed = structuredClone(part);
|
|
@@ -1319,6 +1327,14 @@ var SetPartMesh = class {
|
|
|
1319
1327
|
`parts."${this.partId}": cannot remove mesh \u2014 used as a clip mask by part "${masker.id}" (masks require a mesh); remove its clip first`
|
|
1320
1328
|
);
|
|
1321
1329
|
}
|
|
1330
|
+
const occluded = doc.getModel().parts.find(
|
|
1331
|
+
(p) => p.id !== this.partId && p.occlusion?.by.includes(this.partId)
|
|
1332
|
+
);
|
|
1333
|
+
if (occluded) {
|
|
1334
|
+
throw new import_format2.IkiFormatError(
|
|
1335
|
+
`parts."${this.partId}": cannot remove mesh \u2014 used as an occluder by part "${occluded.id}" (occluders require a mesh); remove its occlusion first`
|
|
1336
|
+
);
|
|
1337
|
+
}
|
|
1322
1338
|
} else {
|
|
1323
1339
|
if ((part.warps?.length ?? 0) > 0) {
|
|
1324
1340
|
throw new import_format2.IkiFormatError(
|
|
@@ -1398,6 +1414,14 @@ function validatePhysicsCandidate(doc, candidatePhysics) {
|
|
|
1398
1414
|
}
|
|
1399
1415
|
throw e;
|
|
1400
1416
|
}
|
|
1417
|
+
for (const rig of candidatePhysics) {
|
|
1418
|
+
const part = doc.getModel().parts.find((p) => p.occlusion?.parameter === rig.output.parameter);
|
|
1419
|
+
if (part !== void 0) {
|
|
1420
|
+
throw new import_format2.IkiFormatError(
|
|
1421
|
+
`physics."${rig.id}".output.parameter "${rig.output.parameter}" keys parts."${part.id}".occlusion; an occlusion amount cannot be keyed on a physics output`
|
|
1422
|
+
);
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1401
1425
|
}
|
|
1402
1426
|
var AddPhysicsRig = class {
|
|
1403
1427
|
label = "Add physics rig";
|
|
@@ -2040,7 +2064,8 @@ var PROFILE_VALUES = {
|
|
|
2040
2064
|
hairFollow: 1,
|
|
2041
2065
|
fore: 0.2,
|
|
2042
2066
|
backShare: 0.1,
|
|
2043
|
-
earFar: 0
|
|
2067
|
+
earFar: 0,
|
|
2068
|
+
earFore: 0.1,
|
|
2044
2069
|
nodDown: 0.18,
|
|
2045
2070
|
nodUp: 0.1,
|
|
2046
2071
|
nodLead: 0.06,
|
|
@@ -2107,7 +2132,7 @@ function deriveProfile(v) {
|
|
|
2107
2132
|
earNear: 1,
|
|
2108
2133
|
/** The far ear's width at full turn, about its outer edge, where the head
|
|
2109
2134
|
* leaves it room; less where it does not. */
|
|
2110
|
-
earFarScale: 1 - v.
|
|
2135
|
+
earFarScale: 1 - v.earFore
|
|
2111
2136
|
};
|
|
2112
2137
|
const mid = v.nodDown * (1 + v.chinShare) / 2;
|
|
2113
2138
|
const feature = (depth) => ({
|
|
@@ -7132,7 +7157,18 @@ function span2(name, v) {
|
|
|
7132
7157
|
}
|
|
7133
7158
|
|
|
7134
7159
|
// src/auto-rig/custom-parts.ts
|
|
7135
|
-
var KEYS = [
|
|
7160
|
+
var KEYS = [
|
|
7161
|
+
"id",
|
|
7162
|
+
"layer",
|
|
7163
|
+
"anchor",
|
|
7164
|
+
"tie",
|
|
7165
|
+
"after",
|
|
7166
|
+
"deformer",
|
|
7167
|
+
"rigid",
|
|
7168
|
+
"occlusion"
|
|
7169
|
+
];
|
|
7170
|
+
var OCCLUSION_KEYS = ["by", "parameter", "stops"];
|
|
7171
|
+
var STOP_KEYS = ["value", "amount"];
|
|
7136
7172
|
var LAYER_KEYS = ["fileName", "bbox"];
|
|
7137
7173
|
var finite4 = (v) => typeof v === "number" && Number.isFinite(v);
|
|
7138
7174
|
var isObject3 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
@@ -7140,7 +7176,7 @@ var inside = (b, [x, y]) => x >= b.x && x < b.x + b.w && y >= b.y && y < b.y + b
|
|
|
7140
7176
|
var RESERVED = new Set(
|
|
7141
7177
|
ROLE_TABLE.flatMap((r) => [r.role, ...partIdsOfRole(r.role)])
|
|
7142
7178
|
);
|
|
7143
|
-
function checkCustomParts(customParts, byRole, canvas) {
|
|
7179
|
+
function checkCustomParts(customParts, byRole, canvas, parameters, physicsOutputs) {
|
|
7144
7180
|
if (!Array.isArray(customParts)) {
|
|
7145
7181
|
throw new CustomPartError(
|
|
7146
7182
|
`customParts must be an array, got ${customParts === null ? "null" : typeof customParts}`
|
|
@@ -7163,7 +7199,7 @@ function checkCustomParts(customParts, byRole, canvas) {
|
|
|
7163
7199
|
throw new CustomPartError(`${at} must be a plain object`);
|
|
7164
7200
|
}
|
|
7165
7201
|
checkedKeys(at, entry, KEYS, CustomPartError);
|
|
7166
|
-
const { id, layer, anchor, tie, after, deformer, rigid } = entry;
|
|
7202
|
+
const { id, layer, anchor, tie, after, deformer, rigid, occlusion } = entry;
|
|
7167
7203
|
if (typeof id !== "string" || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(id)) {
|
|
7168
7204
|
throw new CustomPartError(
|
|
7169
7205
|
`${at}.id must be a plain identifier (letters, digits, underscore; not starting with a digit), got ${JSON.stringify(id)}`
|
|
@@ -7214,9 +7250,84 @@ function checkCustomParts(customParts, byRole, canvas) {
|
|
|
7214
7250
|
`${at}.rigid must be true or false, got ${JSON.stringify(rigid)}`
|
|
7215
7251
|
);
|
|
7216
7252
|
}
|
|
7253
|
+
if (occlusion !== void 0) {
|
|
7254
|
+
checkOcclusion(
|
|
7255
|
+
`${at}.occlusion`,
|
|
7256
|
+
occlusion,
|
|
7257
|
+
present,
|
|
7258
|
+
parameters,
|
|
7259
|
+
physicsOutputs
|
|
7260
|
+
);
|
|
7261
|
+
}
|
|
7217
7262
|
});
|
|
7218
7263
|
return customParts;
|
|
7219
7264
|
}
|
|
7265
|
+
function checkOcclusion(at, occlusion, present, parameters, physicsOutputs) {
|
|
7266
|
+
if (!isObject3(occlusion)) {
|
|
7267
|
+
throw new CustomPartError(`${at} must be a plain object`);
|
|
7268
|
+
}
|
|
7269
|
+
checkedKeys(at, occlusion, OCCLUSION_KEYS, CustomPartError);
|
|
7270
|
+
const { by, parameter, stops } = occlusion;
|
|
7271
|
+
if (!Array.isArray(by) || by.length === 0) {
|
|
7272
|
+
throw new CustomPartError(
|
|
7273
|
+
`${at}.by must be a non-empty array of roles of the set, one of ${present.join(", ")}`
|
|
7274
|
+
);
|
|
7275
|
+
}
|
|
7276
|
+
by.forEach((role, j) => {
|
|
7277
|
+
if (typeof role !== "string" || !present.includes(role)) {
|
|
7278
|
+
throw new CustomPartError(
|
|
7279
|
+
`${at}.by[${j}] must be a role of the set, one of ${present.join(", ")}; got ${JSON.stringify(role)}`
|
|
7280
|
+
);
|
|
7281
|
+
}
|
|
7282
|
+
if (by.indexOf(role) !== j) {
|
|
7283
|
+
throw new CustomPartError(
|
|
7284
|
+
`${at}.by[${j}] "${role}" repeats an earlier role`
|
|
7285
|
+
);
|
|
7286
|
+
}
|
|
7287
|
+
});
|
|
7288
|
+
const descriptor = parameters.find((p) => p.id === parameter);
|
|
7289
|
+
if (typeof parameter !== "string" || descriptor === void 0) {
|
|
7290
|
+
throw new CustomPartError(
|
|
7291
|
+
`${at}.parameter must be a parameter the rig declares, got ${JSON.stringify(parameter)}`
|
|
7292
|
+
);
|
|
7293
|
+
}
|
|
7294
|
+
if (physicsOutputs.has(parameter)) {
|
|
7295
|
+
throw new CustomPartError(
|
|
7296
|
+
`${at}.parameter "${parameter}" is a physics output; an occlusion amount cannot be keyed on one`
|
|
7297
|
+
);
|
|
7298
|
+
}
|
|
7299
|
+
if (!Array.isArray(stops) || stops.length === 0) {
|
|
7300
|
+
throw new CustomPartError(`${at}.stops must be a non-empty array`);
|
|
7301
|
+
}
|
|
7302
|
+
const { min, max } = descriptor;
|
|
7303
|
+
let previous = -Infinity;
|
|
7304
|
+
stops.forEach((stop, k) => {
|
|
7305
|
+
const s = `${at}.stops[${k}]`;
|
|
7306
|
+
if (!isObject3(stop))
|
|
7307
|
+
throw new CustomPartError(`${s} must be a plain object`);
|
|
7308
|
+
checkedKeys(s, stop, STOP_KEYS, CustomPartError);
|
|
7309
|
+
const { value, amount } = stop;
|
|
7310
|
+
if (!finite4(value)) {
|
|
7311
|
+
throw new CustomPartError(
|
|
7312
|
+
`${s}.value must be a finite number, got ${JSON.stringify(value)}`
|
|
7313
|
+
);
|
|
7314
|
+
}
|
|
7315
|
+
if (value < min || value > max) {
|
|
7316
|
+
throw new CustomPartError(
|
|
7317
|
+
`${s}.value ${value} is outside parameter "${parameter}" range [${min},${max}]`
|
|
7318
|
+
);
|
|
7319
|
+
}
|
|
7320
|
+
if (value <= previous) {
|
|
7321
|
+
throw new CustomPartError(`${s}.value must be strictly ascending`);
|
|
7322
|
+
}
|
|
7323
|
+
previous = value;
|
|
7324
|
+
if (!finite4(amount) || amount < 0 || amount > 1) {
|
|
7325
|
+
throw new CustomPartError(
|
|
7326
|
+
`${s}.amount must be a number in 0..1, got ${JSON.stringify(amount)}`
|
|
7327
|
+
);
|
|
7328
|
+
}
|
|
7329
|
+
});
|
|
7330
|
+
}
|
|
7220
7331
|
var CELL_PX2 = 20;
|
|
7221
7332
|
function buildCustomParts(customParts, canvas) {
|
|
7222
7333
|
return customParts.map(({ id, layer }) => {
|
|
@@ -7236,6 +7347,32 @@ function buildCustomParts(customParts, canvas) {
|
|
|
7236
7347
|
};
|
|
7237
7348
|
});
|
|
7238
7349
|
}
|
|
7350
|
+
function writeOcclusion(customParts, built, parts) {
|
|
7351
|
+
const byId = new Map(parts.map((p) => [p.id, p]));
|
|
7352
|
+
customParts.forEach((entry, i) => {
|
|
7353
|
+
if (entry.occlusion === void 0) return;
|
|
7354
|
+
const { by, parameter, stops } = entry.occlusion;
|
|
7355
|
+
const ids = [];
|
|
7356
|
+
by.forEach((role, j) => {
|
|
7357
|
+
for (const id of partIdsOfRole(role)) {
|
|
7358
|
+
const part = byId.get(id);
|
|
7359
|
+
if (part === void 0) continue;
|
|
7360
|
+
const fault = part.clip !== void 0 ? { is: "is clipped", kind: "a clipped part" } : part.mesh === void 0 ? { is: "has no mesh", kind: "a part without a mesh" } : void 0;
|
|
7361
|
+
if (fault !== void 0) {
|
|
7362
|
+
throw new CustomPartError(
|
|
7363
|
+
`customParts[${i}].occlusion.by[${j}] "${role}" yields part "${id}", which ${fault.is}; ${fault.kind} cannot occlude`
|
|
7364
|
+
);
|
|
7365
|
+
}
|
|
7366
|
+
ids.push(id);
|
|
7367
|
+
}
|
|
7368
|
+
});
|
|
7369
|
+
built[i].occlusion = {
|
|
7370
|
+
by: ids,
|
|
7371
|
+
parameter,
|
|
7372
|
+
stops: stops.map((s) => ({ value: s.value, amount: s.amount }))
|
|
7373
|
+
};
|
|
7374
|
+
});
|
|
7375
|
+
}
|
|
7239
7376
|
|
|
7240
7377
|
// src/auto-rig/generate.ts
|
|
7241
7378
|
var MESH_CELLS = {
|
|
@@ -7278,8 +7415,15 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
|
7278
7415
|
const hasNose = has("nose");
|
|
7279
7416
|
const plateHalf = byRole.get("face").cropW / 2;
|
|
7280
7417
|
checkHeadEdges(options.headEdges, byRole);
|
|
7281
|
-
const
|
|
7418
|
+
const physics = has("hair_front") ? hairPhysics(has("hair_back")) : void 0;
|
|
7282
7419
|
const parameters = declareParameters(new Set(byRole.keys()));
|
|
7420
|
+
const entries = options.customParts !== void 0 && !(Array.isArray(options.customParts) && options.customParts.length === 0) ? checkCustomParts(
|
|
7421
|
+
options.customParts,
|
|
7422
|
+
byRole,
|
|
7423
|
+
canvas,
|
|
7424
|
+
parameters,
|
|
7425
|
+
new Set((physics ?? []).map((r) => r.output.parameter))
|
|
7426
|
+
) : [];
|
|
7283
7427
|
const bakes = options.bakes === void 0 ? void 0 : parseBakes(options.bakes, entries, parameters);
|
|
7284
7428
|
checkStrandEdges(
|
|
7285
7429
|
options.strandEdges,
|
|
@@ -7460,6 +7604,7 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
|
7460
7604
|
parts.forEach((p, i) => {
|
|
7461
7605
|
p.order = i;
|
|
7462
7606
|
});
|
|
7607
|
+
writeOcclusion(entries, built, parts);
|
|
7463
7608
|
if (bakes !== void 0) {
|
|
7464
7609
|
bakeReports = applyBakes(bakes, built, entries, {
|
|
7465
7610
|
canvas,
|
|
@@ -7476,7 +7621,7 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
|
7476
7621
|
parameters,
|
|
7477
7622
|
parts,
|
|
7478
7623
|
deformers: deformerList,
|
|
7479
|
-
...
|
|
7624
|
+
...physics !== void 0 ? { physics } : {},
|
|
7480
7625
|
expressions: defaultExpressions(new Set(parameters.map((p) => p.id))),
|
|
7481
7626
|
motions: defaultMotions(new Set(parameters.map((p) => p.id)))
|
|
7482
7627
|
};
|