incanto 0.14.0 → 0.16.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/3d.d.ts +34 -0
- package/dist/3d.js +3 -3
- package/dist/{create-game-OSntcIiM.js → create-game-B5GWzy1E.js} +2 -109
- package/dist/index.js +1 -1
- package/dist/{physics-3d-D_kUdOjr.js → physics-3d-CDlvC9Z_.js} +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-C9-16x_t.js → register-Lp2qn1Wq.js} +435 -37
- package/dist/test.js +3 -3
- package/editor/assets/{agent8-BDC4LhjC.js → agent8-Cw7igxDG.js} +1 -1
- package/editor/assets/{index-7qOYg7t8.js → index-N3Hnrv0w.js} +217 -118
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +25 -0
- package/skills/incanto-environment.md +14 -2
- package/skills/incanto-node-reference.md +6 -0
- package/templates-app/beacon-isle-3d/PROJECT/Status.md +1 -1
- package/templates-app/beacon-isle-3d/generate-world.ts +23 -18
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/beacon-isle-3d/src/behaviors.ts +70 -4
- package/templates-app/beacon-isle-3d/src/game.scene.json +20 -21
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/village-quest-3d/PROJECT/Context.md +1 -1
- package/templates-app/village-quest-3d/PROJECT/Requirements.md +1 -1
- package/templates-app/village-quest-3d/PROJECT/Structure.md +6 -1
- package/templates-app/village-quest-3d/generate-dressing.ts +769 -0
- package/templates-app/village-quest-3d/package.json +1 -1
- package/templates-app/village-quest-3d/src/behaviors.ts +74 -8
- package/templates-app/village-quest-3d/src/grove.scene.json +1 -13
- package/templates-app/village-quest-3d/src/village.scene.json +2989 -162
|
@@ -10269,6 +10269,120 @@ void main() {
|
|
|
10269
10269
|
}
|
|
10270
10270
|
`;
|
|
10271
10271
|
//#endregion
|
|
10272
|
+
//#region src/3d/water/caustics.ts
|
|
10273
|
+
/**
|
|
10274
|
+
* Underwater caustics — the dancing refracted-light pattern the water surface
|
|
10275
|
+
* throws onto everything below it. The engine has no post-processing pipeline,
|
|
10276
|
+
* so the renderer does this as ONE depth-aware composite pass, and ONLY while
|
|
10277
|
+
* the camera is genuinely underwater (so normal above-water rendering — even
|
|
10278
|
+
* standing at the water's edge — is completely untouched):
|
|
10279
|
+
*
|
|
10280
|
+
* 1. render the scene to an offscreen target (color + depth)
|
|
10281
|
+
* 2. draw this fullscreen material, which reconstructs each pixel's WORLD
|
|
10282
|
+
* position from the depth buffer and adds an animated caustic highlight
|
|
10283
|
+
* wherever that world point sits below the water surface
|
|
10284
|
+
*
|
|
10285
|
+
* Because the pattern is keyed to reconstructed world XZ, it STICKS to the
|
|
10286
|
+
* floor/walls/props (it isn't a flat screen overlay) and fades with depth +
|
|
10287
|
+
* view distance so it melts into the underwater fog.
|
|
10288
|
+
*/
|
|
10289
|
+
/** Fullscreen triangle/quad — the vertex stage ignores the camera entirely. */
|
|
10290
|
+
const CAUSTICS_VERT = `
|
|
10291
|
+
varying vec2 vUv;
|
|
10292
|
+
void main() {
|
|
10293
|
+
vUv = uv;
|
|
10294
|
+
gl_Position = vec4(position.xy, 0.0, 1.0);
|
|
10295
|
+
}
|
|
10296
|
+
`;
|
|
10297
|
+
/**
|
|
10298
|
+
* The classic animated caustic pattern (layered moving cells), 0..1 — SHARED
|
|
10299
|
+
* between the underwater composite and Water3D's above-water caustics (the
|
|
10300
|
+
* refracted bottom shimmer), so both views of the same water agree.
|
|
10301
|
+
*/
|
|
10302
|
+
const CAUSTIC_GLSL = `
|
|
10303
|
+
float caustic(vec2 uv, float t) {
|
|
10304
|
+
vec2 p = mod(uv * 6.28318, 6.28318) - 250.0;
|
|
10305
|
+
vec2 i = p;
|
|
10306
|
+
float c = 1.0;
|
|
10307
|
+
float inten = 0.005;
|
|
10308
|
+
for (int n = 0; n < 5; n++) {
|
|
10309
|
+
float ti = t * (1.0 - (3.5 / float(n + 1)));
|
|
10310
|
+
i = p + vec2(cos(ti - i.x) + sin(ti + i.y), sin(ti - i.y) + cos(ti + i.x));
|
|
10311
|
+
c += 1.0 / length(vec2(p.x / (sin(i.x + ti) / inten), p.y / (cos(i.y + ti) / inten)));
|
|
10312
|
+
}
|
|
10313
|
+
c /= 5.0;
|
|
10314
|
+
c = 1.17 - pow(c, 1.4);
|
|
10315
|
+
return clamp(pow(abs(c), 8.0), 0.0, 1.0);
|
|
10316
|
+
}
|
|
10317
|
+
`;
|
|
10318
|
+
const CAUSTICS_FRAG = `
|
|
10319
|
+
precision highp float;
|
|
10320
|
+
varying vec2 vUv;
|
|
10321
|
+
uniform sampler2D tColor;
|
|
10322
|
+
uniform sampler2D tDepth;
|
|
10323
|
+
uniform mat4 uInvViewProj;
|
|
10324
|
+
uniform vec3 uCameraPos;
|
|
10325
|
+
uniform float uWaterLevel;
|
|
10326
|
+
uniform float uTime;
|
|
10327
|
+
uniform vec3 uCausticColor;
|
|
10328
|
+
uniform float uCausticIntensity;
|
|
10329
|
+
uniform float uCausticScale;
|
|
10330
|
+
uniform float uMaxDist;
|
|
10331
|
+
|
|
10332
|
+
${CAUSTIC_GLSL}
|
|
10333
|
+
|
|
10334
|
+
void main() {
|
|
10335
|
+
vec4 color = texture2D(tColor, vUv);
|
|
10336
|
+
float depth = texture2D(tDepth, vUv).x;
|
|
10337
|
+
// depth == 1 is the far plane (sky/background) — nothing to light there
|
|
10338
|
+
if (depth < 1.0) {
|
|
10339
|
+
vec4 ndc = vec4(vUv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
|
|
10340
|
+
vec4 world = uInvViewProj * ndc;
|
|
10341
|
+
world.xyz /= world.w;
|
|
10342
|
+
float below = uWaterLevel - world.y;
|
|
10343
|
+
if (below > 0.0) {
|
|
10344
|
+
float dist = distance(world.xyz, uCameraPos);
|
|
10345
|
+
// caustics — fade with distance (melt into the fog) + a touch with depth
|
|
10346
|
+
float distFade = 1.0 - clamp(dist / uMaxDist, 0.0, 1.0);
|
|
10347
|
+
float depthFade = 1.0 - clamp(below / (uMaxDist * 0.5), 0.0, 0.6);
|
|
10348
|
+
// two octaves at offset speeds = the shimmering interference of real caustics
|
|
10349
|
+
float c =
|
|
10350
|
+
caustic(world.xz * uCausticScale, uTime) * 0.65 +
|
|
10351
|
+
caustic(world.xz * uCausticScale * 1.7 + 30.0, uTime * 0.8) * 0.35;
|
|
10352
|
+
color.rgb += uCausticColor * (c * uCausticIntensity * distFade * distFade * depthFade);
|
|
10353
|
+
}
|
|
10354
|
+
}
|
|
10355
|
+
gl_FragColor = color;
|
|
10356
|
+
}
|
|
10357
|
+
`;
|
|
10358
|
+
/** Build the fullscreen composite mesh (a 2×2 clip-space quad). */
|
|
10359
|
+
function createCausticsQuad() {
|
|
10360
|
+
const material = new ShaderMaterial({
|
|
10361
|
+
vertexShader: CAUSTICS_VERT,
|
|
10362
|
+
fragmentShader: CAUSTICS_FRAG,
|
|
10363
|
+
depthTest: false,
|
|
10364
|
+
depthWrite: false,
|
|
10365
|
+
uniforms: {
|
|
10366
|
+
tColor: { value: null },
|
|
10367
|
+
tDepth: { value: null },
|
|
10368
|
+
uInvViewProj: { value: new Matrix4() },
|
|
10369
|
+
uCameraPos: { value: new Vector3() },
|
|
10370
|
+
uWaterLevel: { value: 0 },
|
|
10371
|
+
uTime: { value: 0 },
|
|
10372
|
+
uCausticColor: { value: new Color("#cdeeff") },
|
|
10373
|
+
uCausticIntensity: { value: .55 },
|
|
10374
|
+
uCausticScale: { value: .32 },
|
|
10375
|
+
uMaxDist: { value: 22 }
|
|
10376
|
+
}
|
|
10377
|
+
});
|
|
10378
|
+
const mesh = new Mesh(new PlaneGeometry(2, 2), material);
|
|
10379
|
+
mesh.frustumCulled = false;
|
|
10380
|
+
return {
|
|
10381
|
+
mesh,
|
|
10382
|
+
uniforms: material.uniforms
|
|
10383
|
+
};
|
|
10384
|
+
}
|
|
10385
|
+
//#endregion
|
|
10272
10386
|
//#region src/3d/water/shaders.ts
|
|
10273
10387
|
/**
|
|
10274
10388
|
* The Water3D 'fancy' shaders — ported VERBATIM from
|
|
@@ -10344,6 +10458,11 @@ uniform vec3 uScale;
|
|
|
10344
10458
|
// incanto: world-anchor + interaction ripples (x, z, age, amplitude)
|
|
10345
10459
|
uniform vec3 uWaterCenter;
|
|
10346
10460
|
uniform vec4 uRipples[8];
|
|
10461
|
+
// incanto swell: directional traveling wave trains (0 = off — legacy look).
|
|
10462
|
+
// uSwellDir is a unit XZ vector; amplitude in meters; wavelength in meters.
|
|
10463
|
+
uniform float uSwellAmplitude;
|
|
10464
|
+
uniform vec2 uSwellDir;
|
|
10465
|
+
uniform float uSwellWavelength;
|
|
10347
10466
|
|
|
10348
10467
|
varying vec3 vNormal;
|
|
10349
10468
|
varying vec3 vWorldPosition;
|
|
@@ -10426,10 +10545,34 @@ float getRippleHeight(vec2 p) {
|
|
|
10426
10545
|
return h;
|
|
10427
10546
|
}
|
|
10428
10547
|
|
|
10429
|
-
// incanto:
|
|
10430
|
-
//
|
|
10548
|
+
// incanto swell: one peaked traveling wave train. Deep-water dispersion
|
|
10549
|
+
// (c = sqrt(g/k)) gives each wavelength its REAL speed, so short chop
|
|
10550
|
+
// overtakes long swell exactly like the open sea. The pow-shaped profile
|
|
10551
|
+
// sharpens crests and flattens troughs (a height-only Gerstner stand-in —
|
|
10552
|
+
// no XZ pinch, so the analytic finite-difference normals stay exact).
|
|
10553
|
+
float swellWave(vec2 p, vec2 dir, float lambda, float amp, float sharp) {
|
|
10554
|
+
float k = 6.2831853 / max(lambda, 1.0);
|
|
10555
|
+
float c = sqrt(9.8 / k);
|
|
10556
|
+
float s = 0.5 + 0.5 * sin(dot(p, dir) * k - uTime * c * k);
|
|
10557
|
+
return amp * (pow(s, sharp) * 2.0 - 1.0);
|
|
10558
|
+
}
|
|
10559
|
+
|
|
10560
|
+
// incanto swell: three trains — the primary + two shorter crossing sets
|
|
10561
|
+
// (+25° / −19°) so crest lines stay broken and organic, never a zebra field.
|
|
10562
|
+
float getSwell(vec2 p) {
|
|
10563
|
+
if (uSwellAmplitude <= 0.0) return 0.0;
|
|
10564
|
+
vec2 d1 = uSwellDir;
|
|
10565
|
+
vec2 d2 = normalize(vec2(d1.x * 0.906 - d1.y * 0.423, d1.x * 0.423 + d1.y * 0.906));
|
|
10566
|
+
vec2 d3 = normalize(vec2(d1.x * 0.946 + d1.y * 0.326, -d1.x * 0.326 + d1.y * 0.946));
|
|
10567
|
+
return swellWave(p, d1, uSwellWavelength, uSwellAmplitude * 0.60, 2.6)
|
|
10568
|
+
+ swellWave(p, d2, uSwellWavelength * 0.53, uSwellAmplitude * 0.27, 2.2)
|
|
10569
|
+
+ swellWave(p, d3, uSwellWavelength * 0.31, uSwellAmplitude * 0.16, 1.8);
|
|
10570
|
+
}
|
|
10571
|
+
|
|
10572
|
+
// incanto: waves + swell + ripples — used for displacement AND the normal
|
|
10573
|
+
// samples so every layer catches the light like real waves.
|
|
10431
10574
|
float getHeight(float x, float z) {
|
|
10432
|
-
return getElevation(x, z) + getRippleHeight(vec2(x, z));
|
|
10575
|
+
return getElevation(x, z) + getSwell(vec2(x, z)) + getRippleHeight(vec2(x, z));
|
|
10433
10576
|
}
|
|
10434
10577
|
|
|
10435
10578
|
void main() {
|
|
@@ -10538,6 +10681,25 @@ uniform vec4 uRipples[8];
|
|
|
10538
10681
|
uniform float uRippleFoam[8];
|
|
10539
10682
|
uniform float uSplashFoam;
|
|
10540
10683
|
|
|
10684
|
+
// incanto swell: open-water WHITECAPS — foam breaking on the highest crests,
|
|
10685
|
+
// independent of the shoreline depth mask. uWaveEnvelope is the JS-computed
|
|
10686
|
+
// total wave amplitude (FBM + swell) so the crest mask normalizes by the
|
|
10687
|
+
// actual sea state, not the surface's extent. uSwellAmplitude gates the
|
|
10688
|
+
// swell-only color work (crest banding + wave-face shading).
|
|
10689
|
+
uniform float uWhitecaps;
|
|
10690
|
+
uniform float uWaveEnvelope;
|
|
10691
|
+
uniform float uSwellAmplitude;
|
|
10692
|
+
|
|
10693
|
+
// incanto presets: above-water CAUSTICS — the dancing light web on the
|
|
10694
|
+
// submerged bottom, seen THROUGH the surface (the pool/shallow-sea look).
|
|
10695
|
+
// Intensity 0 = off. The pattern fn is shared with the underwater composite.
|
|
10696
|
+
uniform float uCausticsAbove;
|
|
10697
|
+
// incanto presets: per-preset reflection ceiling (the old hard 0.6) — lakes
|
|
10698
|
+
// push toward mirror, pools stay glassy-clear.
|
|
10699
|
+
uniform float uReflectivityMax;
|
|
10700
|
+
|
|
10701
|
+
${CAUSTIC_GLSL}
|
|
10702
|
+
|
|
10541
10703
|
// 🎨 Contact surface color customization uniforms
|
|
10542
10704
|
uniform vec3 uEdgeColor;
|
|
10543
10705
|
uniform float uEdgeIntensity;
|
|
@@ -10924,6 +11086,24 @@ void main() {
|
|
|
10924
11086
|
// Mix between surface and peak colors based on peak transition
|
|
10925
11087
|
vec3 mixedColor2 = mix(mixedColor1, uPeakColor, peakFactor);
|
|
10926
11088
|
|
|
11089
|
+
// incanto swell: the legacy ramp normalizes elevation by the surface's
|
|
11090
|
+
// HALF-EXTENT — on a real ocean plane that's hundreds of meters, so the
|
|
11091
|
+
// ramp never sees a wave. When swell is on, re-read the crest height
|
|
11092
|
+
// against the actual sea state (uWaveEnvelope) and (a) lighten crest tops
|
|
11093
|
+
// toward the peak color, (b) shade the wave FACES with a gentle N·L off
|
|
11094
|
+
// the distance-smoothed geometry normal — the lit/shadow lanes are what
|
|
11095
|
+
// make open-ocean swell READ at any distance. Both gated: swell 0 keeps
|
|
11096
|
+
// the legacy look byte-identical.
|
|
11097
|
+
if (uSwellAmplitude > 0.0) {
|
|
11098
|
+
float crestBand = smoothstep(0.3, 0.9,
|
|
11099
|
+
(vWorldPosition.y - uWaterCenter.y) / max(uWaveEnvelope, 0.001));
|
|
11100
|
+
mixedColor2 = mix(mixedColor2, uPeakColor, crestBand * 0.45);
|
|
11101
|
+
float faceShade = clamp(dot(normalize(mix(vec3(0.0, 1.0, 0.0), normalize(vNormal),
|
|
11102
|
+
1.0 - 0.9 * smoothstep(150.0, 600.0, length(vWorldPosition - cameraPosition)))),
|
|
11103
|
+
normalize(uSunDirection)), 0.0, 1.0);
|
|
11104
|
+
mixedColor2 *= 0.80 + 0.32 * faceShade;
|
|
11105
|
+
}
|
|
11106
|
+
|
|
10927
11107
|
// incanto v2: Beer's-law depth absorption + screen-space refraction.
|
|
10928
11108
|
// Shallow water transmits the (refracted) scene almost untouched; depth
|
|
10929
11109
|
// exponentially absorbs it into the ramp color — clear turquoise edges,
|
|
@@ -10975,6 +11155,22 @@ void main() {
|
|
|
10975
11155
|
// underwater scene. Real water blurs what it refracts; the crisp
|
|
10976
11156
|
// half-res grab pixel-speckled at every silhouette and ripple edge.
|
|
10977
11157
|
vec3 sceneColor = texture2D(uSceneColor, refractedUV, 1.75).rgb;
|
|
11158
|
+
// incanto presets: above-water caustics — reconstruct the sampled
|
|
11159
|
+
// bottom's world position along the view ray and light it with the
|
|
11160
|
+
// shared caustic web. Strongest through the first meters of water
|
|
11161
|
+
// (a pool floor dances, the deep sea does not), distance-faded so far
|
|
11162
|
+
// shallows never shimmer-alias.
|
|
11163
|
+
if (uCausticsAbove > 0.0) {
|
|
11164
|
+
vec3 bottomWorld = cameraPosition + viewDirection * refrT;
|
|
11165
|
+
float below = uWaterCenter.y - bottomWorld.y;
|
|
11166
|
+
if (below > 0.05) {
|
|
11167
|
+
float reach = 1.0 - smoothstep(0.2, 9.0, below);
|
|
11168
|
+
float causticFade = 1.0 - smoothstep(60.0, 200.0, camDist);
|
|
11169
|
+
float cw = caustic(bottomWorld.xz * 0.42, uTime * 0.7) * 0.65
|
|
11170
|
+
+ caustic(bottomWorld.xz * 0.72 + 30.0, uTime * 0.55) * 0.35;
|
|
11171
|
+
sceneColor += vec3(0.87, 0.96, 1.0) * (cw * uCausticsAbove * reach * causticFade);
|
|
11172
|
+
}
|
|
11173
|
+
}
|
|
10978
11174
|
// opacity keeps its dial under in-shader compositing: it scales how
|
|
10979
11175
|
// strongly the water body hides the Beer-attenuated scene behind it —
|
|
10980
11176
|
// per channel, so the shallows tint instead of fading uniformly
|
|
@@ -11015,7 +11211,7 @@ void main() {
|
|
|
11015
11211
|
// mirror (dark scenes otherwise paint the near edge black). refinement
|
|
11016
11212
|
// pass: 0.75 → 0.6 — the reference sea stays teal even at range; an HDR
|
|
11017
11213
|
// sky at 3/4 mirror washed the whole far field toward white.
|
|
11018
|
-
float reflectivity = clamp(fresnel, 0.0,
|
|
11214
|
+
float reflectivity = clamp(fresnel, 0.0, uReflectivityMax) * uUseEnvironmentMap;
|
|
11019
11215
|
vec3 finalColor = mix(bodyColor, reflectionColor.rgb, reflectivity);
|
|
11020
11216
|
|
|
11021
11217
|
// incanto v2: sun specular off the detail-perturbed normal.
|
|
@@ -11060,6 +11256,22 @@ void main() {
|
|
|
11060
11256
|
if (uEnableFoam > 0.5) {
|
|
11061
11257
|
foamAmount = calculateFoam();
|
|
11062
11258
|
}
|
|
11259
|
+
// incanto swell: whitecaps — foam eats the TOPS of the tallest crests in
|
|
11260
|
+
// open water. The crest mask normalizes elevation by the real wave envelope
|
|
11261
|
+
// (uScale.y is the surface's half-extent — useless as a sea-state yardstick
|
|
11262
|
+
// on a big ocean plane), and a two-octave noise breaks the caps into
|
|
11263
|
+
// patches that live and die with the crests. Distance-faded: far whitecaps
|
|
11264
|
+
// subtend under a pixel and would alias into horizon speckle.
|
|
11265
|
+
if (uWhitecaps > 0.0 && uWaveEnvelope > 0.001) {
|
|
11266
|
+
float crestN = (vWorldPosition.y - uWaterCenter.y) / uWaveEnvelope;
|
|
11267
|
+
float cap = smoothstep(0.5, 0.85, crestN);
|
|
11268
|
+
vec2 capUV = vWorldPosition.xz * 0.3;
|
|
11269
|
+
float capNoise = noise(capUV * 2.2 + uTime * vec2(0.10, 0.06)) * 0.65
|
|
11270
|
+
+ noise(capUV * 6.5 - uTime * vec2(0.05, 0.14)) * 0.35;
|
|
11271
|
+
float capFade = 1.0 - smoothstep(220.0, 640.0, camDist);
|
|
11272
|
+
float whitecap = uWhitecaps * cap * smoothstep(0.42, 0.78, capNoise) * capFade;
|
|
11273
|
+
foamAmount = max(foamAmount, whitecap);
|
|
11274
|
+
}
|
|
11063
11275
|
// incanto: splash/wake whitewater rides the ripple buffer, INDEPENDENT of the
|
|
11064
11276
|
// depth-foam gate so it works even on shallow ponds / before the first pre-pass
|
|
11065
11277
|
float splashFoam = rippleFoam(vWorldPosition.xz);
|
|
@@ -11322,6 +11534,108 @@ const COLOR_KEYS = [
|
|
|
11322
11534
|
"surface",
|
|
11323
11535
|
"peak"
|
|
11324
11536
|
];
|
|
11537
|
+
const WATER_PRESET_NAMES = [
|
|
11538
|
+
"custom",
|
|
11539
|
+
"ocean",
|
|
11540
|
+
"pool",
|
|
11541
|
+
"lake",
|
|
11542
|
+
"pond"
|
|
11543
|
+
];
|
|
11544
|
+
/**
|
|
11545
|
+
* The four curated water types — `preset: 'ocean' | 'pool' | 'lake' | 'pond'`
|
|
11546
|
+
* is THE one-choice dial: each bundle sets every wave/color/clarity/caustics
|
|
11547
|
+
* knob to a hand-tuned sea state. A preset value applies ONLY while the prop
|
|
11548
|
+
* still sits at its schema default (same convention as the env-sun handoff),
|
|
11549
|
+
* so any explicitly authored prop wins — pick the type, then override details
|
|
11550
|
+
* to taste.
|
|
11551
|
+
*
|
|
11552
|
+
* - ocean: traveling swell + whitecaps, wide turquoise→deep-blue absorption
|
|
11553
|
+
* - pool: near-flat crystal water, strong above-water caustics on the floor
|
|
11554
|
+
* - lake: calm mirror — high reflectivity, murkier green-teal depths
|
|
11555
|
+
* - pond: still, mossy, opaque quickly — the garden pond
|
|
11556
|
+
*/
|
|
11557
|
+
const WATER_PRESETS = {
|
|
11558
|
+
ocean: {
|
|
11559
|
+
waveHeight: .06,
|
|
11560
|
+
swell: .55,
|
|
11561
|
+
swellWavelength: 42,
|
|
11562
|
+
whitecaps: .45,
|
|
11563
|
+
absorption: .2,
|
|
11564
|
+
opacity: .85,
|
|
11565
|
+
detailStrength: .3,
|
|
11566
|
+
colors: {
|
|
11567
|
+
trough: "#0c3d58",
|
|
11568
|
+
surface: "#1a7d9c",
|
|
11569
|
+
peak: "#9adfe0"
|
|
11570
|
+
},
|
|
11571
|
+
color: "#1a7d9c",
|
|
11572
|
+
causticsAbove: .35,
|
|
11573
|
+
reflectionInterval: 400
|
|
11574
|
+
},
|
|
11575
|
+
pool: {
|
|
11576
|
+
waveHeight: .006,
|
|
11577
|
+
swell: 0,
|
|
11578
|
+
whitecaps: 0,
|
|
11579
|
+
absorption: .3,
|
|
11580
|
+
opacity: .5,
|
|
11581
|
+
detailStrength: .16,
|
|
11582
|
+
sunIntensity: 1.25,
|
|
11583
|
+
colors: {
|
|
11584
|
+
trough: "#1e8dbe",
|
|
11585
|
+
surface: "#3fb6dc",
|
|
11586
|
+
peak: "#bdeef7"
|
|
11587
|
+
},
|
|
11588
|
+
color: "#3fb6dc",
|
|
11589
|
+
causticsAbove: 1,
|
|
11590
|
+
reflectionInterval: 600,
|
|
11591
|
+
_look: {
|
|
11592
|
+
fresnelScale: .85,
|
|
11593
|
+
reflectivityMax: .5
|
|
11594
|
+
}
|
|
11595
|
+
},
|
|
11596
|
+
lake: {
|
|
11597
|
+
waveHeight: .028,
|
|
11598
|
+
swell: .14,
|
|
11599
|
+
swellWavelength: 24,
|
|
11600
|
+
whitecaps: 0,
|
|
11601
|
+
absorption: .5,
|
|
11602
|
+
opacity: .88,
|
|
11603
|
+
detailStrength: .3,
|
|
11604
|
+
colors: {
|
|
11605
|
+
trough: "#12343a",
|
|
11606
|
+
surface: "#25565c",
|
|
11607
|
+
peak: "#7fb2ab"
|
|
11608
|
+
},
|
|
11609
|
+
color: "#25565c",
|
|
11610
|
+
causticsAbove: .15,
|
|
11611
|
+
reflectionInterval: 300,
|
|
11612
|
+
_look: {
|
|
11613
|
+
fresnelScale: 1.25,
|
|
11614
|
+
reflectivityMax: .78
|
|
11615
|
+
}
|
|
11616
|
+
},
|
|
11617
|
+
pond: {
|
|
11618
|
+
waveHeight: .012,
|
|
11619
|
+
swell: 0,
|
|
11620
|
+
whitecaps: 0,
|
|
11621
|
+
absorption: .55,
|
|
11622
|
+
opacity: .88,
|
|
11623
|
+
detailStrength: .2,
|
|
11624
|
+
sunIntensity: .9,
|
|
11625
|
+
colors: {
|
|
11626
|
+
trough: "#24402a",
|
|
11627
|
+
surface: "#436b4d",
|
|
11628
|
+
peak: "#8fae8e"
|
|
11629
|
+
},
|
|
11630
|
+
color: "#436b4d",
|
|
11631
|
+
causticsAbove: .2,
|
|
11632
|
+
reflectionInterval: 800,
|
|
11633
|
+
_look: {
|
|
11634
|
+
fresnelScale: 1.1,
|
|
11635
|
+
reflectivityMax: .68
|
|
11636
|
+
}
|
|
11637
|
+
}
|
|
11638
|
+
};
|
|
11325
11639
|
/** Refinement-pass palette — teal-leaning sea blues sampled off the reference
|
|
11326
11640
|
* calm sea (deep open water ≈ #2b7993, mid teal ≈ #16878a). The old ported
|
|
11327
11641
|
* palette (#1f5b8a/#52a0d0/#aee3ff) read as saturated pool blue. */
|
|
@@ -11469,7 +11783,16 @@ var Water3D = class Water3D extends Node3D {
|
|
|
11469
11783
|
detailStrength: { default: .26 },
|
|
11470
11784
|
absorption: { default: .15 },
|
|
11471
11785
|
refraction: { default: true },
|
|
11472
|
-
underwater: { default: true }
|
|
11786
|
+
underwater: { default: true },
|
|
11787
|
+
swell: { default: 0 },
|
|
11788
|
+
swellDirectionDeg: { default: 0 },
|
|
11789
|
+
swellWavelength: { default: 30 },
|
|
11790
|
+
whitecaps: { default: 0 },
|
|
11791
|
+
preset: {
|
|
11792
|
+
default: "custom",
|
|
11793
|
+
options: WATER_PRESET_NAMES
|
|
11794
|
+
},
|
|
11795
|
+
causticsAbove: { default: 0 }
|
|
11473
11796
|
};
|
|
11474
11797
|
/** [width, depth] in meters (the surface lies on XZ). */
|
|
11475
11798
|
size = [40, 40];
|
|
@@ -11524,6 +11847,55 @@ var Water3D = class Water3D extends Node3D {
|
|
|
11524
11847
|
* `{ color?, visibility? }` overrides the fog hue / view distance (meters).
|
|
11525
11848
|
*/
|
|
11526
11849
|
underwater = true;
|
|
11850
|
+
/**
|
|
11851
|
+
* Directional traveling SWELL amplitude in meters (fancy only; 0 = off, the
|
|
11852
|
+
* legacy isotropic look). Three peaked wave trains march across the surface
|
|
11853
|
+
* at real deep-water speeds — THE open-ocean dial: 0.15 = lively lake chop,
|
|
11854
|
+
* 0.4 = coastal sea, 0.8 = heavy weather. Crests feed the color ramp,
|
|
11855
|
+
* `whitecaps` and the shore foam automatically.
|
|
11856
|
+
*/
|
|
11857
|
+
swell = 0;
|
|
11858
|
+
/** Compass direction the swell TRAVELS toward, degrees (0 = +z, 90 = +x). */
|
|
11859
|
+
swellDirectionDeg = 0;
|
|
11860
|
+
/** Primary swell wavelength in meters (the two crossing trains derive). */
|
|
11861
|
+
swellWavelength = 30;
|
|
11862
|
+
/** Open-water whitecap foam on the tallest crests, 0–1 (fancy only). Works
|
|
11863
|
+
* best with `swell` — the caps ride the swell's crest lines. */
|
|
11864
|
+
whitecaps = 0;
|
|
11865
|
+
/**
|
|
11866
|
+
* THE one-choice water type: 'ocean' | 'pool' | 'lake' | 'pond' bundles
|
|
11867
|
+
* every wave/color/clarity/caustics knob into a hand-tuned sea state
|
|
11868
|
+
* ('custom', the default, changes nothing). A preset value applies ONLY
|
|
11869
|
+
* where a prop still sits at its schema default — set the type first, then
|
|
11870
|
+
* override any detail prop to taste and your value wins.
|
|
11871
|
+
*/
|
|
11872
|
+
preset = "custom";
|
|
11873
|
+
/**
|
|
11874
|
+
* Above-water CAUSTICS intensity (0 = off): the dancing light web on the
|
|
11875
|
+
* submerged bottom, seen THROUGH the surface — the pool / tropical-shallows
|
|
11876
|
+
* look. Needs `refraction` (fancy quality). Presets set it; override freely.
|
|
11877
|
+
*/
|
|
11878
|
+
causticsAbove = 0;
|
|
11879
|
+
/** Preset-layered prop read (see {@link WATER_PRESETS}): the preset value
|
|
11880
|
+
* applies only while the prop sits at its schema default. */
|
|
11881
|
+
rp(key) {
|
|
11882
|
+
const bundle = WATER_PRESETS[this.preset];
|
|
11883
|
+
const self = this;
|
|
11884
|
+
if (bundle && key in bundle) {
|
|
11885
|
+
const def = Water3D.props[key]?.default;
|
|
11886
|
+
const cur = self[key];
|
|
11887
|
+
if (typeof cur === "object" && cur !== null ? JSON.stringify(cur) === JSON.stringify(def) : cur === def) return bundle[key];
|
|
11888
|
+
}
|
|
11889
|
+
return self[key];
|
|
11890
|
+
}
|
|
11891
|
+
/** Per-preset internal look constants (fresnel curve, reflection ceiling). */
|
|
11892
|
+
presetLook() {
|
|
11893
|
+
const look = WATER_PRESETS[this.preset]?._look;
|
|
11894
|
+
return {
|
|
11895
|
+
fresnelScale: look?.fresnelScale ?? FANCY_LOOK.fresnelScale,
|
|
11896
|
+
reflectivityMax: look?.reflectivityMax ?? .6
|
|
11897
|
+
};
|
|
11898
|
+
}
|
|
11527
11899
|
/** Loader hook: degenerate planes and bad enums fail at LOAD, not at render. */
|
|
11528
11900
|
static validateJson(node) {
|
|
11529
11901
|
const w = node;
|
|
@@ -11545,6 +11917,14 @@ var Water3D = class Water3D extends Node3D {
|
|
|
11545
11917
|
if (!(w.sunIntensity >= 0)) throw new IncantoError("BAD_FORMAT", `Water3D '${node.name}' sunIntensity must be >= 0, got ${w.sunIntensity}.`, { prop: "sunIntensity" });
|
|
11546
11918
|
if (!(w.detailStrength >= 0)) throw new IncantoError("BAD_FORMAT", `Water3D '${node.name}' detailStrength must be >= 0, got ${w.detailStrength}.`, { prop: "detailStrength" });
|
|
11547
11919
|
if (!(w.absorption >= 0)) throw new IncantoError("BAD_FORMAT", `Water3D '${node.name}' absorption must be >= 0 (per-meter Beer's-law constant), got ${w.absorption}.`, { prop: "absorption" });
|
|
11920
|
+
if (!(w.swell >= 0) || !Number.isFinite(w.swell)) throw new IncantoError("BAD_FORMAT", `Water3D '${node.name}' swell must be >= 0 meters (0 = off), got ${JSON.stringify(w.swell)}.`, { prop: "swell" });
|
|
11921
|
+
if (!(w.swellWavelength >= 2)) throw new IncantoError("BAD_FORMAT", `Water3D '${node.name}' swellWavelength must be >= 2 meters, got ${JSON.stringify(w.swellWavelength)}.`, { prop: "swellWavelength" });
|
|
11922
|
+
if (!(w.whitecaps >= 0) || !(w.whitecaps <= 1)) throw new IncantoError("BAD_FORMAT", `Water3D '${node.name}' whitecaps must be in [0, 1], got ${JSON.stringify(w.whitecaps)}.`, { prop: "whitecaps" });
|
|
11923
|
+
if (!WATER_PRESET_NAMES.includes(w.preset)) throw new IncantoError("BAD_FORMAT", `Water3D '${node.name}' preset must be one of [${WATER_PRESET_NAMES.join(", ")}], got '${w.preset}'.`, {
|
|
11924
|
+
prop: "preset",
|
|
11925
|
+
validOptions: WATER_PRESET_NAMES
|
|
11926
|
+
});
|
|
11927
|
+
if (!(w.causticsAbove >= 0) || !(w.causticsAbove <= 3)) throw new IncantoError("BAD_FORMAT", `Water3D '${node.name}' causticsAbove must be in [0, 3] (0 = off), got ${JSON.stringify(w.causticsAbove)}.`, { prop: "causticsAbove" });
|
|
11548
11928
|
const uw = w.underwater;
|
|
11549
11929
|
if (typeof uw !== "boolean") {
|
|
11550
11930
|
if (typeof uw !== "object" || uw === null || Array.isArray(uw)) throw new IncantoError("BAD_FORMAT", `Water3D '${node.name}' underwater must be true, false or an object ({ color?, visibility? }), got ${JSON.stringify(uw)}.`, { prop: "underwater" });
|
|
@@ -11624,7 +12004,7 @@ var Water3D = class Water3D extends Node3D {
|
|
|
11624
12004
|
this.cubeCamera = new CubeCamera(near, 1e3, this.cubeTarget);
|
|
11625
12005
|
this.lastReflectionAt = 0;
|
|
11626
12006
|
}
|
|
11627
|
-
if (this.lastReflectionAt === 0 || now - this.lastReflectionAt >= this.reflectionInterval) {
|
|
12007
|
+
if (this.lastReflectionAt === 0 || now - this.lastReflectionAt >= this.rp("reflectionInterval")) {
|
|
11628
12008
|
this.lastReflectionAt = now;
|
|
11629
12009
|
const center = worldTranslationOf(this);
|
|
11630
12010
|
const cam = this.cubeCamera;
|
|
@@ -11711,7 +12091,7 @@ var Water3D = class Water3D extends Node3D {
|
|
|
11711
12091
|
halfW: (this.size[0] ?? 1) / 2,
|
|
11712
12092
|
halfD: (this.size[1] ?? 1) / 2
|
|
11713
12093
|
}, UNDERWATER_MARGIN)) return null;
|
|
11714
|
-
const cfg = resolveUnderwater(this.underwater, this.color);
|
|
12094
|
+
const cfg = resolveUnderwater(this.underwater, this.rp("color"));
|
|
11715
12095
|
return cfg.enabled ? {
|
|
11716
12096
|
...cfg,
|
|
11717
12097
|
surfaceY: center.y
|
|
@@ -11757,10 +12137,10 @@ var Water3D = class Water3D extends Node3D {
|
|
|
11757
12137
|
fogFar: { value: 1e3 },
|
|
11758
12138
|
fogDensity: { value: 25e-5 },
|
|
11759
12139
|
uTime: { value: 0 },
|
|
11760
|
-
uOpacity: { value: this.opacity },
|
|
12140
|
+
uOpacity: { value: this.rp("opacity") },
|
|
11761
12141
|
uEnvironmentMap: { value: null },
|
|
11762
12142
|
uUseEnvironmentMap: { value: 0 },
|
|
11763
|
-
uWavesAmplitude: { value: this.waveHeight * AMPLITUDE_PER_WAVE_HEIGHT },
|
|
12143
|
+
uWavesAmplitude: { value: this.rp("waveHeight") * AMPLITUDE_PER_WAVE_HEIGHT },
|
|
11764
12144
|
uWavesSpeed: { value: FANCY_WAVE.speed },
|
|
11765
12145
|
uWavesFrequency: { value: FANCY_WAVE.frequency },
|
|
11766
12146
|
uWavesPersistence: { value: FANCY_WAVE.persistence },
|
|
@@ -11782,9 +12162,9 @@ var Water3D = class Water3D extends Node3D {
|
|
|
11782
12162
|
uSplashFoam: { value: this.splash ? 1 : 0 },
|
|
11783
12163
|
uSunDirection: { value: new Vector3(.5, .8, .3) },
|
|
11784
12164
|
uSunColor: { value: new Color(this.sunColor) },
|
|
11785
|
-
uSunIntensity: { value: this.sunIntensity },
|
|
11786
|
-
uDetailStrength: { value: this.detailStrength },
|
|
11787
|
-
uAbsorption: { value: this.absorption },
|
|
12165
|
+
uSunIntensity: { value: this.rp("sunIntensity") },
|
|
12166
|
+
uDetailStrength: { value: this.rp("detailStrength") },
|
|
12167
|
+
uAbsorption: { value: this.rp("absorption") },
|
|
11788
12168
|
uUseSceneDepth: { value: 0 },
|
|
11789
12169
|
uUseRefraction: { value: 0 },
|
|
11790
12170
|
uSceneColor: { value: null },
|
|
@@ -11798,7 +12178,14 @@ var Water3D = class Water3D extends Node3D {
|
|
|
11798
12178
|
uCameraFar: { value: 1e3 },
|
|
11799
12179
|
uEdgeColor: { value: new Color(FOAM_LOOK.edgeColor) },
|
|
11800
12180
|
uEdgeIntensity: { value: FOAM_LOOK.edgeIntensity },
|
|
11801
|
-
uEdgeWidth: { value: FOAM_LOOK.edgeWidth }
|
|
12181
|
+
uEdgeWidth: { value: FOAM_LOOK.edgeWidth },
|
|
12182
|
+
uSwellAmplitude: { value: this.rp("swell") },
|
|
12183
|
+
uSwellDir: { value: new Vector2(0, 1) },
|
|
12184
|
+
uSwellWavelength: { value: this.rp("swellWavelength") },
|
|
12185
|
+
uWhitecaps: { value: this.rp("whitecaps") },
|
|
12186
|
+
uWaveEnvelope: { value: 0 },
|
|
12187
|
+
uCausticsAbove: { value: this.rp("causticsAbove") },
|
|
12188
|
+
uReflectivityMax: { value: .6 }
|
|
11802
12189
|
},
|
|
11803
12190
|
transparent: true,
|
|
11804
12191
|
depthTest: true,
|
|
@@ -11819,14 +12206,14 @@ var Water3D = class Water3D extends Node3D {
|
|
|
11819
12206
|
fogFar: { value: 1e3 },
|
|
11820
12207
|
fogDensity: { value: 25e-5 },
|
|
11821
12208
|
uTime: { value: 0 },
|
|
11822
|
-
uOpacity: { value: this.opacity },
|
|
11823
|
-
uColor: { value: new Color(this.color) },
|
|
11824
|
-
uSurfaceColor: { value: new Color(this.color) },
|
|
11825
|
-
uSkyColor: { value: new Color(this.color) },
|
|
12209
|
+
uOpacity: { value: this.rp("opacity") },
|
|
12210
|
+
uColor: { value: new Color(this.rp("color")) },
|
|
12211
|
+
uSurfaceColor: { value: new Color(this.rp("color")) },
|
|
12212
|
+
uSkyColor: { value: new Color(this.rp("color")) },
|
|
11826
12213
|
uSunDirection: { value: new Vector3(.5, .8, .3).normalize() },
|
|
11827
12214
|
uSunColor: { value: new Color(this.sunColor) },
|
|
11828
|
-
uSunIntensity: { value: this.sunIntensity },
|
|
11829
|
-
uDetailStrength: { value: this.detailStrength },
|
|
12215
|
+
uSunIntensity: { value: this.rp("sunIntensity") },
|
|
12216
|
+
uDetailStrength: { value: this.rp("detailStrength") },
|
|
11830
12217
|
uFresnelPower: { value: FANCY_LOOK.fresnelPower },
|
|
11831
12218
|
uScale: { value: new Vector3(1, 1, 1) },
|
|
11832
12219
|
uWaterCenter: { value: new Vector3() },
|
|
@@ -11847,8 +12234,8 @@ var Water3D = class Water3D extends Node3D {
|
|
|
11847
12234
|
const d = this.size[1] ?? 1;
|
|
11848
12235
|
const center = worldTranslationOf(this);
|
|
11849
12236
|
if (u.uTime) u.uTime.value = this.time;
|
|
11850
|
-
if (u.uOpacity) u.uOpacity.value = this.opacity;
|
|
11851
|
-
if (u.uWavesAmplitude) u.uWavesAmplitude.value = this.waveHeight * AMPLITUDE_PER_WAVE_HEIGHT;
|
|
12237
|
+
if (u.uOpacity) u.uOpacity.value = this.rp("opacity");
|
|
12238
|
+
if (u.uWavesAmplitude) u.uWavesAmplitude.value = this.rp("waveHeight") * AMPLITUDE_PER_WAVE_HEIGHT;
|
|
11852
12239
|
(u.uScale?.value)?.set(w / 2, d / 2, d / 2);
|
|
11853
12240
|
(u.uWaterCenter?.value)?.set(center.x, center.y, center.z);
|
|
11854
12241
|
const palette = this.resolvePalette();
|
|
@@ -11857,9 +12244,19 @@ var Water3D = class Water3D extends Node3D {
|
|
|
11857
12244
|
(u.uPeakColor?.value)?.copy(palette.peak);
|
|
11858
12245
|
(u.uSunDirection?.value)?.set(this.sunDirection[0] ?? 0, this.sunDirection[1] ?? 1, this.sunDirection[2] ?? 0).normalize();
|
|
11859
12246
|
(u.uSunColor?.value)?.set(this.sunColor);
|
|
11860
|
-
if (u.uSunIntensity) u.uSunIntensity.value = this.sunIntensity;
|
|
11861
|
-
if (u.uDetailStrength) u.uDetailStrength.value = this.detailStrength;
|
|
11862
|
-
if (u.uAbsorption) u.uAbsorption.value = this.absorption;
|
|
12247
|
+
if (u.uSunIntensity) u.uSunIntensity.value = this.rp("sunIntensity");
|
|
12248
|
+
if (u.uDetailStrength) u.uDetailStrength.value = this.rp("detailStrength");
|
|
12249
|
+
if (u.uAbsorption) u.uAbsorption.value = this.rp("absorption");
|
|
12250
|
+
if (u.uSwellAmplitude) u.uSwellAmplitude.value = this.rp("swell");
|
|
12251
|
+
if (u.uSwellWavelength) u.uSwellWavelength.value = this.rp("swellWavelength");
|
|
12252
|
+
if (u.uWhitecaps) u.uWhitecaps.value = this.rp("whitecaps");
|
|
12253
|
+
if (u.uCausticsAbove) u.uCausticsAbove.value = this.rp("causticsAbove");
|
|
12254
|
+
const look = this.presetLook();
|
|
12255
|
+
if (u.uFresnelScale) u.uFresnelScale.value = look.fresnelScale;
|
|
12256
|
+
if (u.uReflectivityMax) u.uReflectivityMax.value = look.reflectivityMax;
|
|
12257
|
+
const swellRad = this.swellDirectionDeg * Math.PI / 180;
|
|
12258
|
+
(u.uSwellDir?.value)?.set(Math.sin(swellRad), Math.cos(swellRad));
|
|
12259
|
+
if (u.uWaveEnvelope) u.uWaveEnvelope.value = this.rp("waveHeight") * AMPLITUDE_PER_WAVE_HEIGHT * 1.5 + this.rp("swell") * 1.03;
|
|
11863
12260
|
if (!this.reflection && u.uUseEnvironmentMap) u.uUseEnvironmentMap.value = 0;
|
|
11864
12261
|
if (!this.foam && u.uEnableFoam) u.uEnableFoam.value = 0;
|
|
11865
12262
|
if (!this.refraction && u.uUseRefraction) u.uUseRefraction.value = 0;
|
|
@@ -11887,8 +12284,9 @@ var Water3D = class Water3D extends Node3D {
|
|
|
11887
12284
|
}
|
|
11888
12285
|
/** The fancy three-color ramp; a customized legacy `color` tints it. */
|
|
11889
12286
|
resolvePalette() {
|
|
11890
|
-
const overrides = this.colors;
|
|
11891
|
-
const
|
|
12287
|
+
const overrides = this.rp("colors");
|
|
12288
|
+
const tint = this.rp("color");
|
|
12289
|
+
const legacyTint = tint !== Water3D.props.color?.default ? tint : null;
|
|
11892
12290
|
const surface = overrides.surface ?? legacyTint ?? FANCY_COLORS.surface;
|
|
11893
12291
|
paletteScratch.surface.set(surface);
|
|
11894
12292
|
if (overrides.trough) paletteScratch.trough.set(overrides.trough);
|
|
@@ -11901,22 +12299,22 @@ var Water3D = class Water3D extends Node3D {
|
|
|
11901
12299
|
}
|
|
11902
12300
|
syncSimple(mesh) {
|
|
11903
12301
|
const mat = mesh.material;
|
|
11904
|
-
mat.opacity = this.opacity;
|
|
12302
|
+
mat.opacity = this.rp("opacity");
|
|
11905
12303
|
const u = mat.uniforms;
|
|
11906
12304
|
const w = this.size[0] ?? 1;
|
|
11907
12305
|
const d = this.size[1] ?? 1;
|
|
11908
12306
|
const center = worldTranslationOf(this, this._scratchA);
|
|
11909
12307
|
if (u.uTime) u.uTime.value = this.time;
|
|
11910
|
-
if (u.uOpacity) u.uOpacity.value = this.opacity;
|
|
11911
|
-
(u.uSurfaceColor?.value)?.set(this.color).lerp(WHITE, .12);
|
|
11912
|
-
(u.uColor?.value)?.set(this.color).lerp(BLACK, .4);
|
|
11913
|
-
(u.uSkyColor?.value)?.set(this.color).lerp(SKY_PALE, .82);
|
|
12308
|
+
if (u.uOpacity) u.uOpacity.value = this.rp("opacity");
|
|
12309
|
+
(u.uSurfaceColor?.value)?.set(this.rp("color")).lerp(WHITE, .12);
|
|
12310
|
+
(u.uColor?.value)?.set(this.rp("color")).lerp(BLACK, .4);
|
|
12311
|
+
(u.uSkyColor?.value)?.set(this.rp("color")).lerp(SKY_PALE, .82);
|
|
11914
12312
|
(u.uScale?.value)?.set(w / 2, d / 2, d / 2);
|
|
11915
12313
|
(u.uWaterCenter?.value)?.set(center.x, center.y, center.z);
|
|
11916
12314
|
(u.uSunDirection?.value)?.set(this.sunDirection[0] ?? 0, this.sunDirection[1] ?? 1, this.sunDirection[2] ?? 0).normalize();
|
|
11917
12315
|
(u.uSunColor?.value)?.set(this.sunColor);
|
|
11918
|
-
if (u.uSunIntensity) u.uSunIntensity.value = this.sunIntensity;
|
|
11919
|
-
if (u.uDetailStrength) u.uDetailStrength.value = this.detailStrength;
|
|
12316
|
+
if (u.uSunIntensity) u.uSunIntensity.value = this.rp("sunIntensity");
|
|
12317
|
+
if (u.uDetailStrength) u.uDetailStrength.value = this.rp("detailStrength");
|
|
11920
12318
|
if (u.uSplashFoam) u.uSplashFoam.value = this.splash ? 1 : 0;
|
|
11921
12319
|
const uRip = u.uRipples?.value;
|
|
11922
12320
|
const uFoam = u.uRippleFoam?.value;
|
|
@@ -11930,7 +12328,7 @@ var Water3D = class Water3D extends Node3D {
|
|
|
11930
12328
|
const pos = geo.getAttribute("position");
|
|
11931
12329
|
const norm = geo.getAttribute("normal");
|
|
11932
12330
|
const t = this.time;
|
|
11933
|
-
const wh = this.waveHeight;
|
|
12331
|
+
const wh = this.rp("waveHeight");
|
|
11934
12332
|
const cx = center.x;
|
|
11935
12333
|
const cz = center.z;
|
|
11936
12334
|
const ripples = this._ripples;
|
|
@@ -12014,9 +12412,9 @@ var Water3D = class Water3D extends Node3D {
|
|
|
12014
12412
|
/** Base wave height at world (x, z) — the CPU twin of the active shader.
|
|
12015
12413
|
* Ripples are excluded on purpose: a splash must not re-trigger itself. */
|
|
12016
12414
|
waveOffsetAt(x, z, center) {
|
|
12017
|
-
if (this.quality === "simple") return simpleWaveHeight(x - center.x, z - center.z, this.time, this.waveHeight);
|
|
12415
|
+
if (this.quality === "simple") return simpleWaveHeight(x - center.x, z - center.z, this.time, this.rp("waveHeight"));
|
|
12018
12416
|
return waveElevation(x, z, this.time, {
|
|
12019
|
-
amplitude: this.waveHeight * AMPLITUDE_PER_WAVE_HEIGHT,
|
|
12417
|
+
amplitude: this.rp("waveHeight") * AMPLITUDE_PER_WAVE_HEIGHT,
|
|
12020
12418
|
frequency: FANCY_WAVE.frequency,
|
|
12021
12419
|
persistence: FANCY_WAVE.persistence,
|
|
12022
12420
|
lacunarity: FANCY_WAVE.lacunarity,
|
|
@@ -12136,4 +12534,4 @@ function registerNodes3D() {
|
|
|
12136
12534
|
registerNode(CharacterBody3D);
|
|
12137
12535
|
}
|
|
12138
12536
|
//#endregion
|
|
12139
|
-
export {
|
|
12537
|
+
export { Joint3D as A, keyboardIntensity as B, BoneLookAt3D as C, DEFAULT_TERRAIN_TEXTURE_BASE as D, Terrain3D as E, StaticBody3D as F, rigPose as H, Node3D as I, validateCollider3D as L, CharacterBody3D as M, PhysicsBody3D as N, TERRAIN_THEMES as O, RigidBody3D as P, QUARTER_PITCH as R, Camera3D as S, Billboard3D as T, movementState as V, DENSITY_PRESETS as _, VOXEL_PALETTE as a, FLOWER_VARIETIES as b, Trail3D as c, LoftMesh3D as d, DirectionalLight3D as f, Foliage3D as g, MeshInstance3D as h, WATER_MAX_RIPPLES as i, Area3D as j, terrainThemeLayers as k, Particles3D as l, InstancedMesh3D as m, Water3D as n, VoxelGrid3D as o, OmniLight3D as p, createCausticsQuad as r, Tree3D as s, registerNodes3D as t, ModelInstance3D as u, Flowers3D as v, BoneAttachment3D as w, CharacterController3D as x, resolveFlowerDensity as y, cameraRelative as z };
|