reze-engine 0.61.4 → 0.61.6
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 +69 -2
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +310 -36
- package/dist/graph/presets/pool_floor.d.ts +3 -0
- package/dist/graph/presets/pool_floor.d.ts.map +1 -0
- package/dist/graph/presets/pool_floor.js +42 -0
- package/dist/graph/presets/water.d.ts +3 -0
- package/dist/graph/presets/water.d.ts.map +1 -0
- package/dist/graph/presets/water.js +31 -0
- package/dist/graph/registry.d.ts.map +1 -1
- package/dist/graph/registry.js +11 -0
- package/dist/graph/slots.js +2 -2
- package/dist/physics/autofit.d.ts +147 -0
- package/dist/physics/autofit.d.ts.map +1 -0
- package/dist/physics/autofit.js +501 -0
- package/dist/shaders/directives.d.ts +9 -0
- package/dist/shaders/directives.d.ts.map +1 -1
- package/dist/shaders/directives.js +5 -0
- package/dist/shaders/materials/common.js +5 -5
- 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 +12 -0
- package/dist/shaders/passes/field-blit.d.ts +26 -0
- package/dist/shaders/passes/field-blit.d.ts.map +1 -0
- package/dist/shaders/passes/field-blit.js +65 -0
- package/dist/shaders/passes/ghosts.d.ts +22 -0
- package/dist/shaders/passes/ghosts.d.ts.map +1 -0
- package/dist/shaders/passes/ghosts.js +75 -0
- package/dist/shaders/passes/ground-noise.d.ts +7 -0
- package/dist/shaders/passes/ground-noise.d.ts.map +1 -0
- package/dist/shaders/passes/ground-noise.js +88 -0
- package/dist/shaders/passes/particles.js +6 -6
- package/dist/shaders/passes/scene-contract.js +1 -1
- package/dist/shaders/passes/sim.d.ts +34 -0
- package/dist/shaders/passes/sim.d.ts.map +1 -0
- package/dist/shaders/passes/sim.js +169 -0
- package/dist/shaders/passes/subsurface.d.ts +34 -0
- package/dist/shaders/passes/subsurface.d.ts.map +1 -0
- package/dist/shaders/passes/subsurface.js +134 -0
- package/dist/shaders/score-api.d.ts +10 -0
- package/dist/shaders/score-api.d.ts.map +1 -0
- package/dist/shaders/score-api.js +114 -0
- package/dist/shaders/shadow-api.d.ts +29 -0
- package/dist/shaders/shadow-api.d.ts.map +1 -0
- package/dist/shaders/shadow-api.js +112 -0
- package/package.json +1 -1
- package/src/engine.ts +309 -26
- package/src/graph/registry.ts +11 -0
- package/src/graph/slots.ts +2 -2
- package/src/shaders/directives.ts +14 -0
- package/src/shaders/materials/common.ts +5 -5
- package/src/shaders/materials/nodes.ts +12 -0
- package/src/shaders/passes/particles.ts +6 -6
- package/src/shaders/passes/scene-contract.ts +1 -1
- package/src/shaders/passes/subsurface.ts +136 -0
- package/dist/_dbg-loader.mjs +0 -1100
- package/dist/physics-debug.d.ts +0 -30
- package/dist/physics-debug.d.ts.map +0 -1
- package/dist/physics-debug.js +0 -526
- package/dist/shaders/materials/body.d.ts +0 -2
- package/dist/shaders/materials/body.d.ts.map +0 -1
- package/dist/shaders/materials/body.js +0 -95
- package/dist/shaders/materials/cloth_rough.d.ts +0 -2
- package/dist/shaders/materials/cloth_rough.d.ts.map +0 -1
- package/dist/shaders/materials/cloth_rough.js +0 -69
- package/dist/shaders/materials/cloth_smooth.d.ts +0 -2
- package/dist/shaders/materials/cloth_smooth.d.ts.map +0 -1
- package/dist/shaders/materials/cloth_smooth.js +0 -61
- package/dist/shaders/materials/default.d.ts +0 -2
- package/dist/shaders/materials/default.d.ts.map +0 -1
- package/dist/shaders/materials/default.js +0 -43
- package/dist/shaders/materials/eye.d.ts +0 -2
- package/dist/shaders/materials/eye.d.ts.map +0 -1
- package/dist/shaders/materials/eye.js +0 -60
- package/dist/shaders/materials/face.d.ts +0 -2
- package/dist/shaders/materials/face.d.ts.map +0 -1
- package/dist/shaders/materials/face.js +0 -95
- package/dist/shaders/materials/hair.d.ts +0 -2
- package/dist/shaders/materials/hair.d.ts.map +0 -1
- package/dist/shaders/materials/hair.js +0 -90
- package/dist/shaders/materials/metal.d.ts +0 -2
- package/dist/shaders/materials/metal.d.ts.map +0 -1
- package/dist/shaders/materials/metal.js +0 -77
- package/dist/shaders/materials/mmd_classic.d.ts +0 -2
- package/dist/shaders/materials/mmd_classic.d.ts.map +0 -1
- package/dist/shaders/materials/mmd_classic.js +0 -66
- package/dist/shaders/materials/stockings.d.ts +0 -2
- package/dist/shaders/materials/stockings.d.ts.map +0 -1
- package/dist/shaders/materials/stockings.js +0 -122
- package/dist/shaders/passes/physics-debug.d.ts +0 -2
- package/dist/shaders/passes/physics-debug.d.ts.map +0 -1
- package/dist/shaders/passes/physics-debug.js +0 -69
package/dist/engine.js
CHANGED
|
@@ -42,6 +42,7 @@ import { boneOverlay, boneMarkerPositions, buildOverlayShapes, jointOverlay, lin
|
|
|
42
42
|
import { BLOOM_BLIT_SHADER_WGSL, BLOOM_DOWNSAMPLE_SHADER_WGSL, BLOOM_UPSAMPLE_SHADER_WGSL, } from "./shaders/passes/bloom";
|
|
43
43
|
import { AGX_LUT_GZ, AGX_LUT_SIZE } from "./shaders/agx-lut";
|
|
44
44
|
import { buildCompositeShader, EFFECT_SCENE_API, buildFieldShader, EFFECT_ANCHORS, EFFECT_SUBJECTS, EFFECT_TRAIL_BASE, EFFECT_TRAIL_SAMPLES, } from "./shaders/passes/composite";
|
|
45
|
+
import { SUBSURFACE_WGSL, SSS_SPIKE } from "./shaders/passes/subsurface";
|
|
45
46
|
import { buildParticleComputeShader, buildParticleRenderShader, PARTICLE_LIGHT_BINDING, PARTICLE_POINTS_BINDING, particleEntryPoints, PARTICLE_INDIRECT_BINDING, PARTICLE_INDIRECT_BYTES, PARTICLE_INDIRECT_DRAW_OFFSET, PARTICLE_STRIDE, } from "./shaders/passes/particles";
|
|
46
47
|
import { MAX_EFFECT_POINTS, POINTS_FLOATS } from "./shaders/points-api";
|
|
47
48
|
import { bonesWithPrefix, pointsData, writeBonePoint } from "./effect-points";
|
|
@@ -1139,6 +1140,28 @@ export class Engine {
|
|
|
1139
1140
|
/** Scene-clock reading when the current effect was installed. The effect's
|
|
1140
1141
|
* `time` is measured from here — see where it is written. */
|
|
1141
1142
|
this.compositeBloomView = null;
|
|
1143
|
+
// Screen-space subsurface scattering (passes/subsurface.ts). The scratch target
|
|
1144
|
+
// is the X pass's output and lives with the canvas size; the bind groups name
|
|
1145
|
+
// it and the HDR resolve, so a resize drops them and the next frame rebuilds.
|
|
1146
|
+
this.sssPipelineX = null;
|
|
1147
|
+
this.sssPipelineY = null;
|
|
1148
|
+
this.sssScratch = null;
|
|
1149
|
+
this.sssBindGroupX = null;
|
|
1150
|
+
this.sssBindGroupY = null;
|
|
1151
|
+
this.sssUniformX = null;
|
|
1152
|
+
this.sssUniformY = null;
|
|
1153
|
+
this.sssUniformData = new Float32Array(8);
|
|
1154
|
+
// Model pipelines' descriptors, and the single-sided twins built from them —
|
|
1155
|
+
// one per pipeline per view (see sidedPipeline).
|
|
1156
|
+
this.pipelineDescs = new WeakMap();
|
|
1157
|
+
this.singleSided = new WeakMap();
|
|
1158
|
+
this.singleSidedMirror = new WeakMap();
|
|
1159
|
+
// Stepped motion (#stepped). The models whose pose is being HELD this frame —
|
|
1160
|
+
// their skinning and morph uploads wait for the stepped clock's next tick —
|
|
1161
|
+
// and the tick each was last shown at. Empty while no effect declares it.
|
|
1162
|
+
this.steppedHeld = new Set();
|
|
1163
|
+
this.steppedTick = new Map();
|
|
1164
|
+
this.steppedLastClock = -1;
|
|
1142
1165
|
this.bloomBlitUniformData = new Float32Array(4);
|
|
1143
1166
|
this.bloomUpsampleUniformData = new Float32Array(4);
|
|
1144
1167
|
this.bloomMipCount = 0;
|
|
@@ -2113,18 +2136,51 @@ export class Engine {
|
|
|
2113
2136
|
return slot ? fx.paramsData[slot.offset] : fallback;
|
|
2114
2137
|
}
|
|
2115
2138
|
/**
|
|
2116
|
-
*
|
|
2139
|
+
* Decide which models hold their pose this frame.
|
|
2117
2140
|
*
|
|
2118
|
-
*
|
|
2119
|
-
*
|
|
2120
|
-
*
|
|
2121
|
-
*
|
|
2122
|
-
*
|
|
2123
|
-
*
|
|
2141
|
+
* Nothing underneath is slowed: animation and physics run every frame as they
|
|
2142
|
+
* always do, so the pose that lands on each tick is the true one for that
|
|
2143
|
+
* moment and a hold never drifts behind the music. What steps is only when it
|
|
2144
|
+
* reaches the GPU — the skinning upload and the morph dispatch wait for the
|
|
2145
|
+
* next tick of a clock running at FPS on the scene clock, which is what an
|
|
2146
|
+
* export steps.
|
|
2124
2147
|
*
|
|
2125
|
-
*
|
|
2126
|
-
* and
|
|
2148
|
+
* FIRST match wins, and only the models it is aimed at hold: a stage, a prop
|
|
2149
|
+
* and every effect keep moving on ones, which is what makes the cast read as
|
|
2150
|
+
* animated rather than the playback as broken.
|
|
2127
2151
|
*/
|
|
2152
|
+
syncSteppedFromEffects() {
|
|
2153
|
+
this.steppedHeld.clear();
|
|
2154
|
+
let fx = null;
|
|
2155
|
+
for (const e of this.effects) {
|
|
2156
|
+
if (e.stepped && e.weight > 0) {
|
|
2157
|
+
fx = e;
|
|
2158
|
+
break;
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
if (!fx) {
|
|
2162
|
+
this.steppedTick.clear();
|
|
2163
|
+
return;
|
|
2164
|
+
}
|
|
2165
|
+
// Paused, nothing holds: time is not moving, so there is nothing to step,
|
|
2166
|
+
// and a pose edited on a stopped timeline has to show as it is edited.
|
|
2167
|
+
const paused = this.sceneClock === this.steppedLastClock;
|
|
2168
|
+
this.steppedLastClock = this.sceneClock;
|
|
2169
|
+
if (paused)
|
|
2170
|
+
return;
|
|
2171
|
+
const D = Engine.STEPPED_DIALS;
|
|
2172
|
+
const fps = Math.max(this.effectDial(fx, D.fps, 6), 1);
|
|
2173
|
+
const tick = Math.floor(this.sceneClock * fps + 1e-6);
|
|
2174
|
+
this.forEachInstance((inst) => {
|
|
2175
|
+
const slot = this.castSlotOf.get(inst.name);
|
|
2176
|
+
if (slot === undefined || !(fx.subjectMask & (1 << slot)))
|
|
2177
|
+
return;
|
|
2178
|
+
if (this.steppedTick.get(inst.name) === tick)
|
|
2179
|
+
this.steppedHeld.add(inst.name);
|
|
2180
|
+
else
|
|
2181
|
+
this.steppedTick.set(inst.name, tick);
|
|
2182
|
+
});
|
|
2183
|
+
}
|
|
2128
2184
|
syncMirrorFromEffects() {
|
|
2129
2185
|
let fx = null;
|
|
2130
2186
|
for (const e of this.effects) {
|
|
@@ -3430,14 +3486,15 @@ export class Engine {
|
|
|
3430
3486
|
// #mirror is a mount on the same footing, and for the same reason: a
|
|
3431
3487
|
// reflection re-renders the scene from a folded camera, which is a pass and
|
|
3432
3488
|
// not a shader, so the effect declares it and draws nothing itself.
|
|
3433
|
-
|
|
3489
|
+
// #stepped too: it decides when a pose reaches the screen, not what is drawn.
|
|
3490
|
+
if (!hasBackground && !hasForeground && !wantsParticles && !wantsTrails && !hasLightEmit(wgsl) && !d.mirror && !d.stepped) {
|
|
3434
3491
|
return { ok: false, diagnostics: [
|
|
3435
3492
|
"an effect must define fn background(ray: vec3f, uv: vec2f, time: f32) -> vec4f, " +
|
|
3436
3493
|
"fn foreground(ray: vec3f, uv: vec2f, time: f32, depth: f32) -> vec4f, " +
|
|
3437
3494
|
"the particle trio (particleInit/particleStep/particleShade), " +
|
|
3438
3495
|
"the ribbon pair (trailWidth/trailShade), " +
|
|
3439
3496
|
"fn lightEmit(i: u32) -> RzLight with #lights <n>, " +
|
|
3440
|
-
"or #
|
|
3497
|
+
"#mirror, or #stepped",
|
|
3441
3498
|
], mounts: noMounts, params: [], duration: 0, readsCast: false };
|
|
3442
3499
|
}
|
|
3443
3500
|
const mounts = { background: hasBackground, foreground: hasForeground };
|
|
@@ -3743,6 +3800,7 @@ export class Engine {
|
|
|
3743
3800
|
paramsBuffer,
|
|
3744
3801
|
paramsData,
|
|
3745
3802
|
hasMirror: d.mirror,
|
|
3803
|
+
stepped: d.stepped,
|
|
3746
3804
|
hasBackground,
|
|
3747
3805
|
hasForeground,
|
|
3748
3806
|
// The author's OWN source, not the assembled module: the assembled one
|
|
@@ -4764,6 +4822,129 @@ export class Engine {
|
|
|
4764
4822
|
/** The user's field mounts, drawn at half resolution for the composite to
|
|
4765
4823
|
* upsample. Runs the whole quad — uniform control flow, so effects may use
|
|
4766
4824
|
* derivatives freely, which the old inline path had to forbid. */
|
|
4825
|
+
/** Whether any installed style group routes through a `subsurface` node —
|
|
4826
|
+
* the scattering pass, and the depth it reads, cost nothing otherwise. */
|
|
4827
|
+
subsurfaceInUse() {
|
|
4828
|
+
for (const inst of this.modelInstances.values()) {
|
|
4829
|
+
for (const g of inst.styleGroups.values()) {
|
|
4830
|
+
if (g.group.materials.length && g.group.graph.nodes.some((n) => n.type === "subsurface"))
|
|
4831
|
+
return true;
|
|
4832
|
+
}
|
|
4833
|
+
}
|
|
4834
|
+
return false;
|
|
4835
|
+
}
|
|
4836
|
+
/**
|
|
4837
|
+
* ray-mmd's skin scattering: a horizontal then a vertical depth-aware blur of
|
|
4838
|
+
* the pixels the scene pass marked as skin (aux .b), the second written back
|
|
4839
|
+
* into the HDR resolve through a blend that keeps ray-mmd's per-channel share
|
|
4840
|
+
* of the unblurred picture. See passes/subsurface.ts.
|
|
4841
|
+
*/
|
|
4842
|
+
renderSubsurface(encoder) {
|
|
4843
|
+
if (!this.device || !this.subsurfaceInUse())
|
|
4844
|
+
return;
|
|
4845
|
+
if (!this.hdrResolveTexture || !this.maskResolveView || !this.depthReadView || !this.dofUniformBuffer)
|
|
4846
|
+
return;
|
|
4847
|
+
const w = this.hdrResolveTexture.width;
|
|
4848
|
+
const h = this.hdrResolveTexture.height;
|
|
4849
|
+
if (!this.sssPipelineX || !this.sssPipelineY) {
|
|
4850
|
+
const module = this.device.createShaderModule({ label: "subsurface scattering", code: SUBSURFACE_WGSL });
|
|
4851
|
+
this.sssPipelineX = this.device.createRenderPipeline({
|
|
4852
|
+
label: "subsurface blur x",
|
|
4853
|
+
layout: "auto",
|
|
4854
|
+
vertex: { module, entryPoint: "vs" },
|
|
4855
|
+
fragment: { module, entryPoint: "fsX", targets: [{ format: this.hdrFormat }] },
|
|
4856
|
+
primitive: { topology: "triangle-list" },
|
|
4857
|
+
});
|
|
4858
|
+
// result = blurred·(1 − spike) + original·spike, per channel: the
|
|
4859
|
+
// destination is the original, and the blend constant holds the spike.
|
|
4860
|
+
this.sssPipelineY = this.device.createRenderPipeline({
|
|
4861
|
+
label: "subsurface blur y",
|
|
4862
|
+
layout: "auto",
|
|
4863
|
+
vertex: { module, entryPoint: "vs" },
|
|
4864
|
+
fragment: {
|
|
4865
|
+
module,
|
|
4866
|
+
entryPoint: "fsY",
|
|
4867
|
+
targets: [
|
|
4868
|
+
{
|
|
4869
|
+
format: this.hdrFormat,
|
|
4870
|
+
blend: {
|
|
4871
|
+
color: { srcFactor: "one-minus-constant", dstFactor: "constant", operation: "add" },
|
|
4872
|
+
alpha: { srcFactor: "zero", dstFactor: "one", operation: "add" },
|
|
4873
|
+
},
|
|
4874
|
+
},
|
|
4875
|
+
],
|
|
4876
|
+
},
|
|
4877
|
+
primitive: { topology: "triangle-list" },
|
|
4878
|
+
});
|
|
4879
|
+
this.sssBindGroupX = null;
|
|
4880
|
+
this.sssBindGroupY = null;
|
|
4881
|
+
}
|
|
4882
|
+
if (!this.sssUniformX || !this.sssUniformY) {
|
|
4883
|
+
const make = (label) => this.device.createBuffer({ label, size: 32, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST });
|
|
4884
|
+
this.sssUniformX = make("subsurface uniforms x");
|
|
4885
|
+
this.sssUniformY = make("subsurface uniforms y");
|
|
4886
|
+
}
|
|
4887
|
+
if (!this.sssScratch || this.sssScratch.width !== w || this.sssScratch.height !== h) {
|
|
4888
|
+
this.sssScratch?.destroy();
|
|
4889
|
+
this.sssScratch = this.device.createTexture({
|
|
4890
|
+
label: "subsurface scratch",
|
|
4891
|
+
size: [w, h],
|
|
4892
|
+
format: this.hdrFormat,
|
|
4893
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
|
|
4894
|
+
});
|
|
4895
|
+
this.sssBindGroupX = null;
|
|
4896
|
+
this.sssBindGroupY = null;
|
|
4897
|
+
}
|
|
4898
|
+
if (!this.sssBindGroupX || !this.sssBindGroupY) {
|
|
4899
|
+
const mask = this.maskResolveView;
|
|
4900
|
+
const depth = this.depthReadView;
|
|
4901
|
+
const dof = this.dofUniformBuffer;
|
|
4902
|
+
const group = (pipeline, src, uniforms, label) => this.device.createBindGroup({
|
|
4903
|
+
label,
|
|
4904
|
+
layout: pipeline.getBindGroupLayout(0),
|
|
4905
|
+
entries: [
|
|
4906
|
+
{ binding: 0, resource: src.createView() },
|
|
4907
|
+
{ binding: 1, resource: mask },
|
|
4908
|
+
{ binding: 2, resource: depth },
|
|
4909
|
+
{ binding: 3, resource: { buffer: dof } },
|
|
4910
|
+
{ binding: 4, resource: { buffer: uniforms } },
|
|
4911
|
+
],
|
|
4912
|
+
});
|
|
4913
|
+
this.sssBindGroupX = group(this.sssPipelineX, this.hdrResolveTexture, this.sssUniformX, "subsurface x");
|
|
4914
|
+
this.sssBindGroupY = group(this.sssPipelineY, this.sssScratch, this.sssUniformY, "subsurface y");
|
|
4915
|
+
}
|
|
4916
|
+
const tanY = Math.tan(this.camera.fov * 0.5);
|
|
4917
|
+
const u = this.sssUniformData;
|
|
4918
|
+
u[2] = 0;
|
|
4919
|
+
u[3] = 0;
|
|
4920
|
+
u[4] = tanY * this.camera.aspect;
|
|
4921
|
+
u[5] = tanY;
|
|
4922
|
+
u[6] = w;
|
|
4923
|
+
u[7] = h;
|
|
4924
|
+
u[0] = 1;
|
|
4925
|
+
u[1] = 0;
|
|
4926
|
+
this.device.queue.writeBuffer(this.sssUniformX, 0, u);
|
|
4927
|
+
u[0] = 0;
|
|
4928
|
+
u[1] = 1;
|
|
4929
|
+
this.device.queue.writeBuffer(this.sssUniformY, 0, u);
|
|
4930
|
+
const px = encoder.beginRenderPass({
|
|
4931
|
+
label: "subsurface blur x",
|
|
4932
|
+
colorAttachments: [{ view: this.sssScratch.createView(), loadOp: "clear", clearValue: [0, 0, 0, 0], storeOp: "store" }],
|
|
4933
|
+
});
|
|
4934
|
+
px.setPipeline(this.sssPipelineX);
|
|
4935
|
+
px.setBindGroup(0, this.sssBindGroupX);
|
|
4936
|
+
px.draw(3);
|
|
4937
|
+
px.end();
|
|
4938
|
+
const py = encoder.beginRenderPass({
|
|
4939
|
+
label: "subsurface blur y",
|
|
4940
|
+
colorAttachments: [{ view: this.hdrResolveTexture.createView(), loadOp: "load", storeOp: "store" }],
|
|
4941
|
+
});
|
|
4942
|
+
py.setPipeline(this.sssPipelineY);
|
|
4943
|
+
py.setBindGroup(0, this.sssBindGroupY);
|
|
4944
|
+
py.setBlendConstant({ r: SSS_SPIKE[0], g: SSS_SPIKE[1], b: SSS_SPIKE[2], a: 0 });
|
|
4945
|
+
py.draw(3);
|
|
4946
|
+
py.end();
|
|
4947
|
+
}
|
|
4767
4948
|
renderFieldPass(encoder) {
|
|
4768
4949
|
// TWO PREDICATES, deliberately, and they are not interchangeable.
|
|
4769
4950
|
//
|
|
@@ -5781,7 +5962,7 @@ export class Engine {
|
|
|
5781
5962
|
}
|
|
5782
5963
|
createRenderPipeline(config) {
|
|
5783
5964
|
const targets = config.fragmentTargets ?? (config.fragmentTarget ? [config.fragmentTarget] : undefined);
|
|
5784
|
-
return this.
|
|
5965
|
+
return this.createModelPipeline({
|
|
5785
5966
|
label: config.label,
|
|
5786
5967
|
layout: config.layout,
|
|
5787
5968
|
vertex: {
|
|
@@ -6195,7 +6376,7 @@ export class Engine {
|
|
|
6195
6376
|
depthCompare: this.depthAhead,
|
|
6196
6377
|
},
|
|
6197
6378
|
};
|
|
6198
|
-
this.depthPrepassPipeline = this.
|
|
6379
|
+
this.depthPrepassPipeline = this.createModelPipeline({
|
|
6199
6380
|
label: "opaque depth prepass",
|
|
6200
6381
|
...prepassDesc,
|
|
6201
6382
|
fragment: {
|
|
@@ -6207,7 +6388,7 @@ export class Engine {
|
|
|
6207
6388
|
// The SOLID prime: same module, cutoff forced to exactly 1.0. Only texels
|
|
6208
6389
|
// whose blend ignores the destination may pre-claim depth in the
|
|
6209
6390
|
// transparent phase — see the override's note in depth-prepass.ts.
|
|
6210
|
-
this.solidPrepassPipeline = this.
|
|
6391
|
+
this.solidPrepassPipeline = this.createModelPipeline({
|
|
6211
6392
|
label: "transparent solid prepass",
|
|
6212
6393
|
...prepassDesc,
|
|
6213
6394
|
fragment: {
|
|
@@ -6223,7 +6404,7 @@ export class Engine {
|
|
|
6223
6404
|
// hair depth from ever claiming the pixels the see-through-hair pass needs
|
|
6224
6405
|
// the eye to survive on. (Bundle draws use the PASS's stencil reference;
|
|
6225
6406
|
// only pipeline/bind/vertex state resets across executeBundles.)
|
|
6226
|
-
this.hairPrimePipeline = this.
|
|
6407
|
+
this.hairPrimePipeline = this.createModelPipeline({
|
|
6227
6408
|
label: "hair depth prime",
|
|
6228
6409
|
...prepassDesc,
|
|
6229
6410
|
depthStencil: {
|
|
@@ -7035,6 +7216,10 @@ export class Engine {
|
|
|
7035
7216
|
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
|
|
7036
7217
|
});
|
|
7037
7218
|
this.maskResolveView = this.maskResolveTexture.createView();
|
|
7219
|
+
this.sssScratch?.destroy();
|
|
7220
|
+
this.sssScratch = null;
|
|
7221
|
+
this.sssBindGroupX = null;
|
|
7222
|
+
this.sssBindGroupY = null;
|
|
7038
7223
|
// The floor mirror's targets — FULL resolution, the same attachment
|
|
7039
7224
|
// contract and sample count as the scene pass, which is what lets the
|
|
7040
7225
|
// mirror bundles reuse every scene pipeline unchanged. Half res was the
|
|
@@ -8739,6 +8924,8 @@ export class Engine {
|
|
|
8739
8924
|
bindGroup: this.groundShadowBindGroup,
|
|
8740
8925
|
materialName: "Ground",
|
|
8741
8926
|
groupId: null,
|
|
8927
|
+
// The ground's own pipeline decides its culling.
|
|
8928
|
+
doubleSided: true,
|
|
8742
8929
|
// The ground belongs to no model instance, so it is not in the cull list —
|
|
8743
8930
|
// cullIndex -1 leaves renderGround unconditional. Its box is filled in
|
|
8744
8931
|
// anyway rather than left a lie for whoever reads this next.
|
|
@@ -10697,6 +10884,9 @@ export class Engine {
|
|
|
10697
10884
|
const gm = inst.gpuMorph;
|
|
10698
10885
|
if (!gm || !gm.dispatchNeeded)
|
|
10699
10886
|
continue;
|
|
10887
|
+
// The face holds with the body (see syncSteppedFromEffects).
|
|
10888
|
+
if (this.steppedHeld.has(inst.name))
|
|
10889
|
+
continue;
|
|
10700
10890
|
if (!pass) {
|
|
10701
10891
|
pass = encoder.beginComputePass({ label: "morph compute", timestampWrites: this.stamps("morph") });
|
|
10702
10892
|
pass.setPipeline(this.morphComputePipeline);
|
|
@@ -12449,6 +12639,7 @@ export class Engine {
|
|
|
12449
12639
|
groupId: null,
|
|
12450
12640
|
baseBindGroupEntries,
|
|
12451
12641
|
castsShadow,
|
|
12642
|
+
doubleSided: inst.isPlane || (mat.edgeFlag & 0x01) !== 0,
|
|
12452
12643
|
outline,
|
|
12453
12644
|
bounds,
|
|
12454
12645
|
cullIndex: -1,
|
|
@@ -13649,6 +13840,7 @@ export class Engine {
|
|
|
13649
13840
|
this.handleResize();
|
|
13650
13841
|
}
|
|
13651
13842
|
const hasModels = this.modelInstances.size > 0;
|
|
13843
|
+
this.syncSteppedFromEffects();
|
|
13652
13844
|
if (hasModels) {
|
|
13653
13845
|
this.updateInstances(deltaTime);
|
|
13654
13846
|
this.updateSkinMatrices();
|
|
@@ -13746,7 +13938,10 @@ export class Engine {
|
|
|
13746
13938
|
// The two real readers are both in the composite and both have their own
|
|
13747
13939
|
// flag above: linearDepth() feeds the DoF gather and the depth handed to a
|
|
13748
13940
|
// foreground mount. Nothing else binds depthTex at all.
|
|
13749
|
-
|
|
13941
|
+
// The scattering pass is the third reader: it rejects taps across a depth
|
|
13942
|
+
// step and scales its width by distance, so a scene wearing a subsurface
|
|
13943
|
+
// look stores depth for as long as it does.
|
|
13944
|
+
const depthRead = dofOn || this.effects.some((e) => e.hasForeground) || this.subsurfaceInUse();
|
|
13750
13945
|
this.renderPassDescriptor.depthStencilAttachment.depthStoreOp = depthRead ? "store" : "discard";
|
|
13751
13946
|
if (depthRead)
|
|
13752
13947
|
this.writeDepthOfFieldUniforms();
|
|
@@ -13946,6 +14141,9 @@ export class Engine {
|
|
|
13946
14141
|
// kept ribbons out of bloom.
|
|
13947
14142
|
this.drawTrails(pass, "camera");
|
|
13948
14143
|
pass.end();
|
|
14144
|
+
// Skin scattering, on the resolved scene and before anything reads it:
|
|
14145
|
+
// bloom should bleed the scattered skin, not the raw one.
|
|
14146
|
+
this.renderSubsurface(encoder);
|
|
13949
14147
|
// The field mounts, likewise: after the scene so foregrounds can read its
|
|
13950
14148
|
// depth, before the composite that samples both layers.
|
|
13951
14149
|
this.renderFieldPass(encoder);
|
|
@@ -14730,11 +14928,53 @@ export class Engine {
|
|
|
14730
14928
|
stencilWriteMask: 0xff,
|
|
14731
14929
|
};
|
|
14732
14930
|
}
|
|
14733
|
-
|
|
14931
|
+
const desc = {
|
|
14734
14932
|
...base,
|
|
14735
14933
|
fragment: { module, constants, targets: blend === "additive" ? this.sceneTargetsAdditive : this.sceneTargets },
|
|
14736
14934
|
depthStencil,
|
|
14737
|
-
}
|
|
14935
|
+
};
|
|
14936
|
+
return this.device.createRenderPipelineAsync(desc).then((pipeline) => {
|
|
14937
|
+
this.pipelineDescs.set(pipeline, desc);
|
|
14938
|
+
return pipeline;
|
|
14939
|
+
});
|
|
14940
|
+
}
|
|
14941
|
+
/** A pipeline whose descriptor is kept, so a single-sided twin can be built
|
|
14942
|
+
* from it on demand (see sidedPipeline). */
|
|
14943
|
+
createModelPipeline(desc) {
|
|
14944
|
+
const pipeline = this.device.createRenderPipeline(desc);
|
|
14945
|
+
this.pipelineDescs.set(pipeline, desc);
|
|
14946
|
+
return pipeline;
|
|
14947
|
+
}
|
|
14948
|
+
/**
|
|
14949
|
+
* The pipeline a draw should use once its double-sided flag is honoured.
|
|
14950
|
+
*
|
|
14951
|
+
* A single-sided material culls its back faces, as MMD does. PMX winds a front
|
|
14952
|
+
* face clockwise, which this engine sees as a BACK face — the eye's front cull
|
|
14953
|
+
* and the outline hull's back cull are the same fact — so the cull is "front"
|
|
14954
|
+
* for the camera and "back" in the mirror, whose reflection flips winding.
|
|
14955
|
+
*
|
|
14956
|
+
* Every pipeline that draws a material's surface goes through here, depth
|
|
14957
|
+
* primes included: a prime that kept a culled face would write depth for a
|
|
14958
|
+
* surface nobody sees and hide what is behind it. A pipeline that already
|
|
14959
|
+
* culls (the eye) is returned as it is.
|
|
14960
|
+
*/
|
|
14961
|
+
sidedPipeline(pipeline, draw, mirrored) {
|
|
14962
|
+
if (draw.doubleSided)
|
|
14963
|
+
return pipeline;
|
|
14964
|
+
const desc = this.pipelineDescs.get(pipeline);
|
|
14965
|
+
if (!desc || (desc.primitive?.cullMode ?? "none") !== "none")
|
|
14966
|
+
return pipeline;
|
|
14967
|
+
const cache = mirrored ? this.singleSidedMirror : this.singleSided;
|
|
14968
|
+
let twin = cache.get(pipeline);
|
|
14969
|
+
if (!twin) {
|
|
14970
|
+
twin = this.device.createRenderPipeline({
|
|
14971
|
+
...desc,
|
|
14972
|
+
label: `${desc.label ?? "pipeline"} (single-sided${mirrored ? ", mirror" : ""})`,
|
|
14973
|
+
primitive: { ...desc.primitive, cullMode: mirrored ? "back" : "front" },
|
|
14974
|
+
});
|
|
14975
|
+
cache.set(pipeline, twin);
|
|
14976
|
+
}
|
|
14977
|
+
return twin;
|
|
14738
14978
|
}
|
|
14739
14979
|
// Pipeline for a material draw call: its group's compiled pipeline when grouped, else
|
|
14740
14980
|
// the neutral base (ungrouped materials render the default graph). Transparent-bucket
|
|
@@ -14790,7 +15030,8 @@ export class Engine {
|
|
|
14790
15030
|
pass.setBindGroup(1, inst.mainPerInstanceBindGroup);
|
|
14791
15031
|
bound = true;
|
|
14792
15032
|
}
|
|
14793
|
-
const
|
|
15033
|
+
const mirrored = view.args === "mirror";
|
|
15034
|
+
const pipeline = this.sidedPipeline(this.pipelineForDrawCall(inst, draw, mirrored), draw, mirrored);
|
|
14794
15035
|
if (pipeline !== currentPipeline) {
|
|
14795
15036
|
pass.setPipeline(pipeline);
|
|
14796
15037
|
currentPipeline = pipeline;
|
|
@@ -14892,15 +15133,18 @@ export class Engine {
|
|
|
14892
15133
|
/** Depth-only prime of the hair's alpha-1 texels, stencil-fenced off the eye
|
|
14893
15134
|
* silhouette. See the note at its call site and hairPrimePipeline. */
|
|
14894
15135
|
drawHairDepthPrime(pass, inst, view) {
|
|
14895
|
-
let bound =
|
|
15136
|
+
let bound = null;
|
|
14896
15137
|
for (const draw of inst.drawCalls) {
|
|
14897
15138
|
if (draw.type !== "opaque" || !this.isHairDraw(inst, draw))
|
|
14898
15139
|
continue;
|
|
14899
|
-
|
|
14900
|
-
|
|
14901
|
-
pass.
|
|
14902
|
-
|
|
14903
|
-
|
|
15140
|
+
const pipeline = this.sidedPipeline(this.hairPrimePipeline, draw, view.args === "mirror");
|
|
15141
|
+
if (bound !== pipeline) {
|
|
15142
|
+
pass.setPipeline(pipeline);
|
|
15143
|
+
if (!bound) {
|
|
15144
|
+
pass.setBindGroup(0, view.perFrame);
|
|
15145
|
+
pass.setBindGroup(1, inst.mainPerInstanceBindGroup);
|
|
15146
|
+
}
|
|
15147
|
+
bound = pipeline;
|
|
14904
15148
|
}
|
|
14905
15149
|
pass.setBindGroup(2, draw.bindGroup);
|
|
14906
15150
|
this.issueDraw(pass, draw, view.args);
|
|
@@ -14962,6 +15206,7 @@ export class Engine {
|
|
|
14962
15206
|
else if (install && install.alphaMode !== "opaque")
|
|
14963
15207
|
continue;
|
|
14964
15208
|
}
|
|
15209
|
+
pipeline = this.sidedPipeline(pipeline, draw, view.args === "mirror");
|
|
14965
15210
|
if (bound !== pipeline) {
|
|
14966
15211
|
pass.setPipeline(pipeline);
|
|
14967
15212
|
// One layout for both prepass pipelines, so groups 0 and 1 carry over.
|
|
@@ -14995,15 +15240,18 @@ export class Engine {
|
|
|
14995
15240
|
drawTransparentSolidPrepass(pass, inst, view) {
|
|
14996
15241
|
if (inst.isStage)
|
|
14997
15242
|
return;
|
|
14998
|
-
let bound =
|
|
15243
|
+
let bound = null;
|
|
14999
15244
|
for (const draw of inst.drawCalls) {
|
|
15000
15245
|
if (draw.type !== "transparent")
|
|
15001
15246
|
continue;
|
|
15002
|
-
|
|
15003
|
-
|
|
15004
|
-
pass.
|
|
15005
|
-
|
|
15006
|
-
|
|
15247
|
+
const pipeline = this.sidedPipeline(this.solidPrepassPipeline, draw, view.args === "mirror");
|
|
15248
|
+
if (bound !== pipeline) {
|
|
15249
|
+
pass.setPipeline(pipeline);
|
|
15250
|
+
if (!bound) {
|
|
15251
|
+
pass.setBindGroup(0, view.perFrame);
|
|
15252
|
+
pass.setBindGroup(1, inst.mainPerInstanceBindGroup);
|
|
15253
|
+
}
|
|
15254
|
+
bound = pipeline;
|
|
15007
15255
|
}
|
|
15008
15256
|
pass.setBindGroup(2, draw.bindGroup);
|
|
15009
15257
|
this.issueDraw(pass, draw, view.args);
|
|
@@ -15054,9 +15302,10 @@ export class Engine {
|
|
|
15054
15302
|
for (const draw of inst.drawCalls) {
|
|
15055
15303
|
if (draw.type !== "opaque")
|
|
15056
15304
|
continue;
|
|
15057
|
-
const
|
|
15058
|
-
if (!
|
|
15305
|
+
const hairOverEyes = this.overEyesPipelineFor(inst, draw);
|
|
15306
|
+
if (!hairOverEyes)
|
|
15059
15307
|
continue;
|
|
15308
|
+
const overEyes = this.sidedPipeline(hairOverEyes, draw, view.args === "mirror");
|
|
15060
15309
|
if (!bound) {
|
|
15061
15310
|
pass.setBindGroup(0, view.perFrame);
|
|
15062
15311
|
pass.setBindGroup(1, inst.mainPerInstanceBindGroup);
|
|
@@ -15512,6 +15761,10 @@ export class Engine {
|
|
|
15512
15761
|
// per-frame cost a stage would otherwise still pay in full.
|
|
15513
15762
|
if (!inst.skinMatricesDirty)
|
|
15514
15763
|
return;
|
|
15764
|
+
// Held on a stepped effect's tick: stays dirty, so the pose that is current
|
|
15765
|
+
// when the next tick comes is the one uploaded.
|
|
15766
|
+
if (this.steppedHeld.has(inst.name))
|
|
15767
|
+
return;
|
|
15515
15768
|
const skinMatrices = inst.model.getSkinMatrices();
|
|
15516
15769
|
this.device.queue.writeBuffer(inst.skinMatrixBuffer, 0, skinMatrices.buffer, skinMatrices.byteOffset, skinMatrices.byteLength);
|
|
15517
15770
|
inst.skinMatricesDirty = false;
|
|
@@ -15626,15 +15879,18 @@ Engine.HDR_FORMAT_OVERRIDE = null;
|
|
|
15626
15879
|
/** Stencil value stamped by eye draws so hair can stencil-test against it and
|
|
15627
15880
|
* alpha-blend a second pass over eye silhouette pixels (see-through-hair effect). */
|
|
15628
15881
|
Engine.STENCIL_EYE_VALUE = 1;
|
|
15629
|
-
/** Aux MRT alongside HDR color.
|
|
15882
|
+
/** Aux MRT alongside HDR color. Three channels:
|
|
15630
15883
|
* .r — bloom mask (1 = model geometry, 0 = ground; sampled by bloom blit to gate prefilter).
|
|
15631
15884
|
* .g — accumulated alpha (the channel that used to live in hdr.a before the HDR format
|
|
15632
15885
|
* switched to rg11b10ufloat, which has no alpha). Sampled by composite/bloom to
|
|
15633
15886
|
* un-premultiply color for tonemap and to produce the canvas-drawable alpha used by
|
|
15634
15887
|
* the premultiplied alphaMode compositor (so the page background still shows through
|
|
15635
15888
|
* cleared / edge-faded regions like before).
|
|
15636
|
-
*
|
|
15637
|
-
|
|
15889
|
+
* .b — subsurface strength, set by a graph's `subsurface` node and 0 everywhere
|
|
15890
|
+
* else; the scattering pass reads it to find skin (passes/subsurface.ts).
|
|
15891
|
+
* rgba8unorm at 4× MSAA is 16 bytes/texel; it never leaves tile memory (storeOp
|
|
15892
|
+
* discard), only its single-sample resolve does. */
|
|
15893
|
+
Engine.BLOOM_MASK_FORMAT = "rgba8unorm";
|
|
15638
15894
|
/**
|
|
15639
15895
|
* The master switch for the id attachment. OFF — and off having been proven
|
|
15640
15896
|
* to work, not off because it was never finished.
|
|
@@ -15786,6 +16042,24 @@ Engine.MIRROR_DIALS = {
|
|
|
15786
16042
|
frame: "FRAME",
|
|
15787
16043
|
frameColor: "FRAME_COLOR",
|
|
15788
16044
|
};
|
|
16045
|
+
/**
|
|
16046
|
+
* Drive the mirror from whichever effect declares one.
|
|
16047
|
+
*
|
|
16048
|
+
* Runs before reflectionActive is read, because the answer to "is there a
|
|
16049
|
+
* mirror" is this function's output. FIRST match wins and the rest are
|
|
16050
|
+
* ignored: there is one reflection target, so a second mirror is not a second
|
|
16051
|
+
* mirror, it is a fight over the same plane — and a scene that quietly
|
|
16052
|
+
* reflected the wrong one would be far harder to understand than one where
|
|
16053
|
+
* the second mirror does nothing.
|
|
16054
|
+
*
|
|
16055
|
+
* Gated on `weight`, so a scheduled mirror appears and leaves with its strip
|
|
16056
|
+
* and a faded-out one costs no reflection pass at all.
|
|
16057
|
+
*/
|
|
16058
|
+
/** The dials a stepped effect is read by, by name — MIRROR_DIALS' pattern. */
|
|
16059
|
+
Engine.STEPPED_DIALS = {
|
|
16060
|
+
/** Poses per second of scene time: 12 is 24fps animation on twos, 6 on fours. */
|
|
16061
|
+
fps: "FPS",
|
|
16062
|
+
};
|
|
15789
16063
|
/** Opaque red — a selection is a working state, not a material property,
|
|
15790
16064
|
* so it reads as unmistakably distinct from anything a model's own
|
|
15791
16065
|
* colours could be. */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pool_floor.d.ts","sourceRoot":"","sources":["../../../src/graph/presets/pool_floor.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAE5C,eAAO,MAAM,gBAAgB,EAAE,WA6B9B,CAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Pool floor — the tiled bottom seen through water, with caustics on it.
|
|
2
|
+
//
|
|
3
|
+
// The other half of a pool, and the half that does most of the work. A water
|
|
4
|
+
// surface can be tuned for a long time without the shot reading as a pool;
|
|
5
|
+
// putting the focused-light web on the FLOOR is what settles it, because that
|
|
6
|
+
// is the cue a photograph actually carries. It is a floor material, so it is
|
|
7
|
+
// applied to the tile under the water rather than to the water itself.
|
|
8
|
+
//
|
|
9
|
+
// Caustics land between the albedo and the shading deliberately: they are
|
|
10
|
+
// light, so they should still be dimmed by the floor's own shadow rather than
|
|
11
|
+
// glowing through it. That is the difference between water-focused sun and a
|
|
12
|
+
// decal.
|
|
13
|
+
export const POOL_FLOOR_GRAPH = {
|
|
14
|
+
version: 1,
|
|
15
|
+
name: "Pool floor",
|
|
16
|
+
tags: ["stage", "water", "pool"],
|
|
17
|
+
nodes: [
|
|
18
|
+
{ id: "tex", type: "texture" },
|
|
19
|
+
{ id: "mat", type: "material_diffuse" },
|
|
20
|
+
{ id: "base", type: "mix/multiply", inputs: { fac: 1.0 } },
|
|
21
|
+
{ id: "caust", type: "caustics" },
|
|
22
|
+
{
|
|
23
|
+
id: "principled",
|
|
24
|
+
type: "principled",
|
|
25
|
+
inputs: { metallic: 0.0, specular_ior_level: 0.4, roughness: 0.45, spec_clamp: 10.0, sheen_weight: 0.0, sheen_tint: 0.0 },
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
links: [
|
|
29
|
+
{ from: { node: "tex", socket: "color" }, to: { node: "base", socket: "a" } },
|
|
30
|
+
{ from: { node: "mat", socket: "color" }, to: { node: "base", socket: "b" } },
|
|
31
|
+
{ from: { node: "base", socket: "color" }, to: { node: "caust", socket: "color" } },
|
|
32
|
+
{ from: { node: "caust", socket: "color" }, to: { node: "principled", socket: "base_color" } },
|
|
33
|
+
],
|
|
34
|
+
output: { node: "principled", socket: "color" },
|
|
35
|
+
params: [
|
|
36
|
+
{ id: "tint", label: "Light tint", target: { node: "caust", socket: "tint" }, kind: "color", default: [1.0, 1.0, 1.0] },
|
|
37
|
+
{ id: "scale", label: "Caustic scale", target: { node: "caust", socket: "scale" }, kind: "float", min: 0.01, max: 1, default: 0.12 },
|
|
38
|
+
{ id: "speed", label: "Caustic speed", target: { node: "caust", socket: "speed" }, kind: "float", min: 0, max: 1, default: 0.15 },
|
|
39
|
+
{ id: "strength", label: "Caustic strength", target: { node: "caust", socket: "strength" }, kind: "float", min: 0, max: 3, default: 0.6 },
|
|
40
|
+
{ id: "fade", label: "Depth fade", target: { node: "caust", socket: "fade" }, kind: "float", min: 1, max: 200, default: 30 },
|
|
41
|
+
],
|
|
42
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"water.d.ts","sourceRoot":"","sources":["../../../src/graph/presets/water.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAE5C,eAAO,MAAM,WAAW,EAAE,WAgBzB,CAAA"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Water — a planar reflection, rippled, seen through Fresnel.
|
|
2
|
+
//
|
|
3
|
+
// Put a stage's water materials in a style group carrying this graph and the
|
|
4
|
+
// pool starts reflecting. The reflection itself is the engine's mirror pass,
|
|
5
|
+
// which this is the only graph to read; everything else here is the shaping
|
|
6
|
+
// that keeps it from reading as a mirror laid flat in the floor.
|
|
7
|
+
//
|
|
8
|
+
// The exposed params are the ones worth a slider while judging a shot. Scale
|
|
9
|
+
// and speed are the ripple; a real pool's surface is slow and broad, so both
|
|
10
|
+
// defaults sit low. Tint is the water's own colour — a game rip carries that
|
|
11
|
+
// in its material, and the converter hands it straight over.
|
|
12
|
+
//
|
|
13
|
+
// How see-through the water is belongs to the MATERIAL's alpha, not to this
|
|
14
|
+
// graph, which is where every other group's coverage comes from too.
|
|
15
|
+
export const WATER_GRAPH = {
|
|
16
|
+
version: 1,
|
|
17
|
+
name: "Water",
|
|
18
|
+
tags: ["water", "stage"],
|
|
19
|
+
nodes: [{ id: "water", type: "water" }],
|
|
20
|
+
links: [],
|
|
21
|
+
output: { node: "water", socket: "color" },
|
|
22
|
+
params: [
|
|
23
|
+
{ id: "tint", label: "Tint", target: { node: "water", socket: "tint" }, kind: "color", default: [0.04, 0.62, 0.66] },
|
|
24
|
+
{ id: "scale", label: "Ripple scale", target: { node: "water", socket: "scale" }, kind: "float", min: 0.01, max: 1, default: 0.18 },
|
|
25
|
+
{ id: "speed", label: "Ripple speed", target: { node: "water", socket: "speed" }, kind: "float", min: 0, max: 1, default: 0.12 },
|
|
26
|
+
{ id: "strength", label: "Ripple depth", target: { node: "water", socket: "strength" }, kind: "float", min: 0, max: 2, default: 0.7 },
|
|
27
|
+
{ id: "blur", label: "Reflection blur", target: { node: "water", socket: "blur" }, kind: "float", min: 0, max: 1, default: 0.25 },
|
|
28
|
+
{ id: "mirroring", label: "Mirroring", target: { node: "water", socket: "mirroring" }, kind: "float", min: 0, max: 1, default: 0.20 },
|
|
29
|
+
{ id: "sparkle", label: "Sparkle", target: { node: "water", socket: "sparkle" }, kind: "float", min: 0, max: 4, default: 1.0 },
|
|
30
|
+
],
|
|
31
|
+
};
|
|
@@ -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;CACtC,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;AAyCD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,
|
|
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;CACtC,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;AAyCD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAivBlD,CAAA"}
|