@ikijs/editor 0.18.0 → 0.19.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 +3 -3
- package/dist/index.d.mts +44 -21
- package/dist/index.d.ts +44 -21
- package/dist/index.js +85 -27
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +85 -27
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -82,9 +82,9 @@ it), the ears lag the face, the far one narrowing. AngleZ rolls the head 14° ab
|
|
|
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
|
|
85
|
-
shoulder at the top, hang from it too: each becomes an
|
|
86
|
-
forearm cut from the one crop, turning about the shoulder and the
|
|
87
|
-
`ParamArmL/R` and `ParamElbowL/R`. An arm needs a `body`.
|
|
85
|
+
shoulder at the top, hang from it too: each becomes an elbow cap, an upper
|
|
86
|
+
arm and a forearm cut from the one crop, turning about the shoulder and the
|
|
87
|
+
elbow on `ParamArmL/R` and `ParamElbowL/R`. An arm needs a `body`.
|
|
88
88
|
|
|
89
89
|
On a layer set with a `nose`, `options.turnTargets` — the cues a 30° reference
|
|
90
90
|
measures (how far the eye pair slides, how much the far eye foreshortens,
|
package/dist/index.d.mts
CHANGED
|
@@ -857,31 +857,43 @@ interface GenerateOptions {
|
|
|
857
857
|
|
|
858
858
|
/**
|
|
859
859
|
* The arms. Each `arm_L` / `arm_R` layer is one drawing of the whole arm,
|
|
860
|
-
* hanging, its shoulder at the top. It becomes
|
|
861
|
-
* deformers hung from the body warp:
|
|
860
|
+
* hanging, its shoulder at the top. It becomes three parts on two nested
|
|
861
|
+
* matrix deformers hung from the body warp:
|
|
862
862
|
* - the upper arm (the role's own id) on `armDeformer_X`, which turns about
|
|
863
863
|
* the shoulder, the deltoid cap's centre;
|
|
864
864
|
* - the forearm (`forearm_X`) on `forearmDeformer_X`, a child of the arm's,
|
|
865
|
-
* which turns about the elbow
|
|
865
|
+
* which turns about the elbow;
|
|
866
|
+
* - the elbow cap (`elbow_X`), also on `forearmDeformer_X`, drawn behind the
|
|
867
|
+
* upper arm.
|
|
866
868
|
* The shoulder pivot rides an all-weight-1 cell of the body warp (`body.ts`),
|
|
867
869
|
* so the arm breathes and turns with the chest rigidly, never sheared.
|
|
868
870
|
*
|
|
869
|
-
*
|
|
870
|
-
* texture rect
|
|
871
|
-
*
|
|
872
|
-
*
|
|
873
|
-
*
|
|
874
|
-
*
|
|
875
|
-
*
|
|
871
|
+
* All three parts are cut from the one crop: they share its box, transform
|
|
872
|
+
* and texture rect. The upper arm is the band above the seam, the elbow
|
|
873
|
+
* pivot's row; the forearm is the band below it. Iki has no glue between
|
|
874
|
+
* meshes, and two bands hinged at a seam open a wedge as wide as the arm on a
|
|
875
|
+
* bend. The cap fills it: a half-disc fan centred on the elbow pivot turns
|
|
876
|
+
* about its own centre, so it rotates into itself and keeps the joint covered
|
|
877
|
+
* at any bend.
|
|
876
878
|
*
|
|
877
|
-
*
|
|
878
|
-
*
|
|
879
|
-
*
|
|
879
|
+
* Behind the upper arm, the cap shows only where the forearm's bend uncovers
|
|
880
|
+
* it, so it must lie inside the paint at rest, or its edge would show past
|
|
881
|
+
* the arm's. Its boundary is therefore the arm's own contour, not a circle:
|
|
882
|
+
* `armGeometry` walks each of the fan's 13 rays out from the elbow to the
|
|
883
|
+
* contour (`capRays`). A ring at the boundary, `CAP_RIM` wide, takes the UVs
|
|
884
|
+
* of the seam row's edge cross-section swept round the arc, so the exposed
|
|
885
|
+
* wedge carries the painted line, fading out in the antialias column as the
|
|
886
|
+
* painted edge does; the fan inside it is the crop's own pixels.
|
|
880
887
|
*
|
|
881
|
-
*
|
|
882
|
-
*
|
|
883
|
-
*
|
|
884
|
-
*
|
|
888
|
+
* Draw order: hair_back < body < elbow_L, arm_L, forearm_L, elbow_R, arm_R,
|
|
889
|
+
* forearm_R < face … < hair_front. The forearm draws over the upper arm,
|
|
890
|
+
* which draws over the cap.
|
|
891
|
+
*
|
|
892
|
+
* Signs: ParamArmX + raises the arm outward on either side, in degrees 1:1.
|
|
893
|
+
* A rotation is CCW-positive, so an arm whose shoulder lies right of the
|
|
894
|
+
* body's axis (+x, the character's left) turns CCW for +, and one at −x turns
|
|
895
|
+
* CW. ParamElbowX + bends the forearm toward the body, the opposite turn to
|
|
896
|
+
* the shoulder's +: it turns CW on the +x side, CCW on the −x side.
|
|
885
897
|
*/
|
|
886
898
|
|
|
887
899
|
type Point = {
|
|
@@ -895,8 +907,14 @@ interface ArmGeometry {
|
|
|
895
907
|
shoulderRadius: number;
|
|
896
908
|
/** The elbow pivot, model space. Its y is the seam the two meshes meet on. */
|
|
897
909
|
elbow: Point;
|
|
898
|
-
/** The
|
|
910
|
+
/** The elbow cap's largest radius, px. */
|
|
899
911
|
capRadius: number;
|
|
912
|
+
/** The cap's radius on each of its `CAP_SEGMENTS + 1` rays, from the elbow
|
|
913
|
+
* at angles 0..π, px: the walk out to the contour, less `capInset`, at
|
|
914
|
+
* most `capRadius`. */
|
|
915
|
+
capRays: number[];
|
|
916
|
+
/** The seam row's widest run, crop columns [start, end). */
|
|
917
|
+
seamRun: [number, number];
|
|
900
918
|
/** +1 for a shoulder right of the body's axis (+ turns CCW), −1 left of it
|
|
901
919
|
* (+ turns CW). */
|
|
902
920
|
side: 1 | -1;
|
|
@@ -910,7 +928,12 @@ interface ArmGeometry {
|
|
|
910
928
|
* run centre of the row it lands in;
|
|
911
929
|
* - the elbow is the centre of the row `ELBOW_AT` of the way from there to
|
|
912
930
|
* the last painted row, at its run centre;
|
|
913
|
-
* - the cap radius is half the elbow's run + 1 px, kept inside the crop
|
|
931
|
+
* - the cap radius is half the elbow's run + 1 px, kept inside the crop;
|
|
932
|
+
* - each cap ray walks 1 px at a time from the elbow until it leaves the
|
|
933
|
+
* widest run of the crop row it is in (strictly inside: `start < x < end`,
|
|
934
|
+
* on canvas columns, the row the floor of the canvas y), then stops
|
|
935
|
+
* `capInset(i)` short of that exit (none on the two seam-end rays, 2 px on
|
|
936
|
+
* the next, `CAP_INSET` on the rest), and at `capRadius`.
|
|
914
937
|
* Pivots are on the 0.01 grid, as the written model is. `bodyAxisX` is the
|
|
915
938
|
* body's axis, model x: the shoulder's side of it sets the sign. An arm too
|
|
916
939
|
* short for its width to put the elbow under the shoulder would rig
|
|
@@ -938,8 +961,8 @@ declare function parseLayerRoles(fileNames: string[]): {
|
|
|
938
961
|
* (`body.ts`) that breathes, follows the head's turn and tilt a little and
|
|
939
962
|
* turns on BodyAngleX/Y/Z, its legs planted; a head deformer hung from it
|
|
940
963
|
* that rolls about the chin and breathes; each arm hung from it too, as an
|
|
941
|
-
* upper arm
|
|
942
|
-
* (`arms.ts`); one small warp grid per feature
|
|
964
|
+
* upper arm, a forearm and an elbow cap turning about the shoulder and the
|
|
965
|
+
* elbow (`arms.ts`); one small warp grid per feature
|
|
943
966
|
* (each eye, each brow, the nose, the mouth), translating and foreshortening
|
|
944
967
|
* it by its own lead over the plate; and the plate, the hair and the blush
|
|
945
968
|
* moved by per-vertex keyforms of their own — the plate as up to four
|
package/dist/index.d.ts
CHANGED
|
@@ -857,31 +857,43 @@ interface GenerateOptions {
|
|
|
857
857
|
|
|
858
858
|
/**
|
|
859
859
|
* The arms. Each `arm_L` / `arm_R` layer is one drawing of the whole arm,
|
|
860
|
-
* hanging, its shoulder at the top. It becomes
|
|
861
|
-
* deformers hung from the body warp:
|
|
860
|
+
* hanging, its shoulder at the top. It becomes three parts on two nested
|
|
861
|
+
* matrix deformers hung from the body warp:
|
|
862
862
|
* - the upper arm (the role's own id) on `armDeformer_X`, which turns about
|
|
863
863
|
* the shoulder, the deltoid cap's centre;
|
|
864
864
|
* - the forearm (`forearm_X`) on `forearmDeformer_X`, a child of the arm's,
|
|
865
|
-
* which turns about the elbow
|
|
865
|
+
* which turns about the elbow;
|
|
866
|
+
* - the elbow cap (`elbow_X`), also on `forearmDeformer_X`, drawn behind the
|
|
867
|
+
* upper arm.
|
|
866
868
|
* The shoulder pivot rides an all-weight-1 cell of the body warp (`body.ts`),
|
|
867
869
|
* so the arm breathes and turns with the chest rigidly, never sheared.
|
|
868
870
|
*
|
|
869
|
-
*
|
|
870
|
-
* texture rect
|
|
871
|
-
*
|
|
872
|
-
*
|
|
873
|
-
*
|
|
874
|
-
*
|
|
875
|
-
*
|
|
871
|
+
* All three parts are cut from the one crop: they share its box, transform
|
|
872
|
+
* and texture rect. The upper arm is the band above the seam, the elbow
|
|
873
|
+
* pivot's row; the forearm is the band below it. Iki has no glue between
|
|
874
|
+
* meshes, and two bands hinged at a seam open a wedge as wide as the arm on a
|
|
875
|
+
* bend. The cap fills it: a half-disc fan centred on the elbow pivot turns
|
|
876
|
+
* about its own centre, so it rotates into itself and keeps the joint covered
|
|
877
|
+
* at any bend.
|
|
876
878
|
*
|
|
877
|
-
*
|
|
878
|
-
*
|
|
879
|
-
*
|
|
879
|
+
* Behind the upper arm, the cap shows only where the forearm's bend uncovers
|
|
880
|
+
* it, so it must lie inside the paint at rest, or its edge would show past
|
|
881
|
+
* the arm's. Its boundary is therefore the arm's own contour, not a circle:
|
|
882
|
+
* `armGeometry` walks each of the fan's 13 rays out from the elbow to the
|
|
883
|
+
* contour (`capRays`). A ring at the boundary, `CAP_RIM` wide, takes the UVs
|
|
884
|
+
* of the seam row's edge cross-section swept round the arc, so the exposed
|
|
885
|
+
* wedge carries the painted line, fading out in the antialias column as the
|
|
886
|
+
* painted edge does; the fan inside it is the crop's own pixels.
|
|
880
887
|
*
|
|
881
|
-
*
|
|
882
|
-
*
|
|
883
|
-
*
|
|
884
|
-
*
|
|
888
|
+
* Draw order: hair_back < body < elbow_L, arm_L, forearm_L, elbow_R, arm_R,
|
|
889
|
+
* forearm_R < face … < hair_front. The forearm draws over the upper arm,
|
|
890
|
+
* which draws over the cap.
|
|
891
|
+
*
|
|
892
|
+
* Signs: ParamArmX + raises the arm outward on either side, in degrees 1:1.
|
|
893
|
+
* A rotation is CCW-positive, so an arm whose shoulder lies right of the
|
|
894
|
+
* body's axis (+x, the character's left) turns CCW for +, and one at −x turns
|
|
895
|
+
* CW. ParamElbowX + bends the forearm toward the body, the opposite turn to
|
|
896
|
+
* the shoulder's +: it turns CW on the +x side, CCW on the −x side.
|
|
885
897
|
*/
|
|
886
898
|
|
|
887
899
|
type Point = {
|
|
@@ -895,8 +907,14 @@ interface ArmGeometry {
|
|
|
895
907
|
shoulderRadius: number;
|
|
896
908
|
/** The elbow pivot, model space. Its y is the seam the two meshes meet on. */
|
|
897
909
|
elbow: Point;
|
|
898
|
-
/** The
|
|
910
|
+
/** The elbow cap's largest radius, px. */
|
|
899
911
|
capRadius: number;
|
|
912
|
+
/** The cap's radius on each of its `CAP_SEGMENTS + 1` rays, from the elbow
|
|
913
|
+
* at angles 0..π, px: the walk out to the contour, less `capInset`, at
|
|
914
|
+
* most `capRadius`. */
|
|
915
|
+
capRays: number[];
|
|
916
|
+
/** The seam row's widest run, crop columns [start, end). */
|
|
917
|
+
seamRun: [number, number];
|
|
900
918
|
/** +1 for a shoulder right of the body's axis (+ turns CCW), −1 left of it
|
|
901
919
|
* (+ turns CW). */
|
|
902
920
|
side: 1 | -1;
|
|
@@ -910,7 +928,12 @@ interface ArmGeometry {
|
|
|
910
928
|
* run centre of the row it lands in;
|
|
911
929
|
* - the elbow is the centre of the row `ELBOW_AT` of the way from there to
|
|
912
930
|
* the last painted row, at its run centre;
|
|
913
|
-
* - the cap radius is half the elbow's run + 1 px, kept inside the crop
|
|
931
|
+
* - the cap radius is half the elbow's run + 1 px, kept inside the crop;
|
|
932
|
+
* - each cap ray walks 1 px at a time from the elbow until it leaves the
|
|
933
|
+
* widest run of the crop row it is in (strictly inside: `start < x < end`,
|
|
934
|
+
* on canvas columns, the row the floor of the canvas y), then stops
|
|
935
|
+
* `capInset(i)` short of that exit (none on the two seam-end rays, 2 px on
|
|
936
|
+
* the next, `CAP_INSET` on the rest), and at `capRadius`.
|
|
914
937
|
* Pivots are on the 0.01 grid, as the written model is. `bodyAxisX` is the
|
|
915
938
|
* body's axis, model x: the shoulder's side of it sets the sign. An arm too
|
|
916
939
|
* short for its width to put the elbow under the shoulder would rig
|
|
@@ -938,8 +961,8 @@ declare function parseLayerRoles(fileNames: string[]): {
|
|
|
938
961
|
* (`body.ts`) that breathes, follows the head's turn and tilt a little and
|
|
939
962
|
* turns on BodyAngleX/Y/Z, its legs planted; a head deformer hung from it
|
|
940
963
|
* that rolls about the chin and breathes; each arm hung from it too, as an
|
|
941
|
-
* upper arm
|
|
942
|
-
* (`arms.ts`); one small warp grid per feature
|
|
964
|
+
* upper arm, a forearm and an elbow cap turning about the shoulder and the
|
|
965
|
+
* elbow (`arms.ts`); one small warp grid per feature
|
|
943
966
|
* (each eye, each brow, the nose, the mouth), translating and foreshortening
|
|
944
967
|
* it by its own lead over the plate; and the plate, the hair and the blush
|
|
945
968
|
* moved by per-vertex keyforms of their own — the plate as up to four
|
package/dist/index.js
CHANGED
|
@@ -2754,7 +2754,11 @@ function headOwnBreath(hasBody) {
|
|
|
2754
2754
|
var ELBOW_AT = 0.42;
|
|
2755
2755
|
var CAP_ROWS = [0.1, 0.3];
|
|
2756
2756
|
var CAP_SEGMENTS = 12;
|
|
2757
|
-
var
|
|
2757
|
+
var CAP_INSET = 3;
|
|
2758
|
+
var capInset = (i) => Math.round(CAP_INSET * Math.min(1, Math.min(i, CAP_SEGMENTS - i) / 2));
|
|
2759
|
+
var CAP_RIM = 0.25;
|
|
2760
|
+
var ARM_RANGE = [-8, 32];
|
|
2761
|
+
var ELBOW_RANGE = [-10, 90];
|
|
2758
2762
|
var ARM_PARAMS = {
|
|
2759
2763
|
arm_L: { arm: import_format5.StandardParameter.ArmLeft, elbow: import_format5.StandardParameter.ElbowLeft },
|
|
2760
2764
|
arm_R: { arm: import_format5.StandardParameter.ArmRight, elbow: import_format5.StandardParameter.ElbowRight }
|
|
@@ -2762,11 +2766,13 @@ var ARM_PARAMS = {
|
|
|
2762
2766
|
var ARM_IDS = {
|
|
2763
2767
|
arm_L: {
|
|
2764
2768
|
forearm: "forearm_L",
|
|
2769
|
+
cap: "elbow_L",
|
|
2765
2770
|
armDeformer: "armDeformer_L",
|
|
2766
2771
|
forearmDeformer: "forearmDeformer_L"
|
|
2767
2772
|
},
|
|
2768
2773
|
arm_R: {
|
|
2769
2774
|
forearm: "forearm_R",
|
|
2775
|
+
cap: "elbow_R",
|
|
2770
2776
|
armDeformer: "armDeformer_R",
|
|
2771
2777
|
forearmDeformer: "forearmDeformer_R"
|
|
2772
2778
|
}
|
|
@@ -2819,11 +2825,30 @@ function armGeometry(layer, bodyAxisX) {
|
|
|
2819
2825
|
b.x1 - elbow.x,
|
|
2820
2826
|
b.y1 - elbow.y
|
|
2821
2827
|
);
|
|
2828
|
+
const inside = (x, y) => {
|
|
2829
|
+
const k = Math.floor(y) - bbox.y;
|
|
2830
|
+
if (k < 0 || k >= bbox.h) return false;
|
|
2831
|
+
const [rs, re] = span(k);
|
|
2832
|
+
return rs < x && x < re;
|
|
2833
|
+
};
|
|
2834
|
+
const capRays = Array.from({ length: CAP_SEGMENTS + 1 }, (_, i) => {
|
|
2835
|
+
const a = Math.PI * i / CAP_SEGMENTS;
|
|
2836
|
+
let t = 1;
|
|
2837
|
+
while (t <= capRadius + CAP_INSET && inside(
|
|
2838
|
+
elbow.x + canvasW / 2 + t * Math.cos(a),
|
|
2839
|
+
canvasH / 2 - elbow.y - t * Math.sin(a)
|
|
2840
|
+
)) {
|
|
2841
|
+
t++;
|
|
2842
|
+
}
|
|
2843
|
+
return Math.min(capRadius, Math.max(1, t - capInset(i)));
|
|
2844
|
+
});
|
|
2822
2845
|
return {
|
|
2823
2846
|
shoulder,
|
|
2824
2847
|
shoulderRadius: ru,
|
|
2825
2848
|
elbow,
|
|
2826
2849
|
capRadius,
|
|
2850
|
+
capRays,
|
|
2851
|
+
seamRun: [s - bbox.x, e - bbox.x],
|
|
2827
2852
|
side: shoulder.x > bodyAxisX ? 1 : -1
|
|
2828
2853
|
};
|
|
2829
2854
|
}
|
|
@@ -2838,69 +2863,101 @@ function armParts(role, layer, g, order) {
|
|
|
2838
2863
|
const lx = (x) => roundTo((x - cx(b)) / bw(b), 1e-5);
|
|
2839
2864
|
const ly = (y) => roundTo((y - cy(b)) / bh(b), 1e-5);
|
|
2840
2865
|
const seam = ly(g.elbow.y);
|
|
2841
|
-
const band = (
|
|
2866
|
+
const band = (top2, bottom) => [
|
|
2842
2867
|
-0.5,
|
|
2843
|
-
|
|
2868
|
+
top2,
|
|
2844
2869
|
0.5,
|
|
2845
|
-
|
|
2870
|
+
top2,
|
|
2846
2871
|
-0.5,
|
|
2847
2872
|
bottom,
|
|
2848
2873
|
0.5,
|
|
2849
2874
|
bottom
|
|
2850
2875
|
];
|
|
2851
2876
|
const quad = [2, 3, 0, 0, 3, 1];
|
|
2852
|
-
const
|
|
2877
|
+
const rays = g.capRays.length;
|
|
2878
|
+
const top = (rays - 1) / 2;
|
|
2879
|
+
const at = (i, r) => {
|
|
2880
|
+
const a = Math.PI * i / (rays - 1);
|
|
2881
|
+
return [lx(g.elbow.x + r * Math.cos(a)), ly(g.elbow.y + r * Math.sin(a))];
|
|
2882
|
+
};
|
|
2883
|
+
const width = (i) => Math.min(CAP_RIM * g.capRadius, g.capRays[i] / 2);
|
|
2884
|
+
const ringRays = Array.from({ length: rays }, (_, i) => i);
|
|
2885
|
+
ringRays.splice(top, 0, top);
|
|
2886
|
+
const vertices = [lx(g.elbow.x), seam];
|
|
2887
|
+
for (let i = 0; i < rays; i++) {
|
|
2888
|
+
vertices.push(...at(i, g.capRays[i] - width(i)));
|
|
2889
|
+
}
|
|
2890
|
+
const ringInner = vertices.length / 2;
|
|
2891
|
+
for (const i of ringRays) vertices.push(...at(i, g.capRays[i] - width(i)));
|
|
2892
|
+
const ringOuter = vertices.length / 2;
|
|
2893
|
+
for (const i of ringRays) vertices.push(...at(i, g.capRays[i]));
|
|
2894
|
+
const { uvs } = meshOf(vertices, []);
|
|
2895
|
+
const col = (c) => roundTo(Math.min(Math.max(c + 0.5, 0.5), bw(b) - 0.5) / bw(b), 1e-5);
|
|
2896
|
+
const v = roundTo(0.5 - seam, 1e-5);
|
|
2897
|
+
ringRays.forEach((i, j) => {
|
|
2898
|
+
const right = j <= top;
|
|
2899
|
+
const outer = right ? g.seamRun[1] : g.seamRun[0] - 1;
|
|
2900
|
+
const step = right ? -width(i) : width(i);
|
|
2901
|
+
uvs[(ringInner + j) * 2] = col(outer + step);
|
|
2902
|
+
uvs[(ringInner + j) * 2 + 1] = v;
|
|
2903
|
+
uvs[(ringOuter + j) * 2] = col(outer);
|
|
2904
|
+
uvs[(ringOuter + j) * 2 + 1] = v;
|
|
2905
|
+
});
|
|
2853
2906
|
const fan = [];
|
|
2854
|
-
for (let i = 0; i
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
);
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
const part = (id, deformer, at, mesh) => ({
|
|
2907
|
+
for (let i = 0; i < rays - 1; i++) fan.push(0, 1 + i, 2 + i);
|
|
2908
|
+
const ring = [];
|
|
2909
|
+
for (let j = 0; j < ringRays.length - 1; j++) {
|
|
2910
|
+
if (j === top) continue;
|
|
2911
|
+
const [p, q] = [ringInner + j, ringOuter + j];
|
|
2912
|
+
ring.push(p, q, q + 1, p, q + 1, p + 1);
|
|
2913
|
+
}
|
|
2914
|
+
const part = (id, deformer, z, mesh) => ({
|
|
2863
2915
|
id,
|
|
2864
2916
|
color: [1, 1, 1, 1],
|
|
2865
2917
|
width: bw(b),
|
|
2866
2918
|
height: bh(b),
|
|
2867
2919
|
transform: { x: cx(b), y: cy(b) },
|
|
2868
|
-
order:
|
|
2920
|
+
order: z,
|
|
2869
2921
|
deformer,
|
|
2870
2922
|
mesh
|
|
2871
2923
|
});
|
|
2872
2924
|
const ids = ARM_IDS[role];
|
|
2873
2925
|
return [
|
|
2874
|
-
part(
|
|
2926
|
+
part(ids.cap, ids.forearmDeformer, order, {
|
|
2927
|
+
vertices,
|
|
2928
|
+
uvs,
|
|
2929
|
+
indices: [...fan, ...ring]
|
|
2930
|
+
}),
|
|
2931
|
+
part(role, ids.armDeformer, order + 1, meshOf(band(0.5, seam), quad)),
|
|
2875
2932
|
part(
|
|
2876
2933
|
ids.forearm,
|
|
2877
2934
|
ids.forearmDeformer,
|
|
2878
|
-
order +
|
|
2879
|
-
meshOf(
|
|
2935
|
+
order + 2,
|
|
2936
|
+
meshOf(band(seam, -0.5), quad)
|
|
2880
2937
|
)
|
|
2881
2938
|
];
|
|
2882
2939
|
}
|
|
2883
2940
|
function armDeformers(role, g) {
|
|
2884
2941
|
const ids = ARM_IDS[role];
|
|
2885
2942
|
const params = ARM_PARAMS[role];
|
|
2886
|
-
const rotate = (parameter) => ({
|
|
2943
|
+
const rotate = (parameter, range, sign) => ({
|
|
2887
2944
|
parameter,
|
|
2888
2945
|
channel: "rotate",
|
|
2889
|
-
from:
|
|
2890
|
-
to:
|
|
2946
|
+
from: sign * range[0],
|
|
2947
|
+
to: sign * range[1]
|
|
2891
2948
|
});
|
|
2892
2949
|
return [
|
|
2893
2950
|
{
|
|
2894
2951
|
id: ids.armDeformer,
|
|
2895
2952
|
parent: BODY_WARP_ID,
|
|
2896
2953
|
pivot: { ...g.shoulder },
|
|
2897
|
-
bindings: [rotate(params.arm)]
|
|
2954
|
+
bindings: [rotate(params.arm, ARM_RANGE, g.side)]
|
|
2898
2955
|
},
|
|
2899
2956
|
{
|
|
2900
2957
|
id: ids.forearmDeformer,
|
|
2901
2958
|
parent: ids.armDeformer,
|
|
2902
2959
|
pivot: { ...g.elbow },
|
|
2903
|
-
bindings: [rotate(params.elbow)]
|
|
2960
|
+
bindings: [rotate(params.elbow, ELBOW_RANGE, -g.side)]
|
|
2904
2961
|
}
|
|
2905
2962
|
];
|
|
2906
2963
|
}
|
|
@@ -2909,8 +2966,8 @@ function armDeformers(role, g) {
|
|
|
2909
2966
|
var ROLE_TABLE = [
|
|
2910
2967
|
{ role: "hair_back", family: "hair_back" },
|
|
2911
2968
|
{ 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"] },
|
|
2969
|
+
{ role: "arm_L", family: "arm", parts: ["elbow_L", "arm_L", "forearm_L"] },
|
|
2970
|
+
{ role: "arm_R", family: "arm", parts: ["elbow_R", "arm_R", "forearm_R"] },
|
|
2914
2971
|
{ role: "face", family: "face", required: true },
|
|
2915
2972
|
{ role: "blush_L", family: "face" },
|
|
2916
2973
|
{ role: "blush_R", family: "face" },
|
|
@@ -5723,13 +5780,14 @@ function declareParameters(roles) {
|
|
|
5723
5780
|
add(import_format8.StandardParameter.BodyAngleZ, "Body Angle Z", -10, 10, 0);
|
|
5724
5781
|
}
|
|
5725
5782
|
const [armMin, armMax] = ARM_RANGE;
|
|
5783
|
+
const [elbowMin, elbowMax] = ELBOW_RANGE;
|
|
5726
5784
|
if (roles.has("arm_L")) {
|
|
5727
5785
|
add(import_format8.StandardParameter.ArmLeft, "Arm L", armMin, armMax, 0);
|
|
5728
|
-
add(import_format8.StandardParameter.ElbowLeft, "Elbow L",
|
|
5786
|
+
add(import_format8.StandardParameter.ElbowLeft, "Elbow L", elbowMin, elbowMax, 0);
|
|
5729
5787
|
}
|
|
5730
5788
|
if (roles.has("arm_R")) {
|
|
5731
5789
|
add(import_format8.StandardParameter.ArmRight, "Arm R", armMin, armMax, 0);
|
|
5732
|
-
add(import_format8.StandardParameter.ElbowRight, "Elbow R",
|
|
5790
|
+
add(import_format8.StandardParameter.ElbowRight, "Elbow R", elbowMin, elbowMax, 0);
|
|
5733
5791
|
}
|
|
5734
5792
|
add(import_format8.StandardParameter.EyeOpenLeft, "Eye L", 0, 1, 1);
|
|
5735
5793
|
add(import_format8.StandardParameter.EyeOpenRight, "Eye R", 0, 1, 1);
|