@bitefoundry/retrieviewer 0.0.3 → 0.0.4
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/ASSET-PROVENANCE.md +6 -0
- package/ASSETS-LICENSE.md +2 -1
- package/ATTRIBUTION.md +6 -1
- package/COMFORT-ART.md +65 -0
- package/DESKTOP-PLATFORMS.md +6 -1
- package/PLUGIN.md +13 -10
- package/PREREQUISITES.md +95 -0
- package/PUPPY-MEMORY.md +102 -1
- package/README.ko.md +110 -0
- package/README.md +117 -59
- package/RELEASING.md +23 -12
- package/THIRD-PARTY-NOTICES.md +5 -3
- package/braille.mjs +35 -9
- package/examples/live.mjs +2 -2
- package/integrations/linux-overlay/overlay.py +2 -2
- package/integrations/macos-overlay/overlay.jxa +8 -6
- package/integrations/opencode/runtime.mjs +4 -4
- package/integrations/opencode/tui.tsx +1 -1
- package/integrations/windows-overlay/Overlay.cs +4 -4
- package/integrations/windows-overlay/protocol.mjs +11 -7
- package/package.json +34 -13
- package/puppy-comfort-sprites.mjs +25 -0
- package/puppy-companion-comfort-q5.bin.gz +0 -0
- package/puppy-companion-comfort.json +77 -0
- package/puppy-companion-life.mjs +49 -16
- package/puppy-companion-objects.mjs +12 -0
- package/puppy-frame-predictive.mjs +15 -9
- package/puppy-frame-store.mjs +2 -2
- package/puppy-paper-world.mjs +14 -0
- package/puppy-paper.mjs +65 -14
- package/retrieviewer-plugin.d.mts +1 -1
- package/retrieviewer-plugin.mjs +1 -1
- package/retrieviewer.d.mts +10 -4
- package/retrieviewer.mjs +20 -14
- package/locomotion-core.mjs +0 -21
- package/locomotion-puppy.animal +0 -0
- package/vendor/procedural-animals/package.json +0 -40
- package/vendor/procedural-animals/src/animal.js +0 -146
- package/vendor/procedural-animals/src/bake.js +0 -51
- package/vendor/procedural-animals/src/build.js +0 -81
- package/vendor/procedural-animals/src/core/build/coatKit.js +0 -121
- package/vendor/procedural-animals/src/core/build/featherCards.js +0 -189
- package/vendor/procedural-animals/src/core/build/finEdges.js +0 -85
- package/vendor/procedural-animals/src/core/build/furSlope.js +0 -115
- package/vendor/procedural-animals/src/core/build/mesh.js +0 -67
- package/vendor/procedural-animals/src/core/build/pipeline.js +0 -272
- package/vendor/procedural-animals/src/core/build/seams.js +0 -183
- package/vendor/procedural-animals/src/core/build/warp.js +0 -112
- package/vendor/procedural-animals/src/core/build/weights.js +0 -393
- package/vendor/procedural-animals/src/core/math/vec.js +0 -81
- package/vendor/procedural-animals/src/core/motion/actions.js +0 -800
- package/vendor/procedural-animals/src/core/motion/bird.js +0 -3063
- package/vendor/procedural-animals/src/core/motion/birdActions.js +0 -1059
- package/vendor/procedural-animals/src/core/motion/common.js +0 -158
- package/vendor/procedural-animals/src/core/motion/index.js +0 -22
- package/vendor/procedural-animals/src/core/motion/quadruped.js +0 -2875
- package/vendor/procedural-animals/src/core/motion/snake.js +0 -1594
- package/vendor/procedural-animals/src/core/motion/spider.js +0 -1810
- package/vendor/procedural-animals/src/core/motion/swimmer.js +0 -1047
- package/vendor/procedural-animals/src/core/motion/swimmerActions.js +0 -613
- package/vendor/procedural-animals/src/core/render/animalObject.js +0 -262
- package/vendor/procedural-animals/src/core/render/coatMaterial.js +0 -1301
- package/vendor/procedural-animals/src/core/render/dqs.js +0 -159
- package/vendor/procedural-animals/src/core/render/eyes.js +0 -676
- package/vendor/procedural-animals/src/core/render/membranes.js +0 -77
- package/vendor/procedural-animals/src/core/render/skeleton.js +0 -41
- package/vendor/procedural-animals/src/core/rig/bird.js +0 -327
- package/vendor/procedural-animals/src/core/rig/quadruped.js +0 -76
- package/vendor/procedural-animals/src/core/rig/rig.js +0 -79
- package/vendor/procedural-animals/src/core/rig/snake.js +0 -76
- package/vendor/procedural-animals/src/core/rig/spider.js +0 -110
- package/vendor/procedural-animals/src/core/rig/swimmer.js +0 -181
- package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +0 -53
- package/vendor/procedural-animals/src/core/sdf/mesher.js +0 -238
- package/vendor/procedural-animals/src/core/sdf/sdf.js +0 -263
- package/vendor/procedural-animals/src/index.d.ts +0 -98
- package/vendor/procedural-animals/src/index.js +0 -29
- package/vendor/procedural-animals/src/registry.js +0 -48
- package/vendor/procedural-animals/src/species/bear/behaviour.js +0 -463
- package/vendor/procedural-animals/src/species/bear/claws.js +0 -147
- package/vendor/procedural-animals/src/species/bear/coat.js +0 -726
- package/vendor/procedural-animals/src/species/bear/index.js +0 -139
- package/vendor/procedural-animals/src/species/bear/motion.js +0 -112
- package/vendor/procedural-animals/src/species/bear/regions.js +0 -78
- package/vendor/procedural-animals/src/species/bear/rig.js +0 -112
- package/vendor/procedural-animals/src/species/bear/sculpt.js +0 -272
- package/vendor/procedural-animals/src/species/boar/behaviour.js +0 -335
- package/vendor/procedural-animals/src/species/boar/coat.js +0 -372
- package/vendor/procedural-animals/src/species/boar/index.js +0 -110
- package/vendor/procedural-animals/src/species/boar/motion.js +0 -85
- package/vendor/procedural-animals/src/species/boar/regions.js +0 -88
- package/vendor/procedural-animals/src/species/boar/rig.js +0 -111
- package/vendor/procedural-animals/src/species/boar/sculpt.js +0 -285
- package/vendor/procedural-animals/src/species/cat/behaviour.js +0 -559
- package/vendor/procedural-animals/src/species/cat/coat.js +0 -841
- package/vendor/procedural-animals/src/species/cat/index.js +0 -211
- package/vendor/procedural-animals/src/species/cat/motion.js +0 -101
- package/vendor/procedural-animals/src/species/cat/regions.js +0 -82
- package/vendor/procedural-animals/src/species/cat/rig.js +0 -100
- package/vendor/procedural-animals/src/species/cat/sculpt.js +0 -266
- package/vendor/procedural-animals/src/species/cat/whiskers.js +0 -110
- package/vendor/procedural-animals/src/species/cheetah/coat.js +0 -427
- package/vendor/procedural-animals/src/species/cheetah/index.js +0 -51
- package/vendor/procedural-animals/src/species/cheetah/joints.js +0 -3
- package/vendor/procedural-animals/src/species/cheetah/motion.js +0 -77
- package/vendor/procedural-animals/src/species/cheetah/regions.js +0 -95
- package/vendor/procedural-animals/src/species/cheetah/rig.js +0 -66
- package/vendor/procedural-animals/src/species/cheetah/sculpt.js +0 -158
- package/vendor/procedural-animals/src/species/chicken/coat.js +0 -313
- package/vendor/procedural-animals/src/species/chicken/coverts.js +0 -320
- package/vendor/procedural-animals/src/species/chicken/index.js +0 -110
- package/vendor/procedural-animals/src/species/chicken/motion.js +0 -177
- package/vendor/procedural-animals/src/species/chicken/regions.js +0 -66
- package/vendor/procedural-animals/src/species/chicken/rig.js +0 -144
- package/vendor/procedural-animals/src/species/chicken/sculpt.js +0 -389
- package/vendor/procedural-animals/src/species/chicken/wingLook.js +0 -66
- package/vendor/procedural-animals/src/species/chicken/wingStack.js +0 -124
- package/vendor/procedural-animals/src/species/cow/behaviour.js +0 -521
- package/vendor/procedural-animals/src/species/cow/coat.js +0 -465
- package/vendor/procedural-animals/src/species/cow/index.js +0 -118
- package/vendor/procedural-animals/src/species/cow/motion.js +0 -81
- package/vendor/procedural-animals/src/species/cow/regions.js +0 -98
- package/vendor/procedural-animals/src/species/cow/rig.js +0 -116
- package/vendor/procedural-animals/src/species/cow/sculpt.js +0 -339
- package/vendor/procedural-animals/src/species/crow/coat.js +0 -145
- package/vendor/procedural-animals/src/species/crow/index.js +0 -70
- package/vendor/procedural-animals/src/species/crow/joints.js +0 -3
- package/vendor/procedural-animals/src/species/crow/motion.js +0 -101
- package/vendor/procedural-animals/src/species/crow/regions.js +0 -50
- package/vendor/procedural-animals/src/species/crow/rig.js +0 -83
- package/vendor/procedural-animals/src/species/crow/sculpt.js +0 -118
- package/vendor/procedural-animals/src/species/deer/behaviour.js +0 -513
- package/vendor/procedural-animals/src/species/deer/coat.js +0 -391
- package/vendor/procedural-animals/src/species/deer/index.js +0 -106
- package/vendor/procedural-animals/src/species/deer/motion.js +0 -97
- package/vendor/procedural-animals/src/species/deer/regions.js +0 -60
- package/vendor/procedural-animals/src/species/deer/rig.js +0 -124
- package/vendor/procedural-animals/src/species/deer/sculpt.js +0 -297
- package/vendor/procedural-animals/src/species/dog/behaviour.js +0 -521
- package/vendor/procedural-animals/src/species/dog/coat.js +0 -495
- package/vendor/procedural-animals/src/species/dog/index.js +0 -144
- package/vendor/procedural-animals/src/species/dog/motion.js +0 -118
- package/vendor/procedural-animals/src/species/dog/regions.js +0 -61
- package/vendor/procedural-animals/src/species/dog/rig.js +0 -129
- package/vendor/procedural-animals/src/species/dog/sculpt.js +0 -246
- package/vendor/procedural-animals/src/species/eagle/coat.js +0 -250
- package/vendor/procedural-animals/src/species/eagle/index.js +0 -76
- package/vendor/procedural-animals/src/species/eagle/joints.js +0 -3
- package/vendor/procedural-animals/src/species/eagle/motion.js +0 -137
- package/vendor/procedural-animals/src/species/eagle/regions.js +0 -57
- package/vendor/procedural-animals/src/species/eagle/rig.js +0 -107
- package/vendor/procedural-animals/src/species/eagle/sculpt.js +0 -137
- package/vendor/procedural-animals/src/species/fish/coat.js +0 -271
- package/vendor/procedural-animals/src/species/fish/index.js +0 -88
- package/vendor/procedural-animals/src/species/fish/motion.js +0 -92
- package/vendor/procedural-animals/src/species/fish/regions.js +0 -27
- package/vendor/procedural-animals/src/species/fish/rig.js +0 -143
- package/vendor/procedural-animals/src/species/fish/sculpt.js +0 -214
- package/vendor/procedural-animals/src/species/fish/variants.js +0 -126
- package/vendor/procedural-animals/src/species/fox/behaviour.js +0 -314
- package/vendor/procedural-animals/src/species/fox/coat.js +0 -444
- package/vendor/procedural-animals/src/species/fox/index.js +0 -120
- package/vendor/procedural-animals/src/species/fox/motion.js +0 -81
- package/vendor/procedural-animals/src/species/fox/regions.js +0 -59
- package/vendor/procedural-animals/src/species/fox/rig.js +0 -91
- package/vendor/procedural-animals/src/species/fox/sculpt.js +0 -202
- package/vendor/procedural-animals/src/species/frog/behaviour.js +0 -590
- package/vendor/procedural-animals/src/species/frog/coat.js +0 -305
- package/vendor/procedural-animals/src/species/frog/index.js +0 -97
- package/vendor/procedural-animals/src/species/frog/motion.js +0 -69
- package/vendor/procedural-animals/src/species/frog/regions.js +0 -46
- package/vendor/procedural-animals/src/species/frog/rig.js +0 -156
- package/vendor/procedural-animals/src/species/frog/sculpt.js +0 -240
- package/vendor/procedural-animals/src/species/goat/behaviour.js +0 -509
- package/vendor/procedural-animals/src/species/goat/coat.js +0 -590
- package/vendor/procedural-animals/src/species/goat/index.js +0 -149
- package/vendor/procedural-animals/src/species/goat/motion.js +0 -95
- package/vendor/procedural-animals/src/species/goat/regions.js +0 -98
- package/vendor/procedural-animals/src/species/goat/rig.js +0 -181
- package/vendor/procedural-animals/src/species/goat/sculpt.js +0 -547
- package/vendor/procedural-animals/src/species/horse/coat.js +0 -361
- package/vendor/procedural-animals/src/species/horse/coatSeam.js +0 -122
- package/vendor/procedural-animals/src/species/horse/index.js +0 -80
- package/vendor/procedural-animals/src/species/horse/motion.js +0 -245
- package/vendor/procedural-animals/src/species/horse/regions.js +0 -60
- package/vendor/procedural-animals/src/species/horse/rig.js +0 -117
- package/vendor/procedural-animals/src/species/horse/sculpt.js +0 -316
- package/vendor/procedural-animals/src/species/horse/seamWeights.js +0 -272
- package/vendor/procedural-animals/src/species/lion/behaviour.js +0 -509
- package/vendor/procedural-animals/src/species/lion/coat.js +0 -1016
- package/vendor/procedural-animals/src/species/lion/index.js +0 -111
- package/vendor/procedural-animals/src/species/lion/motion.js +0 -87
- package/vendor/procedural-animals/src/species/lion/regions.js +0 -106
- package/vendor/procedural-animals/src/species/lion/rig.js +0 -110
- package/vendor/procedural-animals/src/species/lion/sculpt.js +0 -384
- package/vendor/procedural-animals/src/species/lion/whiskers.js +0 -132
- package/vendor/procedural-animals/src/species/pig/behaviour.js +0 -575
- package/vendor/procedural-animals/src/species/pig/coat.js +0 -730
- package/vendor/procedural-animals/src/species/pig/ears.js +0 -242
- package/vendor/procedural-animals/src/species/pig/index.js +0 -161
- package/vendor/procedural-animals/src/species/pig/motion.js +0 -105
- package/vendor/procedural-animals/src/species/pig/regions.js +0 -100
- package/vendor/procedural-animals/src/species/pig/rig.js +0 -152
- package/vendor/procedural-animals/src/species/pig/sculpt.js +0 -382
- package/vendor/procedural-animals/src/species/rabbit/behaviour.js +0 -605
- package/vendor/procedural-animals/src/species/rabbit/coat.js +0 -285
- package/vendor/procedural-animals/src/species/rabbit/index.js +0 -85
- package/vendor/procedural-animals/src/species/rabbit/motion.js +0 -85
- package/vendor/procedural-animals/src/species/rabbit/regions.js +0 -48
- package/vendor/procedural-animals/src/species/rabbit/rig.js +0 -99
- package/vendor/procedural-animals/src/species/rabbit/sculpt.js +0 -148
- package/vendor/procedural-animals/src/species/rat/behaviour.js +0 -539
- package/vendor/procedural-animals/src/species/rat/coat.js +0 -341
- package/vendor/procedural-animals/src/species/rat/index.js +0 -111
- package/vendor/procedural-animals/src/species/rat/motion.js +0 -90
- package/vendor/procedural-animals/src/species/rat/regions.js +0 -92
- package/vendor/procedural-animals/src/species/rat/rig.js +0 -112
- package/vendor/procedural-animals/src/species/rat/sculpt.js +0 -163
- package/vendor/procedural-animals/src/species/rat/whiskers.js +0 -119
- package/vendor/procedural-animals/src/species/shark/coat.js +0 -383
- package/vendor/procedural-animals/src/species/shark/index.js +0 -104
- package/vendor/procedural-animals/src/species/shark/motion.js +0 -69
- package/vendor/procedural-animals/src/species/shark/regions.js +0 -34
- package/vendor/procedural-animals/src/species/shark/rig.js +0 -194
- package/vendor/procedural-animals/src/species/shark/sculpt.js +0 -343
- package/vendor/procedural-animals/src/species/shark/variants.js +0 -105
- package/vendor/procedural-animals/src/species/sheep/behaviour.js +0 -522
- package/vendor/procedural-animals/src/species/sheep/coat.js +0 -529
- package/vendor/procedural-animals/src/species/sheep/index.js +0 -152
- package/vendor/procedural-animals/src/species/sheep/motion.js +0 -86
- package/vendor/procedural-animals/src/species/sheep/neck.js +0 -41
- package/vendor/procedural-animals/src/species/sheep/regions.js +0 -62
- package/vendor/procedural-animals/src/species/sheep/rig.js +0 -163
- package/vendor/procedural-animals/src/species/sheep/sculpt.js +0 -542
- package/vendor/procedural-animals/src/species/snake/coat.js +0 -315
- package/vendor/procedural-animals/src/species/snake/index.js +0 -73
- package/vendor/procedural-animals/src/species/snake/motion.js +0 -51
- package/vendor/procedural-animals/src/species/snake/regions.js +0 -51
- package/vendor/procedural-animals/src/species/snake/rig.js +0 -108
- package/vendor/procedural-animals/src/species/snake/sculpt.js +0 -122
- package/vendor/procedural-animals/src/species/spider/coat.js +0 -279
- package/vendor/procedural-animals/src/species/spider/index.js +0 -78
- package/vendor/procedural-animals/src/species/spider/motion.js +0 -72
- package/vendor/procedural-animals/src/species/spider/regions.js +0 -87
- package/vendor/procedural-animals/src/species/spider/rig.js +0 -118
- package/vendor/procedural-animals/src/species/spider/sculpt.js +0 -182
- package/vendor/procedural-animals/src/species/wolf/behaviour.js +0 -160
- package/vendor/procedural-animals/src/species/wolf/coat.js +0 -749
- package/vendor/procedural-animals/src/species/wolf/index.js +0 -107
- package/vendor/procedural-animals/src/species/wolf/motion.js +0 -80
- package/vendor/procedural-animals/src/species/wolf/regions.js +0 -57
- package/vendor/procedural-animals/src/species/wolf/rig.js +0 -87
- package/vendor/procedural-animals/src/species/wolf/sculpt.js +0 -339
- package/vendor/procedural-animals/src/worker.js +0 -29
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
// Flight-feather cards: real feather geometry (primaries, secondaries, rectrices and their coverts)
|
|
2
|
-
// appended to the base surface. Each card is a thin two-sided vane (top and bottom layer, rachis
|
|
3
|
-
// down the middle, asymmetric outer / inner vane, rounded or emarginated tip, curved rachis) rigidly
|
|
4
|
-
// skinned to its own feather bone, so the engine can fan, fold, twist and splay every feather while
|
|
5
|
-
// the base draw call renders it (one draw, shadows and the crowd tier included). Material id 10
|
|
6
|
-
// (vane) is shaded in core/render/coatMaterial.js from surf = [gloss, iridescence, across, along]:
|
|
7
|
-
// across -1 (outer vane edge) .. 0 (rachis) .. 1 (inner vane edge), along 0 (root) .. 1 (tip).
|
|
8
|
-
// colour(kind, i, side, t, c, layer) -> { rgb, gloss, irid, bar? }: bar { rgb, period (m) } draws bars
|
|
9
|
-
// across the vane in the shader (patternColor = [rgb, -bar count]; opt-in, e.g. barred poultry).
|
|
10
|
-
//
|
|
11
|
-
// Species usage (surfaces hook, see core/build/pipeline.js):
|
|
12
|
-
// surfaces: (ctx) => featherCards({ ...ctx, wing: motion.wing, feathers: motion.feathers,
|
|
13
|
-
// tail: motion.tail, colour: (kind, i, side, t, c) => ({ rgb, gloss, irid }) })
|
|
14
|
-
import { featherJoints, DEG } from '../rig/bird.js';
|
|
15
|
-
import { MAT } from './coatKit.js';
|
|
16
|
-
|
|
17
|
-
const V = (x, y, z) => [x, y, z];
|
|
18
|
-
const addS = (a, b, k) => [a[0] + b[0] * k, a[1] + b[1] * k, a[2] + b[2] * k];
|
|
19
|
-
const cross = (a, b) => [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
|
|
20
|
-
const norm = (a) => { const l = Math.hypot(a[0], a[1], a[2]) || 1; return [a[0] / l, a[1] / l, a[2] / l]; };
|
|
21
|
-
const mirror = (p) => [-p[0], p[1], p[2]];
|
|
22
|
-
|
|
23
|
-
// vane half-widths at t (0 root .. 1 tip): [outer, inner] (also used by the bird engine's ground checks)
|
|
24
|
-
// (f.base0: the vane's width at the root as a fraction of its full width, default 0.3)
|
|
25
|
-
export function vaneWidth(f, t, w) {
|
|
26
|
-
const b0 = f.base0 ?? 0.3;
|
|
27
|
-
const base = b0 + (1 - b0) * smooth(0.0, 0.16, t);
|
|
28
|
-
const tr = f.tipRound;
|
|
29
|
-
let tip = 1;
|
|
30
|
-
if (t > 1 - tr) { const x = (t - (1 - tr)) / tr; tip = Math.sqrt(Math.max(0, 1 - x * x)); }
|
|
31
|
-
let wo = w * f.outer * base * tip, wi = w * (1 - f.outer) * base * tip;
|
|
32
|
-
if (f.emarg > 0) {
|
|
33
|
-
// emarginated primaries: both vanes step in beyond the notch, leaving a narrow "finger"
|
|
34
|
-
const k = smooth(0.5, 0.64, t) * f.emarg;
|
|
35
|
-
wi *= 1 - 0.62 * k; wo *= 1 - 0.3 * k;
|
|
36
|
-
}
|
|
37
|
-
return [wo, Math.max(wi, 0.0006)];
|
|
38
|
-
}
|
|
39
|
-
function smooth(a, b, x) { const t = Math.min(1, Math.max(0, (x - a) / (b - a))); return t * t * (3 - 2 * t); }
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* @param ctx { rig, params, Q, wing, feathers, tail, colour, thickness? }
|
|
43
|
-
* @returns surfaces block { nV, pos, nrm, index, skinIndex, skinWeight, comb, tint, pattern, mark, furLen, patternColor, surf }
|
|
44
|
-
*/
|
|
45
|
-
export function featherCards(ctx) {
|
|
46
|
-
const { rig, Q, wing, feathers, tail } = ctx;
|
|
47
|
-
const colour = ctx.colour || (() => ({ rgb: [0.02, 0.02, 0.02], gloss: 0.5, irid: 0 }));
|
|
48
|
-
// the bind layout (the rig built the joints from the same call)
|
|
49
|
-
const Jl = {};
|
|
50
|
-
for (const k of ['shoulderL', 'tailBase', 'tailTip']) Jl[k] = rig.J[k];
|
|
51
|
-
const lay = featherJoints(Jl, wing, feathers, tail);
|
|
52
|
-
const res = Q?.res ?? 1;
|
|
53
|
-
const nA = res <= 1.35 ? 9 : res <= 2.1 ? 6 : res <= 3.1 ? 4 : 3;
|
|
54
|
-
const th = ctx.thickness ?? 0.0005;
|
|
55
|
-
const coverts = res < 4 || ctx.crowdCoverts;
|
|
56
|
-
const P = [], N = [], C = [], T = [], S = [], SI = [], I = [], X = [];
|
|
57
|
-
const PCL = []; // vane bars: [vertex, rgb, -count]
|
|
58
|
-
const cov = lay.F.coverts;
|
|
59
|
-
|
|
60
|
-
const card = (bone, side, fr, f, opts) => {
|
|
61
|
-
const b = rig.BONE[bone];
|
|
62
|
-
if (!b) throw new Error('featherCards: missing bone ' + bone);
|
|
63
|
-
const s = side;
|
|
64
|
-
const m = (p) => (s > 0 ? p : mirror(p));
|
|
65
|
-
const L = f.len * (opts.lenK || 1), W = f.width * (opts.widthK || 1);
|
|
66
|
-
const A = m(V(fr.axis.x, fr.axis.y, fr.axis.z)), Nn = m(V(fr.normal.x, fr.normal.y, fr.normal.z));
|
|
67
|
-
// inner vane side (+across): s * (N x A)
|
|
68
|
-
const Tv = norm(cross(Nn, A)).map((x) => x * s);
|
|
69
|
-
const root0 = m(V(fr.root.x, fr.root.y, fr.root.z));
|
|
70
|
-
const root = addS(addS(root0, Nn, opts.lift || 0), A, opts.shift || 0);
|
|
71
|
-
const fo = opts.shape ? { ...f, ...opts.shape } : f;
|
|
72
|
-
// vane arch: the edges sit this fraction of the half-width below the rachis (feather spec `arch`,
|
|
73
|
-
// default 0.12; a flatter vane lets overlapping neighbours stack on smaller lift steps)
|
|
74
|
-
const arch = fo.arch ?? 0.12;
|
|
75
|
-
const v0 = P.length / 3;
|
|
76
|
-
const ts = [];
|
|
77
|
-
for (let j = 0; j <= nA; j++) { const u = j / nA; ts.push(0.5 - 0.5 * Math.cos(Math.PI * u)); }
|
|
78
|
-
const pt = (t, c) => {
|
|
79
|
-
const [wo, wi] = vaneWidth(fo, t, W);
|
|
80
|
-
const w = c < 0 ? wo : wi;
|
|
81
|
-
if (fo.arc) {
|
|
82
|
-
// rachis bent along a circular arc of total angle `arc` (rad) toward the inner vane, length
|
|
83
|
-
// kept (long display feathers: a rooster's sickles); the vane width turns with the rachis
|
|
84
|
-
const a = fo.arc * t, R = L / fo.arc, ca = Math.cos(a), sa = Math.sin(a);
|
|
85
|
-
let p = addS(root, A, R * sa);
|
|
86
|
-
p = addS(p, Tv, R * (1 - ca));
|
|
87
|
-
p = addS(p, A, -sa * c * w);
|
|
88
|
-
p = addS(p, Tv, ca * c * w);
|
|
89
|
-
return addS(p, Nn, -fo.droop * L * t * t - Math.abs(c) * w * arch);
|
|
90
|
-
}
|
|
91
|
-
// curved rachis (toward the inner vane, drooping), vanes slightly convex (edges lower)
|
|
92
|
-
const along = t * L, curve = fo.curve * L * t * t, droop = fo.droop * L * t * t;
|
|
93
|
-
let p = addS(root, A, along);
|
|
94
|
-
p = addS(p, Tv, curve + c * w);
|
|
95
|
-
p = addS(p, Nn, -droop - Math.abs(c) * w * arch);
|
|
96
|
-
return p;
|
|
97
|
-
};
|
|
98
|
-
const cols = [-1, 0, 1];
|
|
99
|
-
for (const layer of [1, -1]) {
|
|
100
|
-
for (let j = 0; j <= nA; j++) {
|
|
101
|
-
const t = ts[j];
|
|
102
|
-
for (const c of cols) {
|
|
103
|
-
const p = addS(pt(t, c), Nn, layer * th * 0.5 * (1 - 0.6 * t));
|
|
104
|
-
// surface tangents for the normal
|
|
105
|
-
const e = 1e-3;
|
|
106
|
-
const pa = pt(Math.min(1, t + e), c), pb = pt(Math.max(0, t - e), c);
|
|
107
|
-
const pc = pt(t, Math.min(1, c + 0.05)), pd = pt(t, Math.max(-1, c - 0.05));
|
|
108
|
-
const dt = [pa[0] - pb[0], pa[1] - pb[1], pa[2] - pb[2]], dc = [pc[0] - pd[0], pc[1] - pd[1], pc[2] - pd[2]];
|
|
109
|
-
let n = norm(cross(dt, dc));
|
|
110
|
-
const sgn = (n[0] * Nn[0] + n[1] * Nn[1] + n[2] * Nn[2]) < 0 ? -1 : 1;
|
|
111
|
-
n = n.map((x) => x * sgn * layer);
|
|
112
|
-
if (!Number.isFinite(n[0])) n = Nn.map((x) => x * layer);
|
|
113
|
-
P.push(...p); N.push(...n);
|
|
114
|
-
C.push(...norm(dt));
|
|
115
|
-
const col = colour(opts.kind, f.i, s, t, c, layer);
|
|
116
|
-
T.push(col.rgb[0], col.rgb[1], col.rgb[2], MAT.VANE);
|
|
117
|
-
// opt-in bars across the vane (colour() returns bar: { rgb, period (m) }): shader-drawn
|
|
118
|
-
if (col.bar) PCL.push([P.length / 3 - 1, col.bar.rgb, -L / col.bar.period]);
|
|
119
|
-
S.push(col.gloss ?? 0.5, col.irid ?? 0, c, t);
|
|
120
|
-
const wv = vaneWidth(fo, t, W);
|
|
121
|
-
X.push(c * (c < 0 ? wv[0] : wv[1]) * s);
|
|
122
|
-
SI.push(b.index, 0, 0, 0);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
const base = v0 + (layer > 0 ? 0 : (nA + 1) * 3);
|
|
126
|
-
for (let j = 0; j < nA; j++) {
|
|
127
|
-
for (let k = 0; k < 2; k++) {
|
|
128
|
-
const a = base + j * 3 + k, bq = a + 1, c2 = a + 3, d = a + 4;
|
|
129
|
-
// top layer faces +N; the bottom layer is wound the other way
|
|
130
|
-
if ((layer > 0) === (s > 0)) I.push(a, c2, bq, bq, c2, d);
|
|
131
|
-
else I.push(a, bq, c2, bq, d, c2);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
// winding sanity: flip this card's triangles if their geometric normal disagrees with the layer normal
|
|
136
|
-
fixWinding(P, N, I, v0);
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
// per-feather covert overrides (spec field `cov`: { lift, shift, lenK, widthK, shape }, merged over
|
|
140
|
-
// the defaults below; opt-in: a species can restack its coverts, e.g. reverse their overlap order;
|
|
141
|
-
// `cov: { skip: true }` drops the covert card, e.g. where the species sculpts the coverts as skin)
|
|
142
|
-
const covOpts = (f, o) => (f.cov ? { ...o, ...f.cov, shape: { ...o.shape, ...(f.cov.shape || {}) } } : o);
|
|
143
|
-
const wEH = lay.frames;
|
|
144
|
-
for (const side of [1, -1]) {
|
|
145
|
-
const S2 = side > 0 ? 'L' : 'R';
|
|
146
|
-
for (const fr of wEH.pri) {
|
|
147
|
-
const f = fr.f;
|
|
148
|
-
card(`pri${f.i + 1}${S2}`, side, fr, f, { kind: 'primary' });
|
|
149
|
-
if (coverts && !f.cov?.skip) card(`pri${f.i + 1}${S2}`, side, fr, f, covOpts(f, { kind: 'primaryCovert', lenK: cov.primary * (1 - 0.25 * f.i / Math.max(1, f.n - 1)), widthK: 1.05, lift: 0.0022, shift: -0.004, shape: { emarg: 0, tipRound: 0.6, outer: 0.45, curve: 0.02 } }));
|
|
150
|
-
}
|
|
151
|
-
for (const fr of wEH.sec) {
|
|
152
|
-
const f = fr.f;
|
|
153
|
-
card(`sec${f.i + 1}${S2}`, side, fr, f, { kind: 'secondary' });
|
|
154
|
-
if (coverts && !f.cov?.skip) card(`sec${f.i + 1}${S2}`, side, fr, f, covOpts(f, { kind: 'secondaryCovert', lenK: cov.secondary, widthK: 1.15, lift: 0.0028, shift: -0.006, shape: { tipRound: 0.65, outer: 0.45, curve: 0.02 } }));
|
|
155
|
-
}
|
|
156
|
-
for (const fr of wEH.rec) {
|
|
157
|
-
const f = fr.f;
|
|
158
|
-
card(`rec${f.i + 1}${S2}`, side, fr, f, { kind: 'rectrix' });
|
|
159
|
-
if (coverts && f.i < 4 && !f.cov?.skip) card(`rec${f.i + 1}${S2}`, side, fr, f, covOpts(f, { kind: 'tailCovert', lenK: cov.tail * (1 - 0.1 * f.i), widthK: 1.2, lift: 0.0025, shift: -0.012, shape: { tipRound: 0.7, outer: 0.5 } }));
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
const nV = P.length / 3;
|
|
163
|
-
const out = {
|
|
164
|
-
nV,
|
|
165
|
-
pos: Float32Array.from(P), nrm: Float32Array.from(N), index: Uint32Array.from(I),
|
|
166
|
-
skinIndex: Uint16Array.from(SI), skinWeight: new Float32Array(nV * 4),
|
|
167
|
-
comb: Float32Array.from(C), tint: Float32Array.from(T), surf: Float32Array.from(S),
|
|
168
|
-
pattern: Float32Array.from(X), mark: new Float32Array(nV).fill(1), furLen: new Float32Array(nV),
|
|
169
|
-
patternColor: new Float32Array(nV * 4),
|
|
170
|
-
};
|
|
171
|
-
for (const [v, rgb, n] of PCL) out.patternColor.set([rgb[0], rgb[1], rgb[2], n], v * 4);
|
|
172
|
-
for (let v = 0; v < nV; v++) out.skinWeight[v * 4] = 1;
|
|
173
|
-
return out;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
function fixWinding(P, N, I, v0) {
|
|
177
|
-
// triangles are appended per card; check the first triangle referencing v0's range
|
|
178
|
-
for (let t = 0; t < I.length; t += 3) {
|
|
179
|
-
const a = I[t], b = I[t + 1], c = I[t + 2];
|
|
180
|
-
if (a < v0) continue;
|
|
181
|
-
const e1 = [P[b * 3] - P[a * 3], P[b * 3 + 1] - P[a * 3 + 1], P[b * 3 + 2] - P[a * 3 + 2]];
|
|
182
|
-
const e2 = [P[c * 3] - P[a * 3], P[c * 3 + 1] - P[a * 3 + 1], P[c * 3 + 2] - P[a * 3 + 2]];
|
|
183
|
-
const g = cross(e1, e2);
|
|
184
|
-
const d = g[0] * N[a * 3] + g[1] * N[a * 3 + 1] + g[2] * N[a * 3 + 2];
|
|
185
|
-
if (d < 0) { I[t + 1] = c; I[t + 2] = b; }
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
export { DEG };
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
// Knife-thin fin edges below the mesh cell size.
|
|
2
|
-
//
|
|
3
|
-
// A fin slab (SDFModel.fin) meshes with a rim no thinner than ~2 cells (thinner slabs alias into
|
|
4
|
-
// holes), so at 1 cm cells a shark's fins end in 2 cm rounded, rubbery edges. A fin primitive tagged
|
|
5
|
-
// `sharpen: { edge, band, rim }` has its meshed surface squeezed toward its mid-plane near its free
|
|
6
|
-
// outline: every vertex whose nearest fin slab is that primitive has its distance from the plane
|
|
7
|
-
// scaled by `edge` (e.g. 0.15) at the outline, easing back to 1 at `band` mesh cells (of the vertex's
|
|
8
|
-
// region, so every quality tier) inside it; the rounded rim beyond the outline is drawn in toward it
|
|
9
|
-
// by `rim` (0.4: to 0.4 of its width), so the squeezed edge runs straight instead of following the
|
|
10
|
-
// cells' sampling of the round cap. Where the fin grows out of the body (the field of the non-fin
|
|
11
|
-
// primitives within ~1.5-4 cells of the vertex) nothing moves, so the root fillet keeps its shape.
|
|
12
|
-
// Same vertex count; the field's analytic normals are carried through the squeeze (inverse transpose
|
|
13
|
-
// of its Jacobian), so the shading stays as smooth as the field's. Opt-in: no tagged primitive, no
|
|
14
|
-
// change.
|
|
15
|
-
import { SDFModel, T_FIN, polySD } from '../sdf/sdf.js';
|
|
16
|
-
|
|
17
|
-
const smooth = (a, b, x) => { const t = Math.min(1, Math.max(0, (x - a) / (b - a))); return t * t * (3 - 2 * t); };
|
|
18
|
-
const dsmooth = (a, b, x) => { if (x <= a || x >= b) return 0; const t = (x - a) / (b - a); return (6 * t * (1 - t)) / (b - a); };
|
|
19
|
-
|
|
20
|
-
/** @returns the number of vertices moved */
|
|
21
|
-
export function sharpenFinEdges({ pos, nrm, lists, nV, regionOf }, hOfRegion) {
|
|
22
|
-
let n = 0;
|
|
23
|
-
for (let v = 0; v < nV; v++) {
|
|
24
|
-
const L = lists[v];
|
|
25
|
-
if (!L) continue;
|
|
26
|
-
const h = hOfRegion[regionOf[v]];
|
|
27
|
-
let fin = null, best = Infinity;
|
|
28
|
-
const x = pos[v * 3], y = pos[v * 3 + 1], z = pos[v * 3 + 2];
|
|
29
|
-
for (const pr of L) {
|
|
30
|
-
if (pr.type !== T_FIN || !pr.sharpen || pr.carve) continue;
|
|
31
|
-
const d = Math.abs(SDFModel.dist(pr, x, y, z));
|
|
32
|
-
if (d < best) { best = d; fin = pr; }
|
|
33
|
-
}
|
|
34
|
-
if (!fin) continue;
|
|
35
|
-
const P = fin.P, S = fin.sharpen, e = S.edge, B = S.band * h, c = S.rim ?? 1;
|
|
36
|
-
const dx = x - P[0], dy = y - P[1], dz = z - P[2];
|
|
37
|
-
const pu = dx * P[3] + dy * P[4] + dz * P[5], pv = dx * P[6] + dy * P[7] + dz * P[8];
|
|
38
|
-
const pn = dx * P[9] + dy * P[10] + dz * P[11];
|
|
39
|
-
// depth inside the outline (< 0 on the rounded rim beyond it)
|
|
40
|
-
const din = -polySD(P, pu, pv);
|
|
41
|
-
if (din >= B) continue;
|
|
42
|
-
// the body around the root: the field of every non-fin primitive near the vertex
|
|
43
|
-
const rest = L.filter((pr) => pr.type !== T_FIN && !pr.carve);
|
|
44
|
-
const dBody = rest.length ? SDFModel.evalList(rest, x, y, z) : 1e9;
|
|
45
|
-
const wr = smooth(1.5 * h, 4 * h, dBody);
|
|
46
|
-
if (wr < 1e-3) continue;
|
|
47
|
-
// squeeze factor s(din) = 1 - wr (1 - k(din)), k = e + (1 - e) smooth(0, B, din)
|
|
48
|
-
const s = 1 - wr * (1 - e) * (1 - smooth(0, B, din));
|
|
49
|
-
const ds = wr * (1 - e) * dsmooth(0, B, din);
|
|
50
|
-
// in-plane gradient of din (unit, pointing into the fin)
|
|
51
|
-
const eps = 0.25 * h;
|
|
52
|
-
let gu = -(polySD(P, pu + eps, pv) - polySD(P, pu - eps, pv)) / (2 * eps);
|
|
53
|
-
let gv = -(polySD(P, pu, pv + eps) - polySD(P, pu, pv - eps)) / (2 * eps);
|
|
54
|
-
const gl = Math.hypot(gu, gv) || 1;
|
|
55
|
-
gu /= gl; gv /= gl;
|
|
56
|
-
const gx = P[3] * gu + P[6] * gv, gy = P[4] * gu + P[7] * gv, gz = P[5] * gu + P[8] * gv;
|
|
57
|
-
// the rim beyond the outline drawn in toward it (to c of its width)
|
|
58
|
-
const pull = din < 0 ? (1 - c) * -din * wr : 0;
|
|
59
|
-
const off = pn * (s - 1);
|
|
60
|
-
pos[v * 3] += P[9] * off + gx * pull; pos[v * 3 + 1] += P[10] * off + gy * pull; pos[v * 3 + 2] += P[11] * off + gz * pull;
|
|
61
|
-
// normal: J = I + nf a^T (a = (s - 1) nf + pn ds g) -> J^-T n0 = n0 - a (nf . n0) / s; the rim pull
|
|
62
|
-
// scales along g by c' = 1 - (1 - c) wr -> divide the g component by c'
|
|
63
|
-
let nx = nrm[v * 3], ny = nrm[v * 3 + 1], nz = nrm[v * 3 + 2];
|
|
64
|
-
const fn = (nx * P[9] + ny * P[10] + nz * P[11]) / s;
|
|
65
|
-
const ax = (s - 1) * P[9] + pn * ds * gx, ay = (s - 1) * P[10] + pn * ds * gy, az = (s - 1) * P[11] + pn * ds * gz;
|
|
66
|
-
nx -= ax * fn; ny -= ay * fn; nz -= az * fn;
|
|
67
|
-
if (din < 0 && c < 1) {
|
|
68
|
-
const cc = 1 - (1 - c) * wr, gn = (nx * gx + ny * gy + nz * gz) * (1 / cc - 1);
|
|
69
|
-
nx += gx * gn; ny += gy * gn; nz += gz * gn;
|
|
70
|
-
}
|
|
71
|
-
// at the knife edge itself the faces above and below meet: a vertex there (on the field's rounded
|
|
72
|
-
// cap, close to the mid-plane) takes the edge's in-plane normal; otherwise vertices a hair above and
|
|
73
|
-
// below the plane along the rim would alternate up / down normals (stripes across the edge)
|
|
74
|
-
const q = Math.abs(pn) / Math.max(1e-9, P[12]);
|
|
75
|
-
const fq = smooth(0.15, 0.7, q);
|
|
76
|
-
if (fq < 1) {
|
|
77
|
-
const nfc = (nx * P[9] + ny * P[10] + nz * P[11]) * (1 - fq);
|
|
78
|
-
nx -= P[9] * nfc; ny -= P[10] * nfc; nz -= P[11] * nfc;
|
|
79
|
-
}
|
|
80
|
-
const l = Math.hypot(nx, ny, nz) || 1;
|
|
81
|
-
nrm[v * 3] = nx / l; nrm[v * 3 + 1] = ny / l; nrm[v * 3 + 2] = nz / l;
|
|
82
|
-
n++;
|
|
83
|
-
}
|
|
84
|
-
return n;
|
|
85
|
-
}
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
// Fur-length slope limit (shorten only), applied by the pipeline to every coat.
|
|
2
|
-
//
|
|
3
|
-
// The coat shells are offset copies of the skin at hair height x (0..1) x furLen, so where the hair
|
|
4
|
-
// length jumps from one vertex to the next the shells stand up as a wall: a round pad with a hard
|
|
5
|
-
// rim (a cheek switched from 5 to 11 mm across a plane), an eye sunk in a ring of long fur, a strand
|
|
6
|
-
// pattern smeared into a smooth plate over the steep triangles. Real hair changes length gradually
|
|
7
|
-
// and lies over the shorter hair around it, so the coat surface has no cliffs.
|
|
8
|
-
//
|
|
9
|
-
// The limit: hair may grow no faster than `slope` metres of hair per metre of skin above the hair
|
|
10
|
-
// around it, U(v) = min(L(v), min_u U(u) + s(v) |p_u - p_v|) over the furred, hairy vertices of the
|
|
11
|
-
// same surface (a Dijkstra sweep from the shortest hair outward: exact, one pass). Long hair may rise
|
|
12
|
-
// proportionally faster, s(v) = slope x max(1, L(v) / free): every boundary then bevels over at most
|
|
13
|
-
// ~free / slope of skin whatever the hair length, so manes, ruffs, forelocks and fleeces keep
|
|
14
|
-
// standing off (their edge is beveled, not flattened) while a face loses its walls.
|
|
15
|
-
//
|
|
16
|
-
// Species control (optional):
|
|
17
|
-
// species.render.furSlope slope for hair up to `furSlopeFree` long (default 1); false / 0: off
|
|
18
|
-
// species.render.furSlopeFree hair length (m) above which the allowed slope grows (default 0.025)
|
|
19
|
-
// coat().furSlope per-vertex slope (Float32Array) replacing the default at that vertex;
|
|
20
|
-
// Infinity (or <= 0) leaves that vertex's hair as painted (a crest meant
|
|
21
|
-
// to stand up as a wall)
|
|
22
|
-
// Bare vertices (no hair, or a material without shells) neither limit nor get limited: fur may meet a
|
|
23
|
-
// lid margin, the nose leather or a hoof at full length.
|
|
24
|
-
|
|
25
|
-
export const FUR_SLOPE_DEFAULTS = { slope: 1.0, free: 0.025 };
|
|
26
|
-
|
|
27
|
-
const HAIRY = (m) => m === 0 || m === 4 || m === 8 || m === 9; // materials that grow shells (coatMaterial.js hairy())
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Shortens furLen in place so that no hair rises faster than the slope above its neighbours.
|
|
31
|
-
* @param {Float32Array} furLen per-vertex hair length (m), modified in place
|
|
32
|
-
* @param {Float32Array} pos per-vertex positions (reference space)
|
|
33
|
-
* @param {Uint32Array} index triangle indices
|
|
34
|
-
* @param {number} nV vertex count (vertices >= nV are ignored)
|
|
35
|
-
* @param {Float32Array} tint per-vertex rgba, a = material id
|
|
36
|
-
* @param {object} o { slope, free, perVertex }
|
|
37
|
-
* @returns {{ shortened: number, maxCut: number }} vertices shortened by more than 0.1 mm, the largest cut (m)
|
|
38
|
-
*/
|
|
39
|
-
export function limitFurSlope(furLen, pos, index, nV, tint, { slope = FUR_SLOPE_DEFAULTS.slope, free = FUR_SLOPE_DEFAULTS.free, perVertex = null } = {}) {
|
|
40
|
-
const res = { shortened: 0, maxCut: 0 };
|
|
41
|
-
if (!furLen || !(slope > 0) || !(free > 0)) return res;
|
|
42
|
-
const L0 = Float32Array.from(furLen.subarray(0, nV));
|
|
43
|
-
const active = new Uint8Array(nV);
|
|
44
|
-
let any = false;
|
|
45
|
-
for (let v = 0; v < nV; v++) {
|
|
46
|
-
if (L0[v] > 0 && HAIRY(Math.round(tint[v * 4 + 3]))) { active[v] = 1; any = true; }
|
|
47
|
-
}
|
|
48
|
-
if (!any) return res;
|
|
49
|
-
// the allowed slope of each vertex's hair (0 = unlimited)
|
|
50
|
-
const sOf = new Float32Array(nV);
|
|
51
|
-
for (let v = 0; v < nV; v++) {
|
|
52
|
-
if (!active[v]) continue;
|
|
53
|
-
let s = perVertex ? perVertex[v] : slope;
|
|
54
|
-
if (perVertex && !(s > 0)) s = Infinity; // a species' explicit "leave as painted"
|
|
55
|
-
sOf[v] = Number.isFinite(s) ? s * Math.max(1, L0[v] / free) : 0;
|
|
56
|
-
}
|
|
57
|
-
// adjacency (CSR) over the active vertices
|
|
58
|
-
const deg = new Uint32Array(nV + 1);
|
|
59
|
-
for (let i = 0; i < index.length; i += 3) {
|
|
60
|
-
for (let e = 0; e < 3; e++) {
|
|
61
|
-
const u = index[i + e], v = index[i + ((e + 1) % 3)];
|
|
62
|
-
if (u < nV && v < nV && active[u] && active[v]) { deg[u + 1]++; deg[v + 1]++; }
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
for (let v = 0; v < nV; v++) deg[v + 1] += deg[v];
|
|
66
|
-
const adj = new Uint32Array(deg[nV]), fill = deg.slice(0, nV);
|
|
67
|
-
for (let i = 0; i < index.length; i += 3) {
|
|
68
|
-
for (let e = 0; e < 3; e++) {
|
|
69
|
-
const u = index[i + e], v = index[i + ((e + 1) % 3)];
|
|
70
|
-
if (u < nV && v < nV && active[u] && active[v]) { adj[fill[u]++] = v; adj[fill[v]++] = u; }
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
// Dijkstra: settle vertices in increasing (limited) length; a settled vertex bounds its neighbours
|
|
74
|
-
const U = furLen;
|
|
75
|
-
let hk = new Float64Array(4096), hv = new Int32Array(4096), n = 0;
|
|
76
|
-
const push = (k, v) => {
|
|
77
|
-
if (n === hk.length) { const k2 = new Float64Array(n * 2); k2.set(hk); hk = k2; const v2 = new Int32Array(n * 2); v2.set(hv); hv = v2; }
|
|
78
|
-
let i = n++;
|
|
79
|
-
while (i > 0) { const p = (i - 1) >> 1; if (hk[p] <= k) break; hk[i] = hk[p]; hv[i] = hv[p]; i = p; }
|
|
80
|
-
hk[i] = k; hv[i] = v;
|
|
81
|
-
};
|
|
82
|
-
const pop = () => {
|
|
83
|
-
const top = hv[0], k = hk[--n], v = hv[n];
|
|
84
|
-
let i = 0;
|
|
85
|
-
for (;;) {
|
|
86
|
-
const l = 2 * i + 1;
|
|
87
|
-
if (l >= n) break;
|
|
88
|
-
const r = l + 1, m = r < n && hk[r] < hk[l] ? r : l;
|
|
89
|
-
if (hk[m] >= k) break;
|
|
90
|
-
hk[i] = hk[m]; hv[i] = hv[m]; i = m;
|
|
91
|
-
}
|
|
92
|
-
hk[i] = k; hv[i] = v;
|
|
93
|
-
return top;
|
|
94
|
-
};
|
|
95
|
-
const done = new Uint8Array(nV);
|
|
96
|
-
for (let v = 0; v < nV; v++) if (active[v]) push(U[v], v);
|
|
97
|
-
while (n) {
|
|
98
|
-
const v = pop();
|
|
99
|
-
if (done[v]) continue;
|
|
100
|
-
done[v] = 1;
|
|
101
|
-
const Uv = U[v], px = pos[v * 3], py = pos[v * 3 + 1], pz = pos[v * 3 + 2];
|
|
102
|
-
for (let k = deg[v]; k < deg[v + 1]; k++) {
|
|
103
|
-
const u = adj[k];
|
|
104
|
-
if (done[u] || sOf[u] === 0) continue;
|
|
105
|
-
const cand = Uv + sOf[u] * Math.hypot(pos[u * 3] - px, pos[u * 3 + 1] - py, pos[u * 3 + 2] - pz);
|
|
106
|
-
if (cand < U[u]) { U[u] = cand; push(cand, u); }
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
for (let v = 0; v < nV; v++) {
|
|
110
|
-
const cut = L0[v] - U[v];
|
|
111
|
-
if (cut > 0.0001) res.shortened++;
|
|
112
|
-
if (cut > res.maxCut) res.maxCut = cut;
|
|
113
|
-
}
|
|
114
|
-
return res;
|
|
115
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
// Meshing stage: turns a species' SDF sculpt into surface pieces ("regions").
|
|
2
|
-
//
|
|
3
|
-
// A species describes its regions as jobs (each job can run in its own worker):
|
|
4
|
-
// { name, part, bmin, bmax, h, F?, clip?(x,y,z), patches?: [{ c, R, B, h }], rigidBone? }
|
|
5
|
-
// part: which primitives to mesh (primitives carry part: 'body' | 'jaw' | ...)
|
|
6
|
-
// h: cell size in metres (quality tiers multiply it)
|
|
7
|
-
// clip: keep only cells whose centre passes (used for overlapping regions that cross-fade)
|
|
8
|
-
// patches: balls re-meshed at a finer cell size (eyelid margins); the region itself is clipped
|
|
9
|
-
// to exclude the inner ball and the two cross-fade in a thin shell
|
|
10
|
-
// rigidBone: the whole region follows one bone (a separately meshed jaw)
|
|
11
|
-
import { meshSDF } from '../sdf/mesher.js';
|
|
12
|
-
|
|
13
|
-
export function meshRegion(model, R) {
|
|
14
|
-
const prims = model.forPart(R.part || 'body');
|
|
15
|
-
if (!prims.length) throw new Error(`region ${R.name}: no primitives in part ${R.part}`);
|
|
16
|
-
const d2 = (x, y, z, c) => (x - c[0]) * (x - c[0]) + (y - c[1]) * (y - c[1]) + (z - c[2]) * (z - c[2]);
|
|
17
|
-
const patches = R.patches || [];
|
|
18
|
-
const baseClip = R.clip || null;
|
|
19
|
-
// The region stops one of its own cells inside the patch's inner radius: its cut is as ragged as its
|
|
20
|
-
// cells, and a cut that pokes past the middle of the cross-fade band (a cell wider than the band B) left
|
|
21
|
-
// a slit there that neither surface covered; one cell further in, the cut lies where the patch shows
|
|
22
|
-
// alone and the region's fade is ~0 (drawn nowhere).
|
|
23
|
-
const clip = patches.length
|
|
24
|
-
? (x, y, z) => (!baseClip || baseClip(x, y, z)) && patches.every((p) => d2(x, y, z, p.c) > Math.max(0, p.R - p.B - R.h) ** 2)
|
|
25
|
-
: baseClip;
|
|
26
|
-
const parts = [meshSDF(prims, R.bmin, R.bmax, R.h, R.F || 6, null, clip)];
|
|
27
|
-
for (const p of patches) {
|
|
28
|
-
const rOut = p.R + p.B, pad = rOut + 3 * p.h;
|
|
29
|
-
parts.push(meshSDF(prims, [p.c[0] - pad, p.c[1] - pad, p.c[2] - pad], [p.c[0] + pad, p.c[1] + pad, p.c[2] + pad], p.h, 4, null, (x, y, z) => d2(x, y, z, p.c) < rOut * rOut && (!baseClip || baseClip(x, y, z))));
|
|
30
|
-
}
|
|
31
|
-
const m = parts.length > 1 ? mergeMeshes(parts) : { ...parts[0], patch: null };
|
|
32
|
-
return serialiseLists({ name: R.name, ...m });
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function mergeMeshes(meshes) {
|
|
36
|
-
let n = 0, ni = 0;
|
|
37
|
-
for (const m of meshes) { n += m.count; ni += m.indices.length; }
|
|
38
|
-
const positions = new Float32Array(n * 3), normals = new Float32Array(n * 3), indices = new Uint32Array(ni), patch = new Uint8Array(n);
|
|
39
|
-
const lists = new Array(n);
|
|
40
|
-
let v0 = 0, i0 = 0;
|
|
41
|
-
meshes.forEach((m, k) => {
|
|
42
|
-
positions.set(m.positions, v0 * 3);
|
|
43
|
-
normals.set(m.normals, v0 * 3);
|
|
44
|
-
for (let i = 0; i < m.indices.length; i++) indices[i0 + i] = m.indices[i] + v0;
|
|
45
|
-
for (let i = 0; i < m.count; i++) { lists[v0 + i] = m.lists[i]; patch[v0 + i] = k > 0 ? 1 : 0; }
|
|
46
|
-
v0 += m.count; i0 += m.indices.length;
|
|
47
|
-
});
|
|
48
|
-
return { positions, normals, indices, lists, count: n, patch };
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// replace per-vertex primitive lists by ids so a region can cross a worker boundary
|
|
52
|
-
function serialiseLists(p) {
|
|
53
|
-
const uniq = new Map();
|
|
54
|
-
const listIndex = new Uint32Array(p.count);
|
|
55
|
-
const listIds = [];
|
|
56
|
-
for (let v = 0; v < p.count; v++) {
|
|
57
|
-
const l = p.lists[v];
|
|
58
|
-
let k = uniq.get(l);
|
|
59
|
-
if (k === undefined) { k = listIds.length; uniq.set(l, k); listIds.push(Int16Array.from(l.map((q) => q.id))); }
|
|
60
|
-
listIndex[v] = k;
|
|
61
|
-
}
|
|
62
|
-
return { name: p.name, positions: p.positions, normals: p.normals, indices: p.indices, count: p.count, listIndex, listIds, patch: p.patch || null };
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function regionTransferables(parts) {
|
|
66
|
-
return parts.flatMap((p) => [p.positions.buffer, p.normals.buffer, p.indices.buffer, p.listIndex.buffer]);
|
|
67
|
-
}
|