reze-engine 0.66.4 → 0.67.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/dist/engine.d.ts +75 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +182 -18
- package/dist/graph/presets/body.js +1 -1
- package/dist/graph/presets/cloth_rough.js +1 -1
- package/dist/graph/presets/cloth_smooth.js +1 -1
- package/dist/graph/presets/face.js +1 -1
- package/dist/graph/presets/metal.js +1 -1
- package/dist/graph/registry.d.ts.map +1 -1
- package/dist/graph/registry.js +84 -6
- package/dist/graph/schema.d.ts +14 -0
- package/dist/graph/schema.d.ts.map +1 -1
- package/dist/shaders/materials/nodes.d.ts +1 -1
- package/dist/shaders/materials/nodes.d.ts.map +1 -1
- package/dist/shaders/materials/nodes.js +176 -7
- package/dist/shaders/passes/composite.d.ts.map +1 -1
- package/dist/shaders/passes/composite.js +4 -2
- package/dist/shaders/passes/outline.d.ts +13 -0
- package/dist/shaders/passes/outline.d.ts.map +1 -1
- package/dist/shaders/passes/outline.js +82 -18
- package/package.json +1 -1
- package/src/engine.ts +199 -20
- package/src/graph/presets/body.ts +1 -1
- package/src/graph/presets/cloth_rough.ts +1 -1
- package/src/graph/presets/cloth_smooth.ts +1 -1
- package/src/graph/presets/face.ts +1 -1
- package/src/graph/presets/metal.ts +1 -1
- package/src/graph/registry.ts +85 -6
- package/src/graph/schema.ts +14 -0
- package/src/shaders/materials/nodes.ts +176 -7
- package/src/shaders/passes/composite.ts +4 -2
- package/src/shaders/passes/outline.ts +82 -18
package/dist/engine.js
CHANGED
|
@@ -36,7 +36,7 @@ import { sceneTargets as sceneTargetsFor, sceneColorFormats, setMrtIds, mrtIdsEn
|
|
|
36
36
|
import { LIGHT_GRID_BASE, LIGHT_HEADER, LIGHT_STRIDE, LIGHTS_FLOATS, MAX_LIGHTS, buildLightEmitShader, hasLightEmit, } from "./shaders/lights";
|
|
37
37
|
import { buildLightGrid } from "./light-grid";
|
|
38
38
|
import { groundShaderWgsl, GROUND_NOISE_BAKE_WGSL, GROUND_NOISE_SIZE } from "./shaders/passes/ground";
|
|
39
|
-
import { outlineShaderWgsl, RZ_OUTLINE_DISSOLVE_OFFSET } from "./shaders/passes/outline";
|
|
39
|
+
import { outlineShaderWgsl, RZ_OUTLINE_COLOR_OFFSET, RZ_OUTLINE_DISSOLVE_OFFSET, RZ_OUTLINE_SHADOW_OFFSET, RZ_OUTLINE_TEXTURED_OFFSET, RZ_OUTLINE_WIDTH_OFFSET, } from "./shaders/passes/outline";
|
|
40
40
|
import { transparentDepthPrepassWgsl } from "./shaders/passes/depth-prepass";
|
|
41
41
|
import { SELECTION_MASK_SHADER_WGSL, SELECTION_EDGE_SHADER_WGSL } from "./shaders/passes/selection";
|
|
42
42
|
import { GIZMO_SHADER_WGSL } from "./shaders/passes/gizmo";
|
|
@@ -101,7 +101,7 @@ const PRESET_NAME_HINTS = [
|
|
|
101
101
|
"hair", "ahoge", "bang",
|
|
102
102
|
],
|
|
103
103
|
],
|
|
104
|
-
["body", ["肌", "皮肤", "skin"]],
|
|
104
|
+
["body", ["肌", "皮肤", "skin", "指甲", "nail"]],
|
|
105
105
|
["metal", ["金属", "メタル", "metal", "earring", "耳环", "耳環"]],
|
|
106
106
|
[
|
|
107
107
|
"cloth_smooth",
|
|
@@ -146,6 +146,10 @@ const PRESET_NAME_HINTS = [
|
|
|
146
146
|
],
|
|
147
147
|
],
|
|
148
148
|
];
|
|
149
|
+
// Whole names that are body parts — skin by another name. Whole, never
|
|
150
|
+
// substrings: 手 alone is a hand, inside 手套 (gloves) or 手镯 (a bracelet) it is
|
|
151
|
+
// what the hand wears; 足 is a leg, 足袋 a sock.
|
|
152
|
+
const BODY_PART_NAMES = new Set(["手", "手部", "腕", "足", "脚", "腿", "爪", "hand", "hands", "arm", "arms", "leg", "legs", "body"]);
|
|
149
153
|
// Resolve a material name to a style category (override map first, then name hints), or
|
|
150
154
|
// null if nothing matches — a null-resolving material stays ungrouped (neutral default).
|
|
151
155
|
function resolvePreset(materialName, map) {
|
|
@@ -156,6 +160,8 @@ function resolvePreset(materialName, map) {
|
|
|
156
160
|
}
|
|
157
161
|
}
|
|
158
162
|
const lower = materialName.toLowerCase();
|
|
163
|
+
if (BODY_PART_NAMES.has(lower.replace(/[\s_.\-0-9]+$/, "")))
|
|
164
|
+
return "body";
|
|
159
165
|
for (const [preset, hints] of PRESET_NAME_HINTS) {
|
|
160
166
|
for (const hint of hints) {
|
|
161
167
|
if (lower.includes(hint))
|
|
@@ -245,6 +251,7 @@ export const DEFAULT_DEPTH_OF_FIELD_OPTIONS = {
|
|
|
245
251
|
export const DEFAULT_VIEW_TRANSFORM = {
|
|
246
252
|
exposure: 0,
|
|
247
253
|
gamma: 1.0,
|
|
254
|
+
contrast: 1.4,
|
|
248
255
|
transform: "soft",
|
|
249
256
|
};
|
|
250
257
|
const NEUTRAL_GRADE_CHANNEL = 0.5;
|
|
@@ -1071,7 +1078,7 @@ export class Engine {
|
|
|
1071
1078
|
// 15 × vec4f — see the viewU comment in composite.ts. The last one is the
|
|
1072
1079
|
// camera's world position, which is what lets a foreground effect turn the
|
|
1073
1080
|
// depth it is handed into a PLACE (bgWorldPos) rather than a distance.
|
|
1074
|
-
this.compositeUniformData = new Float32Array(
|
|
1081
|
+
this.compositeUniformData = new Float32Array(64);
|
|
1075
1082
|
/** Composite background (display-space sRGB 0–1) — null = transparent canvas. */
|
|
1076
1083
|
this.backgroundColor = null;
|
|
1077
1084
|
// 360 backdrop (equirectangular skybox, sampled by view ray in composite).
|
|
@@ -1337,6 +1344,25 @@ export class Engine {
|
|
|
1337
1344
|
// cloth. The full MMD-faithful machinery (interleaved per-material hulls,
|
|
1338
1345
|
// texture-alpha-modulated rims) stays in place behind setOutlineEnabled(true).
|
|
1339
1346
|
this.outlineEnabled = false;
|
|
1347
|
+
/**
|
|
1348
|
+
* Every outline's width, as a multiple of what each PMX material asked for
|
|
1349
|
+
* (its edgeSize): 1 is the author's own, 0 draws none. A multiplier rather
|
|
1350
|
+
* than a width because a model's lines are not one width — the hair's rim
|
|
1351
|
+
* and a sleeve's crease differ on purpose, and scaling keeps that.
|
|
1352
|
+
*
|
|
1353
|
+
* A write, not a re-record: one float in each hull's uniform, so a slider
|
|
1354
|
+
* can drive it. Hulls built later take the current value at creation.
|
|
1355
|
+
*/
|
|
1356
|
+
this.outlineWidth = 1;
|
|
1357
|
+
/**
|
|
1358
|
+
* One colour for every outline, in place of each PMX material's edge colour;
|
|
1359
|
+
* null hands each material its own back. Written as the edge colour is —
|
|
1360
|
+
* the values a PMX would carry — so a picked black is MMD's black. The
|
|
1361
|
+
* material's edge ALPHA is kept: only the hue is the scene's.
|
|
1362
|
+
*
|
|
1363
|
+
* A write, like setOutlineWidth: hulls built later take it at creation.
|
|
1364
|
+
*/
|
|
1365
|
+
this.outlineColor = [0, 0, 0, 0];
|
|
1340
1366
|
/** Distinct uncaptured validation messages → how many times each arrived. */
|
|
1341
1367
|
this.gpuErrors = new Map();
|
|
1342
1368
|
/** When set, render resolution is pinned to this size instead of tracking the
|
|
@@ -1353,6 +1379,25 @@ export class Engine {
|
|
|
1353
1379
|
/** A pose pushed in from outside — see setCameraPose. Reapplied every frame,
|
|
1354
1380
|
* so it outranks the orbit AND a loaded track for as long as it is set. */
|
|
1355
1381
|
this.cameraPoseOverride = null;
|
|
1382
|
+
/**
|
|
1383
|
+
* The host's adjustment to a camera track, added to every pose it samples.
|
|
1384
|
+
*
|
|
1385
|
+
* A downloaded camera motion is framed for whoever it was made with: a
|
|
1386
|
+
* shorter model wants it lower, a wider stage wants it further back. This
|
|
1387
|
+
* moves the shot without touching its ANGLE — the motion's rotation and roll
|
|
1388
|
+
* are its choreography, and they stay the track's.
|
|
1389
|
+
*
|
|
1390
|
+
* - `target`: world units, added to the look-at point, so the whole shot
|
|
1391
|
+
* slides with the angle unchanged.
|
|
1392
|
+
* - `distance`: positive pulls the eye further back along its own line of
|
|
1393
|
+
* sight. VMD distances are signed (negative is behind the target, the usual
|
|
1394
|
+
* case), so "further" means away from zero on whichever side it is.
|
|
1395
|
+
* - `fov`: radians, added to the track's lens, never below a sliver.
|
|
1396
|
+
*
|
|
1397
|
+
* Only a loaded track reads it: the orbit has its own sliders, and a pose
|
|
1398
|
+
* forced through setCameraPose is a statement of where the camera IS.
|
|
1399
|
+
*/
|
|
1400
|
+
this.cameraTrackOffset = { target: new Vec3(0, 0, 0), distance: 0, fov: 0 };
|
|
1356
1401
|
/**
|
|
1357
1402
|
* The per-frame bind groups, the camera's and the mirror's.
|
|
1358
1403
|
*
|
|
@@ -1727,6 +1772,7 @@ export class Engine {
|
|
|
1727
1772
|
return {
|
|
1728
1773
|
exposure: partial?.exposure ?? d.exposure,
|
|
1729
1774
|
gamma: partial?.gamma ?? d.gamma,
|
|
1775
|
+
contrast: partial?.contrast ?? d.contrast,
|
|
1730
1776
|
transform: partial?.transform ?? d.transform,
|
|
1731
1777
|
};
|
|
1732
1778
|
}
|
|
@@ -1743,7 +1789,7 @@ export class Engine {
|
|
|
1743
1789
|
}
|
|
1744
1790
|
getViewTransformOptions() {
|
|
1745
1791
|
const v = this.viewTransform;
|
|
1746
|
-
return { exposure: v.exposure, gamma: v.gamma, transform: v.transform };
|
|
1792
|
+
return { exposure: v.exposure, gamma: v.gamma, contrast: v.contrast, transform: v.transform };
|
|
1747
1793
|
}
|
|
1748
1794
|
/**
|
|
1749
1795
|
* Color-grade the tonemapped scene (ASC CDL slope/offset/power + saturation).
|
|
@@ -1853,6 +1899,8 @@ export class Engine {
|
|
|
1853
1899
|
v.exposure = patch.exposure;
|
|
1854
1900
|
if (patch.gamma !== undefined)
|
|
1855
1901
|
v.gamma = patch.gamma;
|
|
1902
|
+
if (patch.contrast !== undefined)
|
|
1903
|
+
v.contrast = patch.contrast;
|
|
1856
1904
|
if (patch.transform !== undefined)
|
|
1857
1905
|
v.transform = patch.transform;
|
|
1858
1906
|
if (this.device && this.compositeUniformBuffer) {
|
|
@@ -1922,6 +1970,9 @@ export class Engine {
|
|
|
1922
1970
|
u[25] = Engine.VIEW_TRANSFORM_ID[v.transform] ?? 0;
|
|
1923
1971
|
u[26] = this.canvas.width;
|
|
1924
1972
|
u[27] = this.canvas.height;
|
|
1973
|
+
// The soft curve's power (viewU[15].x), the scene's own (SceneSetting._contrast).
|
|
1974
|
+
// Its own vec4: viewU[11..14] are the cast's positions whenever an effect runs.
|
|
1975
|
+
u[60] = v.contrast;
|
|
1925
1976
|
// ── Grade (viewU[7..9]) ── The UI's three tonal COLORS map to ASC CDL here,
|
|
1926
1977
|
// on the CPU, so the shader only ever sees slope/offset/power. Mid-gray is
|
|
1927
1978
|
// neutral in all three; the signed distance from it is the amount.
|
|
@@ -1971,6 +2022,34 @@ export class Engine {
|
|
|
1971
2022
|
// per-frame state, which is what makes that affordable.
|
|
1972
2023
|
this.bundlesDirty = true;
|
|
1973
2024
|
}
|
|
2025
|
+
setOutlineWidth(scale) {
|
|
2026
|
+
const v = Number.isFinite(scale) ? Math.max(0, scale) : 1;
|
|
2027
|
+
if (this.outlineWidth === v)
|
|
2028
|
+
return;
|
|
2029
|
+
this.outlineWidth = v;
|
|
2030
|
+
if (!this.device)
|
|
2031
|
+
return;
|
|
2032
|
+
const one = new Float32Array([v]);
|
|
2033
|
+
for (const inst of this.modelInstances.values()) {
|
|
2034
|
+
for (const buffer of inst.outlineUniformBuffers) {
|
|
2035
|
+
this.device.queue.writeBuffer(buffer, RZ_OUTLINE_WIDTH_OFFSET, one);
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
setOutlineColor(color) {
|
|
2040
|
+
const next = color ? [color.x, color.y, color.z, 1] : [0, 0, 0, 0];
|
|
2041
|
+
if (next.every((v, i) => v === this.outlineColor[i]))
|
|
2042
|
+
return;
|
|
2043
|
+
this.outlineColor = next;
|
|
2044
|
+
if (!this.device)
|
|
2045
|
+
return;
|
|
2046
|
+
const data = new Float32Array(next);
|
|
2047
|
+
for (const inst of this.modelInstances.values()) {
|
|
2048
|
+
for (const buffer of inst.outlineUniformBuffers) {
|
|
2049
|
+
this.device.queue.writeBuffer(buffer, RZ_OUTLINE_COLOR_OFFSET, data);
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
1974
2053
|
/**
|
|
1975
2054
|
* Draw the id attachment instead of the scene.
|
|
1976
2055
|
*
|
|
@@ -6766,6 +6845,8 @@ export class Engine {
|
|
|
6766
6845
|
entries: [
|
|
6767
6846
|
{ binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: "uniform" } },
|
|
6768
6847
|
{ binding: 1, visibility: GPUShaderStage.FRAGMENT, sampler: { type: "filtering" } },
|
|
6848
|
+
// the key light, for a style graph's outline colour (see outline.ts)
|
|
6849
|
+
{ binding: 2, visibility: GPUShaderStage.FRAGMENT, buffer: { type: "uniform" } },
|
|
6769
6850
|
],
|
|
6770
6851
|
});
|
|
6771
6852
|
// Outline per-instance reuses mainPerInstanceBindGroupLayout (same skinMats binding)
|
|
@@ -6774,6 +6855,7 @@ export class Engine {
|
|
|
6774
6855
|
entries: [
|
|
6775
6856
|
{ binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: "uniform" } },
|
|
6776
6857
|
{ binding: 1, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: "float" } },
|
|
6858
|
+
{ binding: 2, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: "float" } },
|
|
6777
6859
|
],
|
|
6778
6860
|
});
|
|
6779
6861
|
const outlinePipelineLayout = this.device.createPipelineLayout({
|
|
@@ -6790,6 +6872,7 @@ export class Engine {
|
|
|
6790
6872
|
entries: [
|
|
6791
6873
|
{ binding: 0, resource: { buffer: this.cameraUniformBuffer } },
|
|
6792
6874
|
{ binding: 1, resource: this.materialSampler },
|
|
6875
|
+
{ binding: 2, resource: { buffer: this.lightUniformBuffer } },
|
|
6793
6876
|
],
|
|
6794
6877
|
});
|
|
6795
6878
|
// The same group on the MIRROR camera. An outline is geometry expanded
|
|
@@ -6802,6 +6885,7 @@ export class Engine {
|
|
|
6802
6885
|
entries: [
|
|
6803
6886
|
{ binding: 0, resource: { buffer: this.mirrorCameraBuffer } },
|
|
6804
6887
|
{ binding: 1, resource: this.materialSampler },
|
|
6888
|
+
{ binding: 2, resource: { buffer: this.lightUniformBuffer } },
|
|
6805
6889
|
],
|
|
6806
6890
|
});
|
|
6807
6891
|
const outlineShaderModule = this.device.createShaderModule({
|
|
@@ -6971,13 +7055,14 @@ export class Engine {
|
|
|
6971
7055
|
// strength belong to the combine step.
|
|
6972
7056
|
this.compositeUniformBuffer = this.device.createBuffer({
|
|
6973
7057
|
label: "composite view uniforms",
|
|
6974
|
-
//
|
|
7058
|
+
// 16 × vec4f: (exposure, invGamma, _, _) · (bloom tint, intensity) ·
|
|
6975
7059
|
// (bg rgb, mode) · camera right/up/forward basis for the 360 skybox ray ·
|
|
6976
7060
|
// (time, _, canvas width, canvas height) for user effects · three grade
|
|
6977
7061
|
// vectors (CDL offset+contrast, power+saturation, slope+flag) · camera
|
|
6978
7062
|
// world position, for an effect placing itself in the scene · four
|
|
6979
|
-
// character positions, for one that wants to respond to the cast
|
|
6980
|
-
|
|
7063
|
+
// character positions, for one that wants to respond to the cast · the
|
|
7064
|
+
// soft curve's contrast. Shaders that stop at the cast declare 15.
|
|
7065
|
+
size: 256,
|
|
6981
7066
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
6982
7067
|
});
|
|
6983
7068
|
this.dofUniformBuffer = this.device.createBuffer({
|
|
@@ -8197,6 +8282,26 @@ export class Engine {
|
|
|
8197
8282
|
if (this.cameraPoseOverride)
|
|
8198
8283
|
this.camera.setVmdPose(this.cameraPoseOverride);
|
|
8199
8284
|
}
|
|
8285
|
+
setCameraTrackOffset(offset) {
|
|
8286
|
+
const t = offset?.target;
|
|
8287
|
+
this.cameraTrackOffset = {
|
|
8288
|
+
target: new Vec3(t?.x ?? 0, t?.y ?? 0, t?.z ?? 0),
|
|
8289
|
+
distance: offset?.distance ?? 0,
|
|
8290
|
+
fov: offset?.fov ?? 0,
|
|
8291
|
+
};
|
|
8292
|
+
}
|
|
8293
|
+
/** A sampled track pose with the host's offset laid on. */
|
|
8294
|
+
offsetTrackPose(pose) {
|
|
8295
|
+
const o = this.cameraTrackOffset;
|
|
8296
|
+
if (o.distance === 0 && o.fov === 0 && o.target.x === 0 && o.target.y === 0 && o.target.z === 0)
|
|
8297
|
+
return pose;
|
|
8298
|
+
return {
|
|
8299
|
+
target: new Vec3(pose.target.x + o.target.x, pose.target.y + o.target.y, pose.target.z + o.target.z),
|
|
8300
|
+
rotation: pose.rotation,
|
|
8301
|
+
distance: pose.distance + Math.sign(pose.distance || -1) * o.distance,
|
|
8302
|
+
fov: Math.min(Math.PI * 0.95, Math.max(0.01, pose.fov + o.fov)),
|
|
8303
|
+
};
|
|
8304
|
+
}
|
|
8200
8305
|
/** The pose currently forced from outside, or null when nothing is. */
|
|
8201
8306
|
getCameraPoseOverride() {
|
|
8202
8307
|
return this.cameraPoseOverride;
|
|
@@ -9143,6 +9248,12 @@ export class Engine {
|
|
|
9143
9248
|
{ binding: 12, resource: { buffer: this.probeUniformBuffer } },
|
|
9144
9249
|
],
|
|
9145
9250
|
});
|
|
9251
|
+
// The recorded phases bind these groups by value (sceneView), so a rebuild
|
|
9252
|
+
// they never hear about leaves them drawing with the old one: the first
|
|
9253
|
+
// light cookie landed on the ground (re-bound each frame) and not on the
|
|
9254
|
+
// cast, and a swapped sky kept reflecting the one it replaced. Only init,
|
|
9255
|
+
// a world install and the first cookie get here, so re-recording is cheap.
|
|
9256
|
+
this.bundlesDirty = true;
|
|
9146
9257
|
return true;
|
|
9147
9258
|
}
|
|
9148
9259
|
/**
|
|
@@ -12692,6 +12803,7 @@ export class Engine {
|
|
|
12692
12803
|
dissolve: 1,
|
|
12693
12804
|
materialUniformBuffers: [],
|
|
12694
12805
|
outlineUniformBuffers: [],
|
|
12806
|
+
outlineByMaterial: new Map(),
|
|
12695
12807
|
cullModelIndex: 0,
|
|
12696
12808
|
// Seeded false: the first skin-matrix upload decides it, and until then the
|
|
12697
12809
|
// sphere path is the safe answer (it never culls something it should not).
|
|
@@ -13229,8 +13341,12 @@ export class Engine {
|
|
|
13229
13341
|
// every material — on the heaviest mesh in the scene that doubles the
|
|
13230
13342
|
// geometry submitted per frame to draw cartoon outlines around
|
|
13231
13343
|
// architecture, which is not the look anyone is after.
|
|
13344
|
+
// Every character material gets its hull: the PMX edge flag draws it as
|
|
13345
|
+
// MMD does, and a style group whose look carries an outline draws it on
|
|
13346
|
+
// any material (assignDrawCallGroups sets `drawn`).
|
|
13232
13347
|
let outline;
|
|
13233
|
-
|
|
13348
|
+
const pmxEdge = (mat.edgeFlag & 0x10) !== 0 && mat.edgeSize > 0;
|
|
13349
|
+
if (!inst.isStage) {
|
|
13234
13350
|
const materialUniformData = new Float32Array([
|
|
13235
13351
|
mat.edgeColor[0],
|
|
13236
13352
|
mat.edgeColor[1],
|
|
@@ -13243,21 +13359,31 @@ export class Engine {
|
|
|
13243
13359
|
// block's layout would be 32 bytes of padding per outlined material
|
|
13244
13360
|
// to carry one float. See RZ_OUTLINE_DISSOLVE_OFFSET.
|
|
13245
13361
|
1,
|
|
13362
|
+
// The scene's width multiplier, at RZ_OUTLINE_WIDTH_OFFSET.
|
|
13363
|
+
this.outlineWidth,
|
|
13364
|
+
// A style graph's outline, at RZ_OUTLINE_TEXTURED_OFFSET: none yet.
|
|
13365
|
+
0,
|
|
13366
|
+
// The scene's colour override, at RZ_OUTLINE_COLOR_OFFSET.
|
|
13367
|
+
this.outlineColor[0],
|
|
13368
|
+
this.outlineColor[1],
|
|
13369
|
+
this.outlineColor[2],
|
|
13370
|
+
this.outlineColor[3],
|
|
13371
|
+
// The graph outline's shadow colour, at RZ_OUTLINE_SHADOW_OFFSET.
|
|
13372
|
+
0,
|
|
13373
|
+
0,
|
|
13246
13374
|
0,
|
|
13247
13375
|
0,
|
|
13248
13376
|
]);
|
|
13249
13377
|
const outlineUniformBuffer = this.createUniformBuffer(`${prefix}outline: ${mat.name}`, materialUniformData);
|
|
13250
13378
|
inst.gpuBuffers.push(outlineUniformBuffer);
|
|
13251
13379
|
inst.outlineUniformBuffers.push(outlineUniformBuffer);
|
|
13252
|
-
|
|
13253
|
-
|
|
13254
|
-
|
|
13255
|
-
|
|
13256
|
-
{ binding: 0, resource: { buffer: outlineUniformBuffer } },
|
|
13257
|
-
{ binding: 1, resource: textureView },
|
|
13258
|
-
],
|
|
13380
|
+
inst.outlineByMaterial.set(mat.name, {
|
|
13381
|
+
buffer: outlineUniformBuffer,
|
|
13382
|
+
edge: materialUniformData.slice(0, 5),
|
|
13383
|
+
picture: textureView,
|
|
13259
13384
|
});
|
|
13260
|
-
|
|
13385
|
+
const outlineBindGroup = this.outlineBindGroup(`${prefix}outline: ${mat.name}`, outlineUniformBuffer, textureView, null);
|
|
13386
|
+
outline = { bindGroup: outlineBindGroup, pmx: pmxEdge, drawn: pmxEdge };
|
|
13261
13387
|
if (!inst.outlineVertexBuffer) {
|
|
13262
13388
|
const data = inst.model.getOutlineVertices();
|
|
13263
13389
|
const buf = this.device.createBuffer({
|
|
@@ -14532,7 +14658,7 @@ export class Engine {
|
|
|
14532
14658
|
// Drive the shot from the camera VMD (synced to the animated model's clock).
|
|
14533
14659
|
const pose = this.cameraAnimation.sample(this.transportTime());
|
|
14534
14660
|
if (pose)
|
|
14535
|
-
this.camera.setVmdPose(pose);
|
|
14661
|
+
this.camera.setVmdPose(this.offsetTrackPose(pose));
|
|
14536
14662
|
}
|
|
14537
14663
|
// Before the cast is written, which carries every subject's dissolve to the
|
|
14538
14664
|
// effects reading it.
|
|
@@ -15480,8 +15606,46 @@ export class Engine {
|
|
|
15480
15606
|
}
|
|
15481
15607
|
// Rebind each material draw call to its (successfully-installed) group's uniform buffer,
|
|
15482
15608
|
// or the zero buffer when ungrouped, then re-sort by render-class draw order.
|
|
15609
|
+
/** A hull's per-material group: its block, the picture, the look's tint. */
|
|
15610
|
+
outlineBindGroup(label, buffer, picture, tint) {
|
|
15611
|
+
return this.device.createBindGroup({
|
|
15612
|
+
label,
|
|
15613
|
+
layout: this.outlinePerMaterialBindGroupLayout,
|
|
15614
|
+
entries: [
|
|
15615
|
+
{ binding: 0, resource: { buffer } },
|
|
15616
|
+
{ binding: 1, resource: picture },
|
|
15617
|
+
{ binding: 2, resource: (tint ?? this.fallbackMaterialTexture).createView() },
|
|
15618
|
+
],
|
|
15619
|
+
});
|
|
15620
|
+
}
|
|
15483
15621
|
assignDrawCallGroups(inst, claimed) {
|
|
15484
15622
|
inst.materialToGroup.clear();
|
|
15623
|
+
// The hulls: a group whose look carries an outline (ShaderGraph.outline)
|
|
15624
|
+
// draws it in place of the PMX edge; the rest keep, or get back, their own.
|
|
15625
|
+
for (const [name, hull] of inst.outlineByMaterial) {
|
|
15626
|
+
const id = claimed.get(name);
|
|
15627
|
+
const install = id ? inst.styleGroups.get(id) : undefined;
|
|
15628
|
+
const o = install?.group.graph.outline;
|
|
15629
|
+
const block = o
|
|
15630
|
+
? new Float32Array([o.color[0], o.color[1], o.color[2], 1, o.width])
|
|
15631
|
+
: hull.edge;
|
|
15632
|
+
this.device.queue.writeBuffer(hull.buffer, 0, block);
|
|
15633
|
+
this.device.queue.writeBuffer(hull.buffer, RZ_OUTLINE_TEXTURED_OFFSET, new Float32Array([o ? 1 : 0]));
|
|
15634
|
+
if (o)
|
|
15635
|
+
this.device.queue.writeBuffer(hull.buffer, RZ_OUTLINE_SHADOW_OFFSET, new Float32Array([...o.shadowColor, 1]));
|
|
15636
|
+
const tint = o?.tint != null ? (install?.imagesByMaterial?.[name] ?? install?.images)?.[o.tint] ?? null : null;
|
|
15637
|
+
for (const dc of inst.drawCalls) {
|
|
15638
|
+
if (dc.materialName !== name || !dc.outline)
|
|
15639
|
+
continue;
|
|
15640
|
+
dc.outline.bindGroup = this.outlineBindGroup(`outline: ${name}`, hull.buffer, hull.picture, tint);
|
|
15641
|
+
this.bundlesDirty = true;
|
|
15642
|
+
const drawn = o ? o.width > 0 : dc.outline.pmx;
|
|
15643
|
+
if (dc.outline.drawn !== drawn) {
|
|
15644
|
+
dc.outline.drawn = drawn;
|
|
15645
|
+
this.bundlesDirty = true;
|
|
15646
|
+
}
|
|
15647
|
+
}
|
|
15648
|
+
}
|
|
15485
15649
|
for (const dc of inst.drawCalls) {
|
|
15486
15650
|
if (!dc.baseBindGroupEntries)
|
|
15487
15651
|
continue; // outlines/ground are never grouped
|
|
@@ -15932,7 +16096,7 @@ export class Engine {
|
|
|
15932
16096
|
}
|
|
15933
16097
|
pass.setBindGroup(2, draw.bindGroup);
|
|
15934
16098
|
this.issueDraw(pass, draw, view.args);
|
|
15935
|
-
if (draw.outline && this.outlineEnabled && view.outlines)
|
|
16099
|
+
if (draw.outline?.drawn && this.outlineEnabled && view.outlines)
|
|
15936
16100
|
outlined.push(draw);
|
|
15937
16101
|
}
|
|
15938
16102
|
// THE HULLS AFTER THE SURFACES, as MMD draws a model's edges. A hull held
|
|
@@ -21,7 +21,7 @@ export const BODY_GRAPH = {
|
|
|
21
21
|
{ id: "lit_tint", type: "hue_sat", inputs: { hue: 0.5, saturation: 1.5, value: 1.0, fac: 1.0 } },
|
|
22
22
|
{ id: "toon_color", type: "mix/blend" },
|
|
23
23
|
{ id: "bc", type: "bright_contrast", inputs: { bright: 0.1, contrast: 0.2 } },
|
|
24
|
-
{ id: "emission3", type: "vector_math/scale", inputs: { scale:
|
|
24
|
+
{ id: "emission3", type: "vector_math/scale", inputs: { scale: 3.2 } },
|
|
25
25
|
{ id: "warm_add", type: "math/add", inputs: { b: 0.5 } },
|
|
26
26
|
{ id: "warm_clamp", type: "math/clamp01" },
|
|
27
27
|
{
|
|
@@ -27,7 +27,7 @@ export const CLOTH_ROUGH_GRAPH = {
|
|
|
27
27
|
{ id: "mix_003", type: "mix/blend" },
|
|
28
28
|
{ id: "hue_004", type: "hue_sat", inputs: { hue: 0.5, saturation: 0.800000011920929, value: 2.0, fac: 1.0 } },
|
|
29
29
|
{ id: "npr_overlay", type: "mix/overlay", inputs: { fac: 1.0 } },
|
|
30
|
-
{ id: "npr_emit", type: "vector_math/scale", inputs: { scale:
|
|
30
|
+
{ id: "npr_emit", type: "vector_math/scale", inputs: { scale: 14.56 } },
|
|
31
31
|
{ id: "noise", type: "tex_noise", inputs: { scale: 17.7 } },
|
|
32
32
|
{ id: "noise_ramp", type: "ramp_linear", inputs: { pos0: 0.0, pos1: 1.0 } },
|
|
33
33
|
{ id: "bump", type: "bump", inputs: { strength: 1.0 } },
|
|
@@ -25,7 +25,7 @@ export const CLOTH_SMOOTH_GRAPH = {
|
|
|
25
25
|
{ id: "mix_003", type: "mix/blend" },
|
|
26
26
|
{ id: "hue_004", type: "hue_sat", inputs: { hue: 0.5, saturation: 0.800000011920929, value: 2.0, fac: 1.0 } },
|
|
27
27
|
{ id: "npr_overlay", type: "mix/overlay", inputs: { fac: 1.0 } },
|
|
28
|
-
{ id: "npr_emit", type: "vector_math/scale", inputs: { scale:
|
|
28
|
+
{ id: "npr_emit", type: "vector_math/scale", inputs: { scale: 14.56 } },
|
|
29
29
|
{ id: "principled_base", type: "hue_sat", inputs: { hue: 0.5, saturation: 1.0, value: 0.800000011920929, fac: 1.0 } },
|
|
30
30
|
{
|
|
31
31
|
id: "principled",
|
|
@@ -25,7 +25,7 @@ export const FACE_GRAPH = {
|
|
|
25
25
|
{ id: "lit_tint", type: "hue_sat", inputs: { hue: 0.46000000834465027, saturation: 1.600000023841858, value: 1.5, fac: 1.0 } },
|
|
26
26
|
{ id: "toon_color", type: "mix/blend" },
|
|
27
27
|
{ id: "bc", type: "bright_contrast", inputs: { bright: 0.1, contrast: 0.2 } },
|
|
28
|
-
{ id: "emission3", type: "vector_math/scale", inputs: { scale: 2.
|
|
28
|
+
{ id: "emission3", type: "vector_math/scale", inputs: { scale: 2.0 } },
|
|
29
29
|
// ── warm rim (toon*0.5+0.5 → cardinal ramp) ──
|
|
30
30
|
{ id: "warm_mul", type: "math/multiply", inputs: { b: 0.5 } },
|
|
31
31
|
{ id: "warm_add", type: "math/add", inputs: { b: 0.5 } },
|
|
@@ -24,7 +24,7 @@ export const METAL_GRAPH = {
|
|
|
24
24
|
{ id: "mix_004", type: "mix/blend" },
|
|
25
25
|
{ id: "hue_004", type: "hue_sat", inputs: { hue: 0.5, saturation: 1.0, value: 2.0, fac: 1.0 } },
|
|
26
26
|
{ id: "npr_overlay", type: "mix/overlay", inputs: { fac: 1.0 } },
|
|
27
|
-
{ id: "npr_emit", type: "vector_math/scale", inputs: { scale:
|
|
27
|
+
{ id: "npr_emit", type: "vector_math/scale", inputs: { scale: 6.48 } },
|
|
28
28
|
{ id: "voro_cross", type: "vect_cross", inputs: { b: [0, 1, 0] } },
|
|
29
29
|
{ id: "voro", type: "tex_voronoi/color", inputs: { scale: 4.3 } },
|
|
30
30
|
{ id: "voro_ramp", type: "ramp_linear", inputs: { pos0: 0.0, pos1: 1.0 } },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/graph/registry.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAE3C,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;AAEzD,KAAK,SAAS,GAAG;IACf,IAAI,EAAE,KAAK,CAAA;IACX,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,4FAA4F;IAC5F,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,yFAAyF;IACzF,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IAC9B,2FAA2F;IAC3F,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,MAAM,CAAA;IAC/C,qEAAqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvC,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC;sEACkE;IAClE,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,CAAA;AAYD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,GAAG,MAAM,CAoBhE;AAED,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,GAAG,OAAO,CAIpE;AAMD,wBAAgB,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAM1D;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAKpE;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/graph/registry.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAE3C,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;AAEzD,KAAK,SAAS,GAAG;IACf,IAAI,EAAE,KAAK,CAAA;IACX,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,4FAA4F;IAC5F,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,yFAAyF;IACzF,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IAC9B,2FAA2F;IAC3F,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,MAAM,CAAA;IAC/C,qEAAqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvC,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC;sEACkE;IAClE,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,CAAA;AAYD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,GAAG,MAAM,CAoBhE;AAED,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,GAAG,OAAO,CAIpE;AAMD,wBAAgB,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAM1D;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAKpE;AAsLD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAozBlD,CAAA"}
|
package/dist/graph/registry.js
CHANGED
|
@@ -101,7 +101,11 @@ const uberNode = (slot) => ({
|
|
|
101
101
|
roughness: F(0.6),
|
|
102
102
|
occlusion: F(1),
|
|
103
103
|
normal: { type: "vector", contextDefault: "n" },
|
|
104
|
-
|
|
104
|
+
// The key light: this draw's, by default — the sun, or the light on the
|
|
105
|
+
// character's own layer — its way and its colour (the game's _LocalLightDir,
|
|
106
|
+
// _LocalLightColor). Linked, a look supplies its own (ag_key_light).
|
|
107
|
+
direction: { type: "vector", contextDefault: "l" },
|
|
108
|
+
light_color: { type: "color", contextDefault: "sun" },
|
|
105
109
|
// Unity's v into the ramp: the property map's alpha, which picks a
|
|
106
110
|
// surface's band (skin 0.702, hair and pale cloth 0.506).
|
|
107
111
|
row: F(0.702),
|
|
@@ -115,23 +119,44 @@ const uberNode = (slot) => ({
|
|
|
115
119
|
rim_in_light: F(1),
|
|
116
120
|
emission: C([0, 0, 0]),
|
|
117
121
|
reflection: F(1),
|
|
122
|
+
// THE STUDIO AMBIENT (_GlobalIlluminationOverride): the game blends a
|
|
123
|
+
// character's ambient from its own reflection cube's smallest mip — near
|
|
124
|
+
// neutral, 0.4–0.9 across the newer skins — over the scene's light, by the
|
|
125
|
+
// material's blend (bodies 0.8, hair 1, faces 0.5). It is what keeps a
|
|
126
|
+
// character clean on a coloured stage.
|
|
127
|
+
studio: C([0.6, 0.6, 0.6]),
|
|
128
|
+
studio_blend: F(0),
|
|
118
129
|
// A face's SDF shade (ag_face_sdf); left at -1, the material reads N·L.
|
|
119
130
|
shade: F(-1),
|
|
120
131
|
// 1: the game's FACE_MODE — no GGX, the environment at a flat 0.0157.
|
|
121
132
|
face: F(0),
|
|
133
|
+
// A face's SDF highlight (ag_face_spec), in place of GGX.
|
|
134
|
+
face_spec: F(0),
|
|
135
|
+
// 1: hair (_ANISOTROPIC_SPECULAR) — its ring (ag_hair_ring) in place of GGX,
|
|
136
|
+
// the environment at a flat 0.0157.
|
|
137
|
+
hair: F(0),
|
|
138
|
+
hair_spec: C([0, 0, 0]),
|
|
122
139
|
},
|
|
123
140
|
outputs: { color: "color" },
|
|
124
|
-
emit: (a) => `ag_uber(${slot}u, ${a.base}, ${a.metallic}, ${a.roughness}, ${a.occlusion}, ${a.normal}, ${a.direction}, ${a.row}, ${a.receive_shadow}, ` +
|
|
125
|
-
`${a.rim_mask}, ${a.rim_mid}, ${a.rim_width}, ${a.rim_tint}, ${a.rim_intensity}, ${a.rim_albedo}, ${a.rim_in_light}, ${a.emission}, ${a.reflection}, ${a.shade}, ${a.face}, input.worldPos, v)`,
|
|
141
|
+
emit: (a) => `ag_uber(${slot}u, ${a.base}, ${a.metallic}, ${a.roughness}, ${a.occlusion}, ${a.normal}, ${a.direction}, ${a.light_color}, ${a.row}, ${a.receive_shadow}, ` +
|
|
142
|
+
`${a.rim_mask}, ${a.rim_mid}, ${a.rim_width}, ${a.rim_tint}, ${a.rim_intensity}, ${a.rim_albedo}, ${a.rim_in_light}, ${a.emission}, ${a.reflection}, ${a.studio}, ${a.studio_blend}, ${a.shade}, ${a.face}, ${a.face_spec}, ${a.hair}, ${a.hair_spec}, input.worldPos, v)`,
|
|
126
143
|
takesLight: true,
|
|
127
144
|
});
|
|
128
145
|
const UBER_NODES = Object.fromEntries([0, 1, 2, 3].map((s) => [`ag_uber/${s}`, uberNode(s)]));
|
|
129
|
-
//
|
|
130
|
-
//
|
|
146
|
+
// How much a colour reads as skin (ag_skin): what picks a surface's ramp row in
|
|
147
|
+
// a general look, where the game would read its property mask.
|
|
148
|
+
const AG_SKIN = {
|
|
149
|
+
inputs: { color: C([1, 1, 1], true) },
|
|
150
|
+
outputs: { value: "float" },
|
|
151
|
+
emit: (a) => `ag_skin(${a.color})`,
|
|
152
|
+
};
|
|
153
|
+
// The face's SDF shade, the image on the slot the type names. An empty slot
|
|
154
|
+
// reads white: the whole face takes one shade from where the key light stands
|
|
155
|
+
// to the head, the game's flat face for a model without its SDF.
|
|
131
156
|
const faceSdfNode = (slot) => ({
|
|
132
157
|
inputs: {
|
|
133
158
|
uv: { type: "vector", contextDefault: "vec3f(input.uv, 0.0)" },
|
|
134
|
-
direction: { type: "vector",
|
|
159
|
+
direction: { type: "vector", contextDefault: "l" },
|
|
135
160
|
normal: { type: "vector", contextDefault: "n" },
|
|
136
161
|
smoothness: F(0.1),
|
|
137
162
|
invert: F(0),
|
|
@@ -140,6 +165,54 @@ const faceSdfNode = (slot) => ({
|
|
|
140
165
|
emit: (a) => `ag_face_sdf(${slot}u, ${a.uv}.xy, ${a.direction}, ${a.normal}, ${a.smoothness}, ${a.invert})`,
|
|
141
166
|
});
|
|
142
167
|
const FACE_SDF_NODES = Object.fromEntries([0, 1, 2, 3].map((s) => [`ag_face_sdf/${s}`, faceSdfNode(s)]));
|
|
168
|
+
// The newer SDF (_SDFType 1): a painted face normal, not a threshold field.
|
|
169
|
+
const faceSdfNewNode = (slot) => ({
|
|
170
|
+
...faceSdfNode(slot),
|
|
171
|
+
emit: (a) => `ag_face_sdf_new(${slot}u, ${a.uv}.xy, ${a.direction}, ${a.normal}, ${a.smoothness}, ${a.invert})`,
|
|
172
|
+
});
|
|
173
|
+
const FACE_SDF_NEW_NODES = Object.fromEntries([0, 1, 2, 3].map((s) => [`ag_face_sdf_new/${s}`, faceSdfNewNode(s)]));
|
|
174
|
+
// The face's highlight from the newer SDF's green and blue.
|
|
175
|
+
const faceSpecNode = (slot) => ({
|
|
176
|
+
inputs: {
|
|
177
|
+
uv: { type: "vector", contextDefault: "vec3f(input.uv, 0.0)" },
|
|
178
|
+
direction: { type: "vector", contextDefault: "l" },
|
|
179
|
+
normal: { type: "vector", contextDefault: "n" },
|
|
180
|
+
anisotropy: F(1),
|
|
181
|
+
shift: F(0),
|
|
182
|
+
},
|
|
183
|
+
outputs: { value: "float" },
|
|
184
|
+
emit: (a) => `ag_face_spec(${slot}u, ${a.uv}.xy, ${a.direction}, ${a.normal}, v, ${a.anisotropy}, ${a.shift})`,
|
|
185
|
+
});
|
|
186
|
+
// The hair's angel ring, the band on the slot's image.
|
|
187
|
+
const hairRingNode = (slot) => ({
|
|
188
|
+
inputs: {
|
|
189
|
+
uv: { type: "vector", contextDefault: "vec3f(input.uv, 0.0)" },
|
|
190
|
+
normal: { type: "vector", contextDefault: "n" },
|
|
191
|
+
color: C([1, 1, 1]),
|
|
192
|
+
anisotropy: F(1),
|
|
193
|
+
shift: F(0),
|
|
194
|
+
},
|
|
195
|
+
outputs: { color: "color" },
|
|
196
|
+
emit: (a) => `ag_hair_ring(${slot}u, ${a.uv}.xy, ${a.normal}, v, ${a.color}, ${a.anisotropy}, ${a.shift})`,
|
|
197
|
+
});
|
|
198
|
+
const HAIR_RING_NODES = Object.fromEntries([0, 1, 2, 3].map((s) => [`ag_hair_ring/${s}`, hairRingNode(s)]));
|
|
199
|
+
// The game's pupil (SimPipeline/Character/Eye): unlit relief, matcap and
|
|
200
|
+
// glints — slots: 0 depth, 1 normal, 2 matcap, 3 glint mask.
|
|
201
|
+
const AG_EYE = {
|
|
202
|
+
inputs: {
|
|
203
|
+
height_scale: F(0.2), min_layer: F(8), max_layer: F(32), intensity: F(0.9),
|
|
204
|
+
main_color: C([1, 1, 1]), matcap_color: C([1, 1, 1]), matcap_pow: F(1),
|
|
205
|
+
mask_scale: F(0.15), mask_soft: F(0.014),
|
|
206
|
+
mask2: F(0), mask2_color: C([1, 1, 1]), mask3: F(0), mask3_color: C([1, 1, 1]),
|
|
207
|
+
blink: F(0), blink_scale: F(10), scale_speed: F(0.1), rotate_speed: F(0.6), blink_angle: F(5),
|
|
208
|
+
level: F(1),
|
|
209
|
+
},
|
|
210
|
+
outputs: { color: "color" },
|
|
211
|
+
emit: (a) => `ag_eye(input.uv, n, v, input.worldPos, ${a.height_scale}, ${a.min_layer}, ${a.max_layer}, ${a.intensity}, ${a.main_color}, ` +
|
|
212
|
+
`${a.matcap_color}, ${a.matcap_pow}, ${a.mask_scale}, ${a.mask_soft}, ${a.mask2}, ${a.mask2_color}, ${a.mask3}, ${a.mask3_color}, ` +
|
|
213
|
+
`${a.blink}, ${a.blink_scale}, ${a.scale_speed}, ${a.rotate_speed}, ${a.blink_angle}, ${a.level})`,
|
|
214
|
+
};
|
|
215
|
+
const FACE_SPEC_NODES = Object.fromEntries([0, 1, 2, 3].map((s) => [`ag_face_spec/${s}`, faceSpecNode(s)]));
|
|
143
216
|
// A packed property map on the slot the type names — the game's material
|
|
144
217
|
// contract: R metal, G perceptual roughness (answered as smoothness, Unity's
|
|
145
218
|
// word for 1 − r), B occlusion, A emission mask, each remapped through the
|
|
@@ -586,7 +659,12 @@ export const NODE_REGISTRY = {
|
|
|
586
659
|
// Principled is one: the ramp image on the group slot named by the type.
|
|
587
660
|
// Defaults are 104903's skin.
|
|
588
661
|
...UBER_NODES,
|
|
662
|
+
ag_skin: AG_SKIN,
|
|
589
663
|
...FACE_SDF_NODES,
|
|
664
|
+
...FACE_SDF_NEW_NODES,
|
|
665
|
+
...FACE_SPEC_NODES,
|
|
666
|
+
ag_eye: AG_EYE,
|
|
667
|
+
...HAIR_RING_NODES,
|
|
590
668
|
...PROPERTY_MAP_NODES,
|
|
591
669
|
/**
|
|
592
670
|
* Lit — Unity's Lit (URP's PBR), term for term: what a stage, a prop or
|
package/dist/graph/schema.d.ts
CHANGED
|
@@ -89,6 +89,20 @@ export type ShaderGraph = {
|
|
|
89
89
|
url: string;
|
|
90
90
|
srgb?: boolean;
|
|
91
91
|
} | null)[];
|
|
92
|
+
/**
|
|
93
|
+
* The look's outline, the anime game's in place of MMD's flat edge: the
|
|
94
|
+
* material's picture × colour, toward shadowColor where the key light leaves
|
|
95
|
+
* it, `width` world units wide (held 1.2–3 px of a 1920-wide frame) — an Aether
|
|
96
|
+
* Gazer _OutlineWidth w is w·1.3/1920·8 here. Unset, the PMX edge stands.
|
|
97
|
+
*/
|
|
98
|
+
outline?: {
|
|
99
|
+
color: [number, number, number];
|
|
100
|
+
shadowColor: [number, number, number];
|
|
101
|
+
width: number;
|
|
102
|
+
/** One of `images` (its index) whose colour multiplies the outline at the
|
|
103
|
+
* mesh's uvs — the game's per-texel outline mask. */
|
|
104
|
+
tint?: number;
|
|
105
|
+
};
|
|
92
106
|
};
|
|
93
107
|
export type Diagnostic = {
|
|
94
108
|
severity: "error" | "warning";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/graph/schema.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAE9F,MAAM,MAAM,SAAS,GAAG;IACtB,kFAAkF;IAClF,EAAE,EAAE,MAAM,CAAA;IACV,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAA;IACZ,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACpC;mFAC+E;IAC/E,EAAE,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAA;CAC7C,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACtC,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CACrC,CAAA;AAED,0FAA0F;AAC1F,MAAM,MAAM,YAAY,GAAG;IACzB,+DAA+D;IAC/D,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACxC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAA;IACvB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,WAAW,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,CAAC,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,uEAAuE;IACvE,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACxC;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IAC1C,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;IACvB;;uFAEmF;IACnF,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/graph/schema.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAE9F,MAAM,MAAM,SAAS,GAAG;IACtB,kFAAkF;IAClF,EAAE,EAAE,MAAM,CAAA;IACV,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAA;IACZ,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACpC;mFAC+E;IAC/E,EAAE,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAA;CAC7C,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACtC,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CACrC,CAAA;AAED,0FAA0F;AAC1F,MAAM,MAAM,YAAY,GAAG;IACzB,+DAA+D;IAC/D,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACxC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAA;IACvB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,WAAW,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,CAAC,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,uEAAuE;IACvE,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACxC;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IAC1C,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;IACvB;;uFAEmF;IACnF,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC,EAAE,CAAA;IACnD;;;;;OAKG;IACH,OAAO,CAAC,EAAE;QACR,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;QAC/B,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;QACrC,KAAK,EAAE,MAAM,CAAA;QACb;8DACsD;QACtD,IAAI,CAAC,EAAE,MAAM,CAAA;KACd,CAAA;CACF,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAA;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAID,eAAO,MAAM,SAAS,MAAM,CAAA;AAC5B,eAAO,MAAM,UAAU,KAAK,CAAA"}
|