@zephyr3d/scene 0.9.26 → 0.9.27
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/animation/animationset.js +92 -30
- package/dist/animation/animationset.js.map +1 -1
- package/dist/animation/joint_dynamics/convex_collider.js +320 -0
- package/dist/animation/joint_dynamics/convex_collider.js.map +1 -0
- package/dist/animation/skeleton.js +21 -1
- package/dist/animation/skeleton.js.map +1 -1
- package/dist/asset/model.js +6 -2
- package/dist/asset/model.js.map +1 -1
- package/dist/camera/camera.js +75 -23
- package/dist/camera/camera.js.map +1 -1
- package/dist/index.d.ts +4764 -3600
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/material/hairstrand.js +235 -235
- package/dist/material/hairstrand.js.map +1 -1
- package/dist/material/material.js +296 -296
- package/dist/material/material.js.map +1 -1
- package/dist/material/mixins/lit.js +33 -1
- package/dist/material/mixins/lit.js.map +1 -1
- package/dist/material/shader/helper.js +404 -3
- package/dist/material/shader/helper.js.map +1 -1
- package/dist/material/water.js +2057 -72
- package/dist/material/water.js.map +1 -1
- package/dist/posteffect/motionblur.js +663 -58
- package/dist/posteffect/motionblur.js.map +1 -1
- package/dist/posteffect/posteffect.js +12 -1
- package/dist/posteffect/posteffect.js.map +1 -1
- package/dist/posteffect/sao.js +46 -44
- package/dist/posteffect/sao.js.map +1 -1
- package/dist/posteffect/sss.js +30 -2
- package/dist/posteffect/sss.js.map +1 -1
- package/dist/render/abuffer_oit.js +37 -37
- package/dist/render/abuffer_oit.js.map +1 -1
- package/dist/render/clipmap.js +156 -5
- package/dist/render/clipmap.js.map +1 -1
- package/dist/render/cull_visitor.js +1 -0
- package/dist/render/cull_visitor.js.map +1 -1
- package/dist/render/dualdepthpeeling_oit.js +49 -49
- package/dist/render/dualdepthpeeling_oit.js.map +1 -1
- package/dist/render/fbm_wavegenerator.js +3 -3
- package/dist/render/fbm_wavegenerator.js.map +1 -1
- package/dist/render/fft_wavegenerator.js +57 -15
- package/dist/render/fft_wavegenerator.js.map +1 -1
- package/dist/render/gerstner_wavegenerator.js +127 -20
- package/dist/render/gerstner_wavegenerator.js.map +1 -1
- package/dist/render/hzb.js +80 -22
- package/dist/render/hzb.js.map +1 -1
- package/dist/render/lightpass.js +6 -3
- package/dist/render/lightpass.js.map +1 -1
- package/dist/render/oit.js +11 -11
- package/dist/render/oit.js.map +1 -1
- package/dist/render/render_queue.js +36 -0
- package/dist/render/render_queue.js.map +1 -1
- package/dist/render/renderer.js +4 -0
- package/dist/render/renderer.js.map +1 -1
- package/dist/render/rendergraph/blackboard.js +1 -0
- package/dist/render/rendergraph/blackboard.js.map +1 -1
- package/dist/render/rendergraph/forward_plus_builder.js +318 -9
- package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
- package/dist/render/rendergraph/frame_resource_requirements.js +1 -0
- package/dist/render/rendergraph/frame_resource_requirements.js.map +1 -1
- package/dist/render/rendergraph/history_resources.js +8 -1
- package/dist/render/rendergraph/history_resources.js.map +1 -1
- package/dist/render/underwater.js +624 -0
- package/dist/render/underwater.js.map +1 -0
- package/dist/render/water_caustics.js +1380 -0
- package/dist/render/water_caustics.js.map +1 -0
- package/dist/render/weightedblended_oit.js +33 -33
- package/dist/render/weightedblended_oit.js.map +1 -1
- package/dist/scene/water.js +540 -4
- package/dist/scene/water.js.map +1 -1
- package/dist/shaders/water.js +22 -19
- package/dist/shaders/water.js.map +1 -1
- package/dist/shaders/water_medium.js +56 -0
- package/dist/shaders/water_medium.js.map +1 -0
- package/dist/shadow/shadow_region.js +49 -49
- package/dist/shadow/shadow_region.js.map +1 -1
- package/dist/utility/serialization/manager.js +3 -1
- package/dist/utility/serialization/manager.js.map +1 -1
- package/dist/utility/serialization/scene/animation.js +31 -2
- package/dist/utility/serialization/scene/animation.js.map +1 -1
- package/dist/utility/serialization/scene/camera.js +53 -25
- package/dist/utility/serialization/scene/camera.js.map +1 -1
- package/dist/utility/serialization/scene/light.js.map +1 -1
- package/dist/utility/serialization/scene/water.js +1101 -21
- package/dist/utility/serialization/scene/water.js.map +1 -1
- package/dist/utility/shprojector.js +87 -87
- package/dist/utility/shprojector.js.map +1 -1
- package/package.json +1 -1
- package/dist/render/rendergraph/frame_graph_context.js +0 -41
- package/dist/render/rendergraph/frame_graph_context.js.map +0 -1
- package/dist/shaders/ssgi.js +0 -63
- package/dist/shaders/ssgi.js.map +0 -1
- package/dist/shaders/ssgi_reprojection.js +0 -118
- package/dist/shaders/ssgi_reprojection.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Vector2 } from '@zephyr3d/base';
|
|
1
|
+
import { Vector2, Vector3 } from '@zephyr3d/base';
|
|
2
2
|
import '../../../scene/scene.js';
|
|
3
|
-
import '../../../values.js';
|
|
3
|
+
import { MAX_GERSTNER_WAVE_COUNT } from '../../../values.js';
|
|
4
4
|
import '../../../render/render_queue.js';
|
|
5
5
|
import '../../../render/primitive.js';
|
|
6
6
|
import '@zephyr3d/device';
|
|
@@ -32,6 +32,7 @@ import '../../../render/clipmap.js';
|
|
|
32
32
|
import '../../../render/envlight.js';
|
|
33
33
|
import '../../../render/dualdepthpeeling_oit.js';
|
|
34
34
|
import { FFTWaveGenerator } from '../../../render/fft_wavegenerator.js';
|
|
35
|
+
import { GerstnerWaveGenerator } from '../../../render/gerstner_wavegenerator.js';
|
|
35
36
|
import { FBMWaveGenerator } from '../../../render/fbm_wavegenerator.js';
|
|
36
37
|
import '../../../render/rendergraph/scene_render_context.js';
|
|
37
38
|
import { GraphNode } from '../../../scene/graph_node.js';
|
|
@@ -48,6 +49,7 @@ import '../../../scene/batchgroup.js';
|
|
|
48
49
|
import '../../../scene/terrain-cm/terrain-cm.js';
|
|
49
50
|
import '../../../scene/terrain-cm/grass.js';
|
|
50
51
|
import '../../../scene/raycast_visitor.js';
|
|
52
|
+
import { WATER_DEBUG_OUTPUTS, DEFAULT_SCATTER_ANISOTROPY } from '../../../material/water.js';
|
|
51
53
|
|
|
52
54
|
/** @internal */ function getFBMWaveGeneratorClass() {
|
|
53
55
|
return {
|
|
@@ -278,6 +280,345 @@ import '../../../scene/raycast_visitor.js';
|
|
|
278
280
|
}
|
|
279
281
|
};
|
|
280
282
|
}
|
|
283
|
+
/** @internal */ function getGerstnerWaveGeneratorClass() {
|
|
284
|
+
return {
|
|
285
|
+
ctor: GerstnerWaveGenerator,
|
|
286
|
+
name: 'GerstnerWaveGenerator',
|
|
287
|
+
getProps () {
|
|
288
|
+
return defineProps([
|
|
289
|
+
{
|
|
290
|
+
name: 'NumWaves',
|
|
291
|
+
description: 'Number of independent Gerstner waves summed to form the surface',
|
|
292
|
+
type: 'int',
|
|
293
|
+
options: {
|
|
294
|
+
minValue: 1,
|
|
295
|
+
maxValue: MAX_GERSTNER_WAVE_COUNT
|
|
296
|
+
},
|
|
297
|
+
get (value) {
|
|
298
|
+
value.num[0] = this.numWaves;
|
|
299
|
+
},
|
|
300
|
+
set (value) {
|
|
301
|
+
this.numWaves = value.num[0];
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
name: 'Waves',
|
|
306
|
+
description: 'Per-wave parameters, one entry per wave in NumWaves order',
|
|
307
|
+
type: 'object_array',
|
|
308
|
+
options: {
|
|
309
|
+
objectTypes: [
|
|
310
|
+
GerstnerWave
|
|
311
|
+
]
|
|
312
|
+
},
|
|
313
|
+
get (value) {
|
|
314
|
+
value.object = [];
|
|
315
|
+
for(let i = 0; i < this.numWaves; i++){
|
|
316
|
+
const wave = new GerstnerWave();
|
|
317
|
+
wave.bind(this, i);
|
|
318
|
+
value.object.push(wave);
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
set (value) {
|
|
322
|
+
const waves = value.object;
|
|
323
|
+
// The wave count is ground truth for how many slots the shader
|
|
324
|
+
// reads. NumWaves and Waves are applied concurrently during
|
|
325
|
+
// deserialization, so this setter must leave the generator in the
|
|
326
|
+
// state this array implies regardless of which one runs first.
|
|
327
|
+
this.numWaves = waves.length;
|
|
328
|
+
for(let i = 0; i < waves.length; i++){
|
|
329
|
+
waves[i].applyTo(this, i);
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
add (value, index) {
|
|
333
|
+
const wave = value?.object?.[0];
|
|
334
|
+
const insertAt = index ?? this.numWaves;
|
|
335
|
+
this.insertWave(insertAt);
|
|
336
|
+
wave?.applyTo(this, insertAt);
|
|
337
|
+
},
|
|
338
|
+
delete (index) {
|
|
339
|
+
this.deleteWave(index);
|
|
340
|
+
}
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
name: 'FoamWidth',
|
|
344
|
+
description: 'Width of foam bands generated on the wave crests',
|
|
345
|
+
type: 'float',
|
|
346
|
+
default: 1.2,
|
|
347
|
+
options: {
|
|
348
|
+
animatable: true,
|
|
349
|
+
minValue: 0,
|
|
350
|
+
maxValue: 10
|
|
351
|
+
},
|
|
352
|
+
get (value) {
|
|
353
|
+
value.num[0] = this.foamWidth;
|
|
354
|
+
},
|
|
355
|
+
set (value) {
|
|
356
|
+
this.foamWidth = value.num[0];
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
name: 'FoamContrast',
|
|
361
|
+
description: 'Contrast of the foam pattern on Gerstner waves',
|
|
362
|
+
type: 'float',
|
|
363
|
+
default: 7.2,
|
|
364
|
+
options: {
|
|
365
|
+
animatable: true,
|
|
366
|
+
minValue: 0,
|
|
367
|
+
maxValue: 10
|
|
368
|
+
},
|
|
369
|
+
get (value) {
|
|
370
|
+
value.num[0] = this.foamContrast;
|
|
371
|
+
},
|
|
372
|
+
set (value) {
|
|
373
|
+
this.foamContrast = value.num[0];
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
]);
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* A single Gerstner wave, as the editor sees one entry of the
|
|
382
|
+
* `Waves` object array on a {@link GerstnerWaveGenerator}.
|
|
383
|
+
*
|
|
384
|
+
* It behaves as a live view while it is bound: the field setters write the new
|
|
385
|
+
* value straight through to the generator's wave buffer, which is what makes an
|
|
386
|
+
* edit in the property panel take effect on the water immediately. Without that
|
|
387
|
+
* the editor would only touch this object's own fields and the surface would
|
|
388
|
+
* keep the previous wave until something else bumped the generator's version.
|
|
389
|
+
*
|
|
390
|
+
* The binding is transient and scoped to one editor session: `_owner` and
|
|
391
|
+
* `_index` are set when the `Waves` getter builds the entry, and the editor
|
|
392
|
+
* rebuilds the whole array from that getter after every add/delete. A copy that
|
|
393
|
+
* survives a list mutation is never reused, so the cached index cannot drift
|
|
394
|
+
* onto a different wave - the same reason it is safe to write through with it.
|
|
395
|
+
*/ class GerstnerWave {
|
|
396
|
+
_owner;
|
|
397
|
+
_index;
|
|
398
|
+
_direction;
|
|
399
|
+
_steepness;
|
|
400
|
+
_amplitude;
|
|
401
|
+
_length;
|
|
402
|
+
_omni;
|
|
403
|
+
_originX;
|
|
404
|
+
_originZ;
|
|
405
|
+
constructor(){
|
|
406
|
+
this._owner = null;
|
|
407
|
+
this._index = -1;
|
|
408
|
+
this._direction = 0;
|
|
409
|
+
this._steepness = 0;
|
|
410
|
+
this._amplitude = 0;
|
|
411
|
+
this._length = 1;
|
|
412
|
+
this._omni = false;
|
|
413
|
+
this._originX = 0;
|
|
414
|
+
this._originZ = 0;
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Binds this entry to a slot of `owner`, so the field setters write through
|
|
418
|
+
* to the generator. Called by the `Waves` getter and by `add`; the index is
|
|
419
|
+
* the slot the entry currently represents.
|
|
420
|
+
* @internal
|
|
421
|
+
*/ bind(owner, index) {
|
|
422
|
+
this._owner = owner;
|
|
423
|
+
this._index = index;
|
|
424
|
+
this.loadFromOwner(owner, index);
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Copies the values in slot `index` of `owner` into this object, refreshing
|
|
428
|
+
* the cached fields without writing back.
|
|
429
|
+
* @internal
|
|
430
|
+
*/ loadFromOwner(owner, index) {
|
|
431
|
+
this._direction = owner.getWaveDirection(index);
|
|
432
|
+
this._steepness = owner.getWaveSteepness(index);
|
|
433
|
+
this._amplitude = owner.getWaveAmplitude(index);
|
|
434
|
+
this._length = owner.getWaveLength(index);
|
|
435
|
+
this._omni = owner.isOmniWave(index);
|
|
436
|
+
this._originX = owner.getOriginX(index);
|
|
437
|
+
this._originZ = owner.getOriginZ(index);
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Writes this object's values into slot `index` of `owner`, unconditionally.
|
|
441
|
+
*
|
|
442
|
+
* Used by the `Waves` setter for a serialised-in array, whose entries were
|
|
443
|
+
* constructed without an owner, and by `add` for a freshly created one. It is
|
|
444
|
+
* distinct from the write-through in the field setters, which fire on each
|
|
445
|
+
* individual edit.
|
|
446
|
+
* @internal
|
|
447
|
+
*/ applyTo(owner, index) {
|
|
448
|
+
owner.setWaveDirection(index, this._direction);
|
|
449
|
+
owner.setWaveSteepness(index, this._steepness);
|
|
450
|
+
owner.setWaveAmplitude(index, this._amplitude);
|
|
451
|
+
owner.setWaveLength(index, this._length);
|
|
452
|
+
owner.setOmniWave(index, this._omni);
|
|
453
|
+
owner.setOrigin(index, this._originX, this._originZ);
|
|
454
|
+
this._owner = owner;
|
|
455
|
+
this._index = index;
|
|
456
|
+
}
|
|
457
|
+
/** @internal */ writethrough(setter, val) {
|
|
458
|
+
const owner = this._owner;
|
|
459
|
+
if (owner) {
|
|
460
|
+
setter(owner, this._index, val);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
/** Gets the wave direction angle in radians. */ get direction() {
|
|
464
|
+
return this._direction;
|
|
465
|
+
}
|
|
466
|
+
set direction(val) {
|
|
467
|
+
this._direction = val;
|
|
468
|
+
this.writethrough((o, i, v)=>o.setWaveDirection(i, v), val);
|
|
469
|
+
}
|
|
470
|
+
/** Gets the wave steepness. */ get steepness() {
|
|
471
|
+
return this._steepness;
|
|
472
|
+
}
|
|
473
|
+
set steepness(val) {
|
|
474
|
+
this._steepness = val;
|
|
475
|
+
this.writethrough((o, i, v)=>o.setWaveSteepness(i, v), val);
|
|
476
|
+
}
|
|
477
|
+
/** Gets the wave amplitude. */ get amplitude() {
|
|
478
|
+
return this._amplitude;
|
|
479
|
+
}
|
|
480
|
+
set amplitude(val) {
|
|
481
|
+
this._amplitude = val;
|
|
482
|
+
this.writethrough((o, i, v)=>o.setWaveAmplitude(i, v), val);
|
|
483
|
+
}
|
|
484
|
+
/** Gets the wave length in meters. */ get length() {
|
|
485
|
+
return this._length;
|
|
486
|
+
}
|
|
487
|
+
set length(val) {
|
|
488
|
+
this._length = val;
|
|
489
|
+
this.writethrough((o, i, v)=>o.setWaveLength(i, v), val);
|
|
490
|
+
}
|
|
491
|
+
/** Gets whether the wave is omni-directional. */ get omni() {
|
|
492
|
+
return this._omni;
|
|
493
|
+
}
|
|
494
|
+
set omni(val) {
|
|
495
|
+
this._omni = val;
|
|
496
|
+
if (this._owner) {
|
|
497
|
+
this._owner.setOmniWave(this._index, val);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
/** Gets the origin X of an omni-directional wave. */ get originX() {
|
|
501
|
+
return this._originX;
|
|
502
|
+
}
|
|
503
|
+
set originX(val) {
|
|
504
|
+
this._originX = val;
|
|
505
|
+
if (this._owner) {
|
|
506
|
+
this._owner.setOrigin(this._index, val, this._originZ);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
/** Gets the origin Z of an omni-directional wave. */ get originZ() {
|
|
510
|
+
return this._originZ;
|
|
511
|
+
}
|
|
512
|
+
set originZ(val) {
|
|
513
|
+
this._originZ = val;
|
|
514
|
+
if (this._owner) {
|
|
515
|
+
this._owner.setOrigin(this._index, this._originX, val);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
/** @internal */ function getGerstnerWaveClass() {
|
|
520
|
+
return {
|
|
521
|
+
ctor: GerstnerWave,
|
|
522
|
+
name: 'GerstnerWave',
|
|
523
|
+
getProps () {
|
|
524
|
+
return defineProps([
|
|
525
|
+
{
|
|
526
|
+
name: 'Direction',
|
|
527
|
+
description: 'Wave direction angle in radians',
|
|
528
|
+
type: 'float',
|
|
529
|
+
options: {
|
|
530
|
+
animatable: true,
|
|
531
|
+
minValue: -3.14,
|
|
532
|
+
maxValue: 3.14
|
|
533
|
+
},
|
|
534
|
+
get (value) {
|
|
535
|
+
value.num[0] = this.direction;
|
|
536
|
+
},
|
|
537
|
+
set (value) {
|
|
538
|
+
this.direction = value.num[0];
|
|
539
|
+
}
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
name: 'Steepness',
|
|
543
|
+
description: 'Wave steepness. The sum of steepness across waves sets how sharply crests fold',
|
|
544
|
+
type: 'float',
|
|
545
|
+
options: {
|
|
546
|
+
animatable: true,
|
|
547
|
+
minValue: 0,
|
|
548
|
+
maxValue: 2
|
|
549
|
+
},
|
|
550
|
+
get (value) {
|
|
551
|
+
value.num[0] = this.steepness;
|
|
552
|
+
},
|
|
553
|
+
set (value) {
|
|
554
|
+
this.steepness = value.num[0];
|
|
555
|
+
}
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
name: 'Amplitude',
|
|
559
|
+
description: 'Wave height amplitude',
|
|
560
|
+
type: 'float',
|
|
561
|
+
options: {
|
|
562
|
+
animatable: true,
|
|
563
|
+
minValue: 0,
|
|
564
|
+
maxValue: 5
|
|
565
|
+
},
|
|
566
|
+
get (value) {
|
|
567
|
+
value.num[0] = this.amplitude;
|
|
568
|
+
},
|
|
569
|
+
set (value) {
|
|
570
|
+
this.amplitude = value.num[0];
|
|
571
|
+
}
|
|
572
|
+
},
|
|
573
|
+
{
|
|
574
|
+
name: 'Length',
|
|
575
|
+
description: 'Wave length in meters',
|
|
576
|
+
type: 'float',
|
|
577
|
+
options: {
|
|
578
|
+
animatable: true,
|
|
579
|
+
minValue: 0,
|
|
580
|
+
maxValue: 100
|
|
581
|
+
},
|
|
582
|
+
get (value) {
|
|
583
|
+
value.num[0] = this.length;
|
|
584
|
+
},
|
|
585
|
+
set (value) {
|
|
586
|
+
this.length = value.num[0];
|
|
587
|
+
}
|
|
588
|
+
},
|
|
589
|
+
{
|
|
590
|
+
name: 'Omni',
|
|
591
|
+
description: 'If true, radiates outward from an origin rather than travelling in one direction',
|
|
592
|
+
type: 'bool',
|
|
593
|
+
get (value) {
|
|
594
|
+
value.bool[0] = this.omni;
|
|
595
|
+
},
|
|
596
|
+
set (value) {
|
|
597
|
+
this.omni = value.bool[0];
|
|
598
|
+
}
|
|
599
|
+
},
|
|
600
|
+
{
|
|
601
|
+
name: 'Origin',
|
|
602
|
+
description: 'Origin of an omni-directional wave, ignored by directional waves',
|
|
603
|
+
type: 'vec2',
|
|
604
|
+
options: {
|
|
605
|
+
animatable: true,
|
|
606
|
+
minValue: -1e3,
|
|
607
|
+
maxValue: 1000
|
|
608
|
+
},
|
|
609
|
+
get (value) {
|
|
610
|
+
value.num[0] = this.originX;
|
|
611
|
+
value.num[1] = this.originZ;
|
|
612
|
+
},
|
|
613
|
+
set (value) {
|
|
614
|
+
this.originX = value.num[0];
|
|
615
|
+
this.originZ = value.num[1];
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
]);
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
}
|
|
281
622
|
/** @internal */ function getWaterClass(manager) {
|
|
282
623
|
return {
|
|
283
624
|
ctor: Water,
|
|
@@ -300,7 +641,8 @@ import '../../../scene/raycast_visitor.js';
|
|
|
300
641
|
options: {
|
|
301
642
|
objectTypes: [
|
|
302
643
|
FFTWaveGenerator,
|
|
303
|
-
FBMWaveGenerator
|
|
644
|
+
FBMWaveGenerator,
|
|
645
|
+
GerstnerWaveGenerator
|
|
304
646
|
]
|
|
305
647
|
},
|
|
306
648
|
isNullable () {
|
|
@@ -363,53 +705,791 @@ import '../../../scene/raycast_visitor.js';
|
|
|
363
705
|
}
|
|
364
706
|
},
|
|
365
707
|
{
|
|
366
|
-
name: '
|
|
367
|
-
description: '
|
|
708
|
+
name: 'Infinite',
|
|
709
|
+
description: 'Draw the surface as an unbounded ocean reaching the horizon instead of a body of water ending at the node extent. Reaches the horizon without enlarging the camera far plane, so near-scene depth precision is unaffected. Leave off for ponds, lakes and pools, which have an edge.',
|
|
710
|
+
type: 'bool',
|
|
711
|
+
default: false,
|
|
712
|
+
get (value) {
|
|
713
|
+
value.bool[0] = this.infinite;
|
|
714
|
+
},
|
|
715
|
+
set (value) {
|
|
716
|
+
this.infinite = value.bool[0];
|
|
717
|
+
}
|
|
718
|
+
},
|
|
719
|
+
{
|
|
720
|
+
name: 'ViewDistance',
|
|
721
|
+
description: 'How far the surface is built out from the camera, in meters, or 0 to derive it from the true horizon distance for the camera height. Keep the sky AerialPerspectiveDistance at least this large, or the far water stops converging towards the sky colour and the hard band comes back.',
|
|
368
722
|
type: 'float',
|
|
369
|
-
default:
|
|
723
|
+
default: 0,
|
|
724
|
+
options: {
|
|
725
|
+
minValue: 0,
|
|
726
|
+
maxValue: 100000
|
|
727
|
+
},
|
|
728
|
+
isHidden () {
|
|
729
|
+
return !this.infinite;
|
|
730
|
+
},
|
|
731
|
+
get (value) {
|
|
732
|
+
value.num[0] = this.viewDistance;
|
|
733
|
+
},
|
|
734
|
+
set (value) {
|
|
735
|
+
this.viewDistance = value.num[0];
|
|
736
|
+
}
|
|
737
|
+
},
|
|
738
|
+
{
|
|
739
|
+
name: 'CausticsEnabled',
|
|
740
|
+
description: 'Whether the water projects caustics onto the geometry below it',
|
|
741
|
+
type: 'bool',
|
|
742
|
+
default: true,
|
|
743
|
+
get (value) {
|
|
744
|
+
value.bool[0] = this.causticsEnabled;
|
|
745
|
+
},
|
|
746
|
+
set (value) {
|
|
747
|
+
this.causticsEnabled = value.bool[0];
|
|
748
|
+
}
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
name: 'CausticsIntensity',
|
|
752
|
+
description: 'Strength of the caustic contrast',
|
|
753
|
+
type: 'float',
|
|
754
|
+
default: 1,
|
|
370
755
|
options: {
|
|
371
756
|
animatable: true,
|
|
372
757
|
minValue: 0,
|
|
758
|
+
maxValue: 5
|
|
759
|
+
},
|
|
760
|
+
isHidden () {
|
|
761
|
+
return !this.causticsEnabled;
|
|
762
|
+
},
|
|
763
|
+
get (value) {
|
|
764
|
+
value.num[0] = this.causticsIntensity;
|
|
765
|
+
},
|
|
766
|
+
set (value) {
|
|
767
|
+
this.causticsIntensity = value.num[0];
|
|
768
|
+
}
|
|
769
|
+
},
|
|
770
|
+
{
|
|
771
|
+
name: 'CausticsDepth',
|
|
772
|
+
description: 'Depth in meters below the surface where the caustics are in focus',
|
|
773
|
+
type: 'float',
|
|
774
|
+
default: 4,
|
|
775
|
+
options: {
|
|
776
|
+
animatable: true,
|
|
777
|
+
minValue: 0.01,
|
|
373
778
|
maxValue: 100
|
|
374
779
|
},
|
|
780
|
+
isHidden () {
|
|
781
|
+
return !this.causticsEnabled;
|
|
782
|
+
},
|
|
375
783
|
get (value) {
|
|
376
|
-
value.num[0] = this.
|
|
784
|
+
value.num[0] = this.causticsDepth;
|
|
377
785
|
},
|
|
378
786
|
set (value) {
|
|
379
|
-
this.
|
|
787
|
+
this.causticsDepth = value.num[0];
|
|
788
|
+
}
|
|
789
|
+
},
|
|
790
|
+
{
|
|
791
|
+
name: 'CausticsRange',
|
|
792
|
+
description: 'Furthest distance in meters from the camera the caustic map reaches',
|
|
793
|
+
type: 'float',
|
|
794
|
+
default: 4,
|
|
795
|
+
options: {
|
|
796
|
+
minValue: 1,
|
|
797
|
+
maxValue: 1000
|
|
798
|
+
},
|
|
799
|
+
isHidden () {
|
|
800
|
+
return !this.causticsEnabled;
|
|
801
|
+
},
|
|
802
|
+
get (value) {
|
|
803
|
+
value.num[0] = this.causticsRange;
|
|
804
|
+
},
|
|
805
|
+
set (value) {
|
|
806
|
+
this.causticsRange = value.num[0];
|
|
380
807
|
}
|
|
381
808
|
},
|
|
382
809
|
{
|
|
383
|
-
name: '
|
|
384
|
-
description: '
|
|
810
|
+
name: 'CausticsFadeDistance',
|
|
811
|
+
description: 'Width in meters the caustics fade out over at the edge of the map, or 0 to derive it from the range',
|
|
385
812
|
type: 'float',
|
|
386
813
|
default: 0,
|
|
814
|
+
options: {
|
|
815
|
+
minValue: 0,
|
|
816
|
+
maxValue: 100
|
|
817
|
+
},
|
|
818
|
+
isHidden () {
|
|
819
|
+
return !this.causticsEnabled;
|
|
820
|
+
},
|
|
821
|
+
get (value) {
|
|
822
|
+
value.num[0] = this.causticsFadeDistance;
|
|
823
|
+
},
|
|
824
|
+
set (value) {
|
|
825
|
+
this.causticsFadeDistance = value.num[0];
|
|
826
|
+
}
|
|
827
|
+
},
|
|
828
|
+
{
|
|
829
|
+
name: 'CausticsSceneDepth',
|
|
830
|
+
description: 'Land caustics on the scene instead of on a plane at CausticsDepth. Reuses the sun shadow cascade, so it costs no extra geometry pass; WebGL2 keeps the plane, which its shadow map format cannot avoid.',
|
|
831
|
+
type: 'bool',
|
|
832
|
+
default: true,
|
|
833
|
+
get (value) {
|
|
834
|
+
value.bool[0] = this.causticsSceneDepth;
|
|
835
|
+
},
|
|
836
|
+
set (value) {
|
|
837
|
+
this.causticsSceneDepth = value.bool[0];
|
|
838
|
+
}
|
|
839
|
+
},
|
|
840
|
+
{
|
|
841
|
+
name: 'CausticsWarp',
|
|
842
|
+
description: 'How strongly caustic map texels are concentrated near the camera; ignored while the map already fits the water within range',
|
|
843
|
+
type: 'float',
|
|
844
|
+
default: 1.5,
|
|
845
|
+
options: {
|
|
846
|
+
minValue: 0,
|
|
847
|
+
maxValue: 8
|
|
848
|
+
},
|
|
849
|
+
isHidden () {
|
|
850
|
+
return !this.causticsEnabled;
|
|
851
|
+
},
|
|
852
|
+
get (value) {
|
|
853
|
+
value.num[0] = this.causticsWarp;
|
|
854
|
+
},
|
|
855
|
+
set (value) {
|
|
856
|
+
this.causticsWarp = value.num[0];
|
|
857
|
+
}
|
|
858
|
+
},
|
|
859
|
+
{
|
|
860
|
+
name: 'UnderwaterEnabled',
|
|
861
|
+
description: 'Whether a camera inside this water sees it from the inside: the medium over the whole scene, the sky replaced by water, and the surface read from below with its Snell window. Atmospheric fog is suppressed while submerged.',
|
|
862
|
+
type: 'bool',
|
|
863
|
+
default: true,
|
|
864
|
+
get (value) {
|
|
865
|
+
value.bool[0] = this.underwaterEnabled;
|
|
866
|
+
},
|
|
867
|
+
set (value) {
|
|
868
|
+
this.underwaterEnabled = value.bool[0];
|
|
869
|
+
}
|
|
870
|
+
},
|
|
871
|
+
{
|
|
872
|
+
name: 'UnderwaterAmbientIntensity',
|
|
873
|
+
description: 'Scale on the downwelling sky light filling the water column. This is what the water fades to in the distance, so it sets how bright the underwater haze reads.',
|
|
874
|
+
type: 'float',
|
|
875
|
+
default: 1,
|
|
387
876
|
options: {
|
|
388
877
|
animatable: true,
|
|
389
878
|
minValue: 0,
|
|
390
|
-
maxValue:
|
|
879
|
+
maxValue: 5
|
|
880
|
+
},
|
|
881
|
+
isHidden () {
|
|
882
|
+
return !this.underwaterEnabled;
|
|
883
|
+
},
|
|
884
|
+
get (value) {
|
|
885
|
+
value.num[0] = this.underwaterAmbientIntensity;
|
|
886
|
+
},
|
|
887
|
+
set (value) {
|
|
888
|
+
this.underwaterAmbientIntensity = value.num[0];
|
|
889
|
+
}
|
|
890
|
+
},
|
|
891
|
+
{
|
|
892
|
+
name: 'UnderwaterGodRays',
|
|
893
|
+
description: 'Whether shafts of sunlight are marched through the water column. Reads the caustic map as the surface transmittance, so the shafts carry the pattern that lands on the sea bed; needs CausticsEnabled.',
|
|
894
|
+
type: 'bool',
|
|
895
|
+
default: true,
|
|
896
|
+
isHidden () {
|
|
897
|
+
return !this.underwaterEnabled;
|
|
391
898
|
},
|
|
392
899
|
get (value) {
|
|
393
|
-
value.
|
|
900
|
+
value.bool[0] = this.underwaterGodRays;
|
|
394
901
|
},
|
|
395
902
|
set (value) {
|
|
396
|
-
this.
|
|
903
|
+
this.underwaterGodRays = value.bool[0];
|
|
397
904
|
}
|
|
398
905
|
},
|
|
399
906
|
{
|
|
400
|
-
name: '
|
|
401
|
-
description: '
|
|
907
|
+
name: 'UnderwaterGodRayIntensity',
|
|
908
|
+
description: 'Strength of the light shafts, 1 for the value the medium implies',
|
|
402
909
|
type: 'float',
|
|
403
|
-
default:
|
|
910
|
+
default: 1,
|
|
404
911
|
options: {
|
|
405
|
-
|
|
406
|
-
|
|
912
|
+
animatable: true,
|
|
913
|
+
minValue: 0,
|
|
914
|
+
maxValue: 5
|
|
915
|
+
},
|
|
916
|
+
isHidden () {
|
|
917
|
+
return !this.underwaterEnabled || !this.underwaterGodRays;
|
|
918
|
+
},
|
|
919
|
+
get (value) {
|
|
920
|
+
value.num[0] = this.underwaterGodRayIntensity;
|
|
921
|
+
},
|
|
922
|
+
set (value) {
|
|
923
|
+
this.underwaterGodRayIntensity = value.num[0];
|
|
924
|
+
}
|
|
925
|
+
},
|
|
926
|
+
{
|
|
927
|
+
name: 'UnderwaterGodRaySteps',
|
|
928
|
+
description: 'Samples taken along each view ray for the light shafts. Raise it when the shafts read as grain rather than as beams.',
|
|
929
|
+
type: 'int',
|
|
930
|
+
default: 24,
|
|
931
|
+
options: {
|
|
932
|
+
minValue: 4,
|
|
933
|
+
maxValue: 96
|
|
934
|
+
},
|
|
935
|
+
isHidden () {
|
|
936
|
+
return !this.underwaterEnabled || !this.underwaterGodRays;
|
|
937
|
+
},
|
|
938
|
+
get (value) {
|
|
939
|
+
value.num[0] = this.underwaterGodRaySteps;
|
|
940
|
+
},
|
|
941
|
+
set (value) {
|
|
942
|
+
this.underwaterGodRaySteps = value.num[0];
|
|
943
|
+
}
|
|
944
|
+
},
|
|
945
|
+
{
|
|
946
|
+
name: 'UnderwaterGodRayShadow',
|
|
947
|
+
description: 'Whether geometry standing in the water breaks the light shafts. The shafts come from the caustic map, which knows only what the surface did to the sunlight, so without this a shaft runs straight through a piling. Costs a shadow map lookup per march step.',
|
|
948
|
+
type: 'bool',
|
|
949
|
+
default: false,
|
|
950
|
+
isHidden () {
|
|
951
|
+
return !this.underwaterEnabled || !this.underwaterGodRays;
|
|
952
|
+
},
|
|
953
|
+
get (value) {
|
|
954
|
+
value.bool[0] = this.underwaterGodRayShadow;
|
|
955
|
+
},
|
|
956
|
+
set (value) {
|
|
957
|
+
this.underwaterGodRayShadow = value.bool[0];
|
|
958
|
+
}
|
|
959
|
+
},
|
|
960
|
+
{
|
|
961
|
+
name: 'UnderwaterHysteresis',
|
|
962
|
+
description: 'Half-width in meters of the dead band around the surface the submerged test uses, so a camera at water level does not flip state every frame',
|
|
963
|
+
type: 'float',
|
|
964
|
+
default: 0.05,
|
|
965
|
+
options: {
|
|
966
|
+
minValue: 0,
|
|
967
|
+
maxValue: 2
|
|
968
|
+
},
|
|
969
|
+
isHidden () {
|
|
970
|
+
return !this.underwaterEnabled;
|
|
971
|
+
},
|
|
972
|
+
get (value) {
|
|
973
|
+
value.num[0] = this.underwaterHysteresis;
|
|
974
|
+
},
|
|
975
|
+
set (value) {
|
|
976
|
+
this.underwaterHysteresis = value.num[0];
|
|
977
|
+
}
|
|
978
|
+
},
|
|
979
|
+
{
|
|
980
|
+
name: 'MediumMode',
|
|
981
|
+
description: 'How the water medium attenuates light: physical coefficients, or the legacy ramp textures',
|
|
982
|
+
type: 'string',
|
|
983
|
+
default: 'physical',
|
|
984
|
+
options: {
|
|
985
|
+
enum: {
|
|
986
|
+
labels: [
|
|
987
|
+
'Physical',
|
|
988
|
+
'Ramp'
|
|
989
|
+
],
|
|
990
|
+
values: [
|
|
991
|
+
'physical',
|
|
992
|
+
'ramp'
|
|
993
|
+
]
|
|
994
|
+
}
|
|
995
|
+
},
|
|
996
|
+
get (value) {
|
|
997
|
+
value.str[0] = this.material.mediumMode;
|
|
998
|
+
},
|
|
999
|
+
set (value) {
|
|
1000
|
+
this.material.mediumMode = value.str[0];
|
|
1001
|
+
}
|
|
1002
|
+
},
|
|
1003
|
+
{
|
|
1004
|
+
name: 'RefractionMode',
|
|
1005
|
+
description: 'How the refracted view sample is located. March walks the refracted ray against the scene depth and samples where it lands, which keeps the sample on the object behind the water; Offset skips the search and displaces the screen UV by the wave normal, which costs no depth fetches but samples the wrong point. Use Offset on hardware that cannot afford the search.',
|
|
1006
|
+
type: 'string',
|
|
1007
|
+
default: 'march',
|
|
1008
|
+
options: {
|
|
1009
|
+
enum: {
|
|
1010
|
+
labels: [
|
|
1011
|
+
'March (accurate)',
|
|
1012
|
+
'Offset (cheap)'
|
|
1013
|
+
],
|
|
1014
|
+
values: [
|
|
1015
|
+
'march',
|
|
1016
|
+
'offset'
|
|
1017
|
+
]
|
|
1018
|
+
}
|
|
1019
|
+
},
|
|
1020
|
+
get (value) {
|
|
1021
|
+
value.str[0] = this.material.refractionMode;
|
|
1022
|
+
},
|
|
1023
|
+
set (value) {
|
|
1024
|
+
this.material.refractionMode = value.str[0];
|
|
1025
|
+
}
|
|
1026
|
+
},
|
|
1027
|
+
{
|
|
1028
|
+
name: 'DebugOutput',
|
|
1029
|
+
description: 'Debugging aid: replaces the water colour with one of the shading terms it is built from, so a broken term can be identified by eye',
|
|
1030
|
+
type: 'string',
|
|
1031
|
+
default: 'none',
|
|
1032
|
+
options: {
|
|
1033
|
+
enum: {
|
|
1034
|
+
labels: WATER_DEBUG_OUTPUTS.map((e)=>e.label),
|
|
1035
|
+
values: WATER_DEBUG_OUTPUTS.map((e)=>e.value)
|
|
1036
|
+
}
|
|
1037
|
+
},
|
|
1038
|
+
get (value) {
|
|
1039
|
+
value.str[0] = this.debugOutput;
|
|
1040
|
+
},
|
|
1041
|
+
set (value) {
|
|
1042
|
+
this.debugOutput = value.str[0];
|
|
1043
|
+
}
|
|
1044
|
+
},
|
|
1045
|
+
{
|
|
1046
|
+
name: 'Absorption',
|
|
1047
|
+
description: 'Absorption coefficient sigma_a of the water medium, per meter, per channel',
|
|
1048
|
+
type: 'rgb',
|
|
1049
|
+
default: [
|
|
1050
|
+
1.0,
|
|
1051
|
+
0.25,
|
|
1052
|
+
0.15
|
|
1053
|
+
],
|
|
1054
|
+
options: {
|
|
1055
|
+
animatable: true,
|
|
1056
|
+
minValue: 0,
|
|
1057
|
+
maxValue: 10
|
|
1058
|
+
},
|
|
1059
|
+
isHidden () {
|
|
1060
|
+
return this.material.mediumMode !== 'physical';
|
|
1061
|
+
},
|
|
1062
|
+
get (value) {
|
|
1063
|
+
value.num[0] = this.material.absorption.x;
|
|
1064
|
+
value.num[1] = this.material.absorption.y;
|
|
1065
|
+
value.num[2] = this.material.absorption.z;
|
|
1066
|
+
},
|
|
1067
|
+
set (value) {
|
|
1068
|
+
this.material.absorption = new Vector3(value.num[0], value.num[1], value.num[2]);
|
|
1069
|
+
}
|
|
1070
|
+
},
|
|
1071
|
+
{
|
|
1072
|
+
name: 'AbsorptionScale',
|
|
1073
|
+
description: 'Scale for the absorption coefficient',
|
|
1074
|
+
type: 'float',
|
|
1075
|
+
default: 1,
|
|
1076
|
+
options: {
|
|
1077
|
+
animatable: true,
|
|
1078
|
+
minValue: 0,
|
|
1079
|
+
maxValue: 10
|
|
1080
|
+
},
|
|
1081
|
+
isHidden () {
|
|
1082
|
+
return this.material.mediumMode !== 'physical';
|
|
1083
|
+
},
|
|
1084
|
+
get (value) {
|
|
1085
|
+
value.num[0] = this.material.absorptionScale;
|
|
1086
|
+
},
|
|
1087
|
+
set (value) {
|
|
1088
|
+
this.material.absorptionScale = value.num[0];
|
|
1089
|
+
}
|
|
1090
|
+
},
|
|
1091
|
+
{
|
|
1092
|
+
name: 'Scattering',
|
|
1093
|
+
description: 'Scattering coefficient sigma_s of the water medium, per meter, per channel',
|
|
1094
|
+
type: 'rgb',
|
|
1095
|
+
default: [
|
|
1096
|
+
0.05,
|
|
1097
|
+
0.12,
|
|
1098
|
+
0.18
|
|
1099
|
+
],
|
|
1100
|
+
options: {
|
|
1101
|
+
animatable: true,
|
|
1102
|
+
minValue: 0,
|
|
1103
|
+
maxValue: 10
|
|
1104
|
+
},
|
|
1105
|
+
isHidden () {
|
|
1106
|
+
return this.material.mediumMode !== 'physical';
|
|
1107
|
+
},
|
|
1108
|
+
get (value) {
|
|
1109
|
+
value.num[0] = this.material.scattering.x;
|
|
1110
|
+
value.num[1] = this.material.scattering.y;
|
|
1111
|
+
value.num[2] = this.material.scattering.z;
|
|
1112
|
+
},
|
|
1113
|
+
set (value) {
|
|
1114
|
+
this.material.scattering = new Vector3(value.num[0], value.num[1], value.num[2]);
|
|
1115
|
+
}
|
|
1116
|
+
},
|
|
1117
|
+
{
|
|
1118
|
+
name: 'ScatteringScale',
|
|
1119
|
+
description: 'Scale for the scattering coefficient',
|
|
1120
|
+
type: 'float',
|
|
1121
|
+
default: 1,
|
|
1122
|
+
options: {
|
|
1123
|
+
animatable: true,
|
|
1124
|
+
minValue: 0,
|
|
1125
|
+
maxValue: 10
|
|
1126
|
+
},
|
|
1127
|
+
isHidden () {
|
|
1128
|
+
return this.material.mediumMode !== 'physical';
|
|
1129
|
+
},
|
|
1130
|
+
get (value) {
|
|
1131
|
+
value.num[0] = this.material.scatteringScale;
|
|
1132
|
+
},
|
|
1133
|
+
set (value) {
|
|
1134
|
+
this.material.scatteringScale = value.num[0];
|
|
1135
|
+
}
|
|
1136
|
+
},
|
|
1137
|
+
{
|
|
1138
|
+
name: 'DepthScale',
|
|
1139
|
+
description: 'Depth attenuation scale for the water material (ramp medium only)',
|
|
1140
|
+
type: 'float',
|
|
1141
|
+
default: 10,
|
|
1142
|
+
options: {
|
|
1143
|
+
animatable: true,
|
|
1144
|
+
minValue: 0,
|
|
1145
|
+
maxValue: 100
|
|
1146
|
+
},
|
|
1147
|
+
isHidden () {
|
|
1148
|
+
return this.material.mediumMode !== 'ramp';
|
|
1149
|
+
},
|
|
1150
|
+
get (value) {
|
|
1151
|
+
value.num[0] = this.material.depthMulti;
|
|
1152
|
+
},
|
|
1153
|
+
set (value) {
|
|
1154
|
+
this.material.depthMulti = value.num[0];
|
|
1155
|
+
}
|
|
1156
|
+
},
|
|
1157
|
+
{
|
|
1158
|
+
name: 'ReflectionStrength',
|
|
1159
|
+
description: 'Scale on the Fresnel reflectance, 1 for the physical value. Lower it to trade the reflection away and show more of what is beneath the surface.',
|
|
1160
|
+
type: 'float',
|
|
1161
|
+
default: 1,
|
|
1162
|
+
options: {
|
|
1163
|
+
animatable: true,
|
|
1164
|
+
minValue: 0,
|
|
1165
|
+
maxValue: 1
|
|
1166
|
+
},
|
|
1167
|
+
get (value) {
|
|
1168
|
+
value.num[0] = this.material.reflectionStrength;
|
|
1169
|
+
},
|
|
1170
|
+
set (value) {
|
|
1171
|
+
this.material.reflectionStrength = value.num[0];
|
|
1172
|
+
}
|
|
1173
|
+
},
|
|
1174
|
+
{
|
|
1175
|
+
name: 'SubsurfaceIntensity',
|
|
1176
|
+
description: 'Strength of the sunlight scattered forward through a wave crest, which is what makes a backlit crest glow. Grazing views of a low sun show it; looking down at the water does not.',
|
|
1177
|
+
type: 'float',
|
|
1178
|
+
default: 1.5,
|
|
1179
|
+
options: {
|
|
1180
|
+
animatable: true,
|
|
1181
|
+
minValue: 0,
|
|
1182
|
+
maxValue: 10
|
|
1183
|
+
},
|
|
1184
|
+
get (value) {
|
|
1185
|
+
value.num[0] = this.material.subsurfaceIntensity;
|
|
1186
|
+
},
|
|
1187
|
+
set (value) {
|
|
1188
|
+
this.material.subsurfaceIntensity = value.num[0];
|
|
1189
|
+
}
|
|
1190
|
+
},
|
|
1191
|
+
{
|
|
1192
|
+
name: 'SubsurfaceSteepness',
|
|
1193
|
+
description: 'How sharply surface tilt gates the subsurface glow. Higher makes gentle swell glow too; lower restricts it to steep wave flanks.',
|
|
1194
|
+
type: 'float',
|
|
1195
|
+
default: 60,
|
|
1196
|
+
options: {
|
|
1197
|
+
animatable: true,
|
|
1198
|
+
minValue: 0,
|
|
1199
|
+
maxValue: 100
|
|
1200
|
+
},
|
|
1201
|
+
get (value) {
|
|
1202
|
+
value.num[0] = this.material.subsurfaceSteepness;
|
|
1203
|
+
},
|
|
1204
|
+
set (value) {
|
|
1205
|
+
this.material.subsurfaceSteepness = value.num[0];
|
|
1206
|
+
}
|
|
1207
|
+
},
|
|
1208
|
+
{
|
|
1209
|
+
name: 'SunScatteringIntensity',
|
|
1210
|
+
description: 'Strength of the sunlight scattered out of the water column towards the eye, 1 for the value the medium coefficients imply. This is what makes a shadow on the water darken the water itself and a low sun tint it; 0 leaves the body lit by the environment alone.',
|
|
1211
|
+
type: 'float',
|
|
1212
|
+
default: 1,
|
|
1213
|
+
options: {
|
|
1214
|
+
animatable: true,
|
|
1215
|
+
minValue: 0,
|
|
1216
|
+
maxValue: 4
|
|
1217
|
+
},
|
|
1218
|
+
get (value) {
|
|
1219
|
+
value.num[0] = this.material.sunScatteringIntensity;
|
|
1220
|
+
},
|
|
1221
|
+
set (value) {
|
|
1222
|
+
this.material.sunScatteringIntensity = value.num[0];
|
|
1223
|
+
}
|
|
1224
|
+
},
|
|
1225
|
+
{
|
|
1226
|
+
name: 'FoamAmount',
|
|
1227
|
+
description: 'Coverage of the foam on breaking wave crests, mapped from the folding the wave generator reports. 0 disables crest foam. Independent of ShoreFoamAmount.',
|
|
1228
|
+
type: 'float',
|
|
1229
|
+
default: 1,
|
|
1230
|
+
options: {
|
|
1231
|
+
animatable: true,
|
|
1232
|
+
minValue: 0,
|
|
1233
|
+
maxValue: 4
|
|
1234
|
+
},
|
|
1235
|
+
get (value) {
|
|
1236
|
+
value.num[0] = this.material.foamAmount;
|
|
1237
|
+
},
|
|
1238
|
+
set (value) {
|
|
1239
|
+
this.material.foamAmount = value.num[0];
|
|
1240
|
+
}
|
|
1241
|
+
},
|
|
1242
|
+
{
|
|
1243
|
+
name: 'FoamFalloff',
|
|
1244
|
+
description: 'Falloff applied to crest foam coverage. Above 1 pushes light folding towards no foam at all, so only a genuinely broken crest shows - which is what keeps a windy sea from turning uniformly white.',
|
|
1245
|
+
type: 'float',
|
|
1246
|
+
default: 1.5,
|
|
1247
|
+
options: {
|
|
1248
|
+
animatable: true,
|
|
1249
|
+
minValue: 0.01,
|
|
1250
|
+
maxValue: 8
|
|
1251
|
+
},
|
|
1252
|
+
isHidden () {
|
|
1253
|
+
return this.material.foamAmount <= 0;
|
|
1254
|
+
},
|
|
1255
|
+
get (value) {
|
|
1256
|
+
value.num[0] = this.material.foamFalloff;
|
|
1257
|
+
},
|
|
1258
|
+
set (value) {
|
|
1259
|
+
this.material.foamFalloff = value.num[0];
|
|
1260
|
+
}
|
|
1261
|
+
},
|
|
1262
|
+
{
|
|
1263
|
+
name: 'FoamColor',
|
|
1264
|
+
description: 'Diffuse albedo of the foam, shared by the crest foam and the shoreline foam. Slightly off-white and slightly blue - sea foam is water and air, and a pure white one reads as snow.',
|
|
1265
|
+
type: 'rgb',
|
|
1266
|
+
default: [
|
|
1267
|
+
0.92,
|
|
1268
|
+
0.95,
|
|
1269
|
+
0.97
|
|
1270
|
+
],
|
|
1271
|
+
options: {
|
|
1272
|
+
animatable: true,
|
|
1273
|
+
minValue: 0,
|
|
1274
|
+
maxValue: 1
|
|
1275
|
+
},
|
|
1276
|
+
get (value) {
|
|
1277
|
+
value.num[0] = this.material.foamColor.x;
|
|
1278
|
+
value.num[1] = this.material.foamColor.y;
|
|
1279
|
+
value.num[2] = this.material.foamColor.z;
|
|
1280
|
+
},
|
|
1281
|
+
set (value) {
|
|
1282
|
+
this.material.foamColor = new Vector3(value.num[0], value.num[1], value.num[2]);
|
|
1283
|
+
}
|
|
1284
|
+
},
|
|
1285
|
+
{
|
|
1286
|
+
name: 'ShoreFoamAmount',
|
|
1287
|
+
description: 'Coverage of the foam that collects where the water meets a surface - the waterline on a shelving bed, and the collar around a piling or a hull. 0 disables it, which also removes its cost. Independent of the crest foam the wave generator produces. Requires WebGL2 or WebGPU.',
|
|
1288
|
+
type: 'float',
|
|
1289
|
+
default: 0,
|
|
1290
|
+
// Deliberately not animatable: crossing zero switches the whole
|
|
1291
|
+
// feature in and out of the shader, so an animation curve driving this
|
|
1292
|
+
// through zero rebuilds the program on the way past.
|
|
1293
|
+
options: {
|
|
1294
|
+
minValue: 0,
|
|
1295
|
+
maxValue: 4
|
|
1296
|
+
},
|
|
1297
|
+
get (value) {
|
|
1298
|
+
value.num[0] = this.shoreFoamAmount;
|
|
1299
|
+
},
|
|
1300
|
+
set (value) {
|
|
1301
|
+
this.shoreFoamAmount = value.num[0];
|
|
1302
|
+
}
|
|
1303
|
+
},
|
|
1304
|
+
{
|
|
1305
|
+
name: 'ShoreFoamDepth',
|
|
1306
|
+
description: 'How far the foam band reaches from the surface behind it, in meters. Over a bed this is a depth of water; against something vertical it is the horizontal distance to its side, and one value serves both. How wide that is on screen depends on the geometry: a thin line on a steep drop-off, a broad stretch on a flat shelf.',
|
|
1307
|
+
type: 'float',
|
|
1308
|
+
default: 0.5,
|
|
1309
|
+
options: {
|
|
1310
|
+
animatable: true,
|
|
1311
|
+
minValue: 0.001,
|
|
1312
|
+
maxValue: 20
|
|
1313
|
+
},
|
|
1314
|
+
isHidden () {
|
|
1315
|
+
return this.shoreFoamAmount <= 0;
|
|
1316
|
+
},
|
|
1317
|
+
get (value) {
|
|
1318
|
+
value.num[0] = this.shoreFoamDepth;
|
|
1319
|
+
},
|
|
1320
|
+
set (value) {
|
|
1321
|
+
this.shoreFoamDepth = value.num[0];
|
|
1322
|
+
}
|
|
1323
|
+
},
|
|
1324
|
+
{
|
|
1325
|
+
name: 'ShoreFoamFalloff',
|
|
1326
|
+
description: 'Falloff across the foam band. Above 1 pushes the coverage towards the contact line and keeps the outer edge thin and broken.',
|
|
1327
|
+
type: 'float',
|
|
1328
|
+
default: 1.5,
|
|
1329
|
+
options: {
|
|
1330
|
+
animatable: true,
|
|
1331
|
+
minValue: 0.01,
|
|
1332
|
+
maxValue: 8
|
|
1333
|
+
},
|
|
1334
|
+
isHidden () {
|
|
1335
|
+
return this.shoreFoamAmount <= 0;
|
|
1336
|
+
},
|
|
1337
|
+
get (value) {
|
|
1338
|
+
value.num[0] = this.shoreFoamFalloff;
|
|
1339
|
+
},
|
|
1340
|
+
set (value) {
|
|
1341
|
+
this.shoreFoamFalloff = value.num[0];
|
|
1342
|
+
}
|
|
1343
|
+
},
|
|
1344
|
+
{
|
|
1345
|
+
name: 'ShoreFoamScale',
|
|
1346
|
+
description: 'Size of the clumps the band breaks into, as cycles across the band rather than cycles per meter. Being relative to the band width, one value reads the same on a shoreline metres across and on a collar a handspan wide.',
|
|
1347
|
+
type: 'float',
|
|
1348
|
+
default: 2.5,
|
|
1349
|
+
options: {
|
|
1350
|
+
animatable: true,
|
|
1351
|
+
minValue: 0,
|
|
1352
|
+
maxValue: 20
|
|
1353
|
+
},
|
|
1354
|
+
isHidden () {
|
|
1355
|
+
return this.shoreFoamAmount <= 0;
|
|
1356
|
+
},
|
|
1357
|
+
get (value) {
|
|
1358
|
+
value.num[0] = this.shoreFoamScale;
|
|
1359
|
+
},
|
|
1360
|
+
set (value) {
|
|
1361
|
+
this.shoreFoamScale = value.num[0];
|
|
1362
|
+
}
|
|
1363
|
+
},
|
|
1364
|
+
{
|
|
1365
|
+
name: 'ShoreFoamWashAmount',
|
|
1366
|
+
description: 'How far the waterline runs up and back, as a fraction of ShoreFoamDepth. This is what makes the band read as surf rather than as a painted rim; 0 leaves it static. Above 1 the band closes completely at the bottom of the cycle, which looks like the foam blinking out.',
|
|
1367
|
+
type: 'float',
|
|
1368
|
+
default: 0.5,
|
|
1369
|
+
options: {
|
|
1370
|
+
animatable: true,
|
|
1371
|
+
minValue: 0,
|
|
1372
|
+
maxValue: 2
|
|
1373
|
+
},
|
|
1374
|
+
isHidden () {
|
|
1375
|
+
return this.shoreFoamAmount <= 0;
|
|
1376
|
+
},
|
|
1377
|
+
get (value) {
|
|
1378
|
+
value.num[0] = this.shoreFoamWashAmount;
|
|
1379
|
+
},
|
|
1380
|
+
set (value) {
|
|
1381
|
+
this.shoreFoamWashAmount = value.num[0];
|
|
1382
|
+
}
|
|
1383
|
+
},
|
|
1384
|
+
{
|
|
1385
|
+
name: 'ShoreFoamWashSpeed',
|
|
1386
|
+
description: 'Run-up cycles per second. Swell rather than wind waves, so well under 1.',
|
|
1387
|
+
type: 'float',
|
|
1388
|
+
default: 0.12,
|
|
1389
|
+
options: {
|
|
1390
|
+
animatable: true,
|
|
1391
|
+
minValue: 0,
|
|
1392
|
+
maxValue: 2
|
|
1393
|
+
},
|
|
1394
|
+
isHidden () {
|
|
1395
|
+
return this.shoreFoamAmount <= 0;
|
|
1396
|
+
},
|
|
1397
|
+
get (value) {
|
|
1398
|
+
value.num[0] = this.shoreFoamWashSpeed;
|
|
1399
|
+
},
|
|
1400
|
+
set (value) {
|
|
1401
|
+
this.shoreFoamWashSpeed = value.num[0];
|
|
1402
|
+
}
|
|
1403
|
+
},
|
|
1404
|
+
{
|
|
1405
|
+
name: 'ShoreFoamWashScale',
|
|
1406
|
+
description: 'Spatial frequency of the run-up phase, in cycles per meter. At 0 the whole waterline rises and falls in lockstep, which reads as the water level itself changing; a cycle every few tens of meters breaks a long shoreline into sections that run out of step with one another.',
|
|
1407
|
+
type: 'float',
|
|
1408
|
+
default: 0.03,
|
|
1409
|
+
options: {
|
|
1410
|
+
animatable: true,
|
|
1411
|
+
minValue: 0,
|
|
1412
|
+
maxValue: 1
|
|
1413
|
+
},
|
|
1414
|
+
isHidden () {
|
|
1415
|
+
return this.shoreFoamAmount <= 0;
|
|
1416
|
+
},
|
|
1417
|
+
get (value) {
|
|
1418
|
+
value.num[0] = this.shoreFoamWashScale;
|
|
1419
|
+
},
|
|
1420
|
+
set (value) {
|
|
1421
|
+
this.shoreFoamWashScale = value.num[0];
|
|
1422
|
+
}
|
|
1423
|
+
},
|
|
1424
|
+
{
|
|
1425
|
+
name: 'CheapRefractionDepth',
|
|
1426
|
+
description: 'Depth in meters the cheap refraction mode assumes the water is. Sets how strong the distortion looks when RefractionMode is Offset; ignored by March. A constant rather than the measured distance to the bottom, because an offset scaled by that distance paints a second copy of any object breaking the surface.',
|
|
1427
|
+
type: 'float',
|
|
1428
|
+
default: 1,
|
|
1429
|
+
options: {
|
|
1430
|
+
animatable: true,
|
|
1431
|
+
minValue: 0,
|
|
1432
|
+
maxValue: 20
|
|
1433
|
+
},
|
|
1434
|
+
isHidden () {
|
|
1435
|
+
return this.material.refractionMode !== 'offset';
|
|
1436
|
+
},
|
|
1437
|
+
get (value) {
|
|
1438
|
+
value.num[0] = this.material.cheapRefractionDepth;
|
|
1439
|
+
},
|
|
1440
|
+
set (value) {
|
|
1441
|
+
this.material.cheapRefractionDepth = value.num[0];
|
|
1442
|
+
}
|
|
1443
|
+
},
|
|
1444
|
+
{
|
|
1445
|
+
name: 'RefractionBlur',
|
|
1446
|
+
description: 'Scale on how much the medium blurs what is seen through it, 1 for the width the scattering coefficient and the path length imply. Turbid or deep water smudges the bottom; 0 keeps it sharp at any depth.',
|
|
1447
|
+
type: 'float',
|
|
1448
|
+
default: 1,
|
|
1449
|
+
options: {
|
|
1450
|
+
animatable: true,
|
|
1451
|
+
minValue: 0,
|
|
1452
|
+
maxValue: 4
|
|
1453
|
+
},
|
|
1454
|
+
get (value) {
|
|
1455
|
+
value.num[0] = this.material.refractionBlur;
|
|
1456
|
+
},
|
|
1457
|
+
set (value) {
|
|
1458
|
+
this.material.refractionBlur = value.num[0];
|
|
1459
|
+
}
|
|
1460
|
+
},
|
|
1461
|
+
{
|
|
1462
|
+
name: 'ScatterAnisotropy',
|
|
1463
|
+
description: 'Mean cosine of a single scattering event. 0 scatters equally in all directions; higher brightens the water when looking towards the sun through it. Sea water measures near 0.9, but a turbid column blends towards isotropic on its own.',
|
|
1464
|
+
type: 'float',
|
|
1465
|
+
default: DEFAULT_SCATTER_ANISOTROPY,
|
|
1466
|
+
options: {
|
|
1467
|
+
animatable: true,
|
|
1468
|
+
minValue: 0,
|
|
1469
|
+
maxValue: 0.95
|
|
1470
|
+
},
|
|
1471
|
+
get (value) {
|
|
1472
|
+
value.num[0] = this.material.scatterAnisotropy;
|
|
1473
|
+
},
|
|
1474
|
+
set (value) {
|
|
1475
|
+
this.material.scatterAnisotropy = value.num[0];
|
|
1476
|
+
}
|
|
1477
|
+
},
|
|
1478
|
+
{
|
|
1479
|
+
name: 'RefractionScale',
|
|
1480
|
+
description: 'Artistic scale on the refracted view offset. 1 is physical: the view ray is bent by Snell’s law and followed to whatever is behind the water, so the incidence angle, the depth and the perspective are already accounted for. 0 disables refraction.',
|
|
1481
|
+
type: 'float',
|
|
1482
|
+
default: 1,
|
|
1483
|
+
options: {
|
|
1484
|
+
animatable: true,
|
|
1485
|
+
minValue: 0,
|
|
1486
|
+
maxValue: 4
|
|
407
1487
|
},
|
|
408
1488
|
get (value) {
|
|
409
|
-
value.num[0] = this.material.
|
|
1489
|
+
value.num[0] = this.material.refractionScale;
|
|
410
1490
|
},
|
|
411
1491
|
set (value) {
|
|
412
|
-
this.material.
|
|
1492
|
+
this.material.refractionScale = value.num[0];
|
|
413
1493
|
}
|
|
414
1494
|
},
|
|
415
1495
|
{
|
|
@@ -499,5 +1579,5 @@ import '../../../scene/raycast_visitor.js';
|
|
|
499
1579
|
};
|
|
500
1580
|
}
|
|
501
1581
|
|
|
502
|
-
export { getFBMWaveGeneratorClass, getFFTWaveGeneratorClass, getWaterClass };
|
|
1582
|
+
export { getFBMWaveGeneratorClass, getFFTWaveGeneratorClass, getGerstnerWaveClass, getGerstnerWaveGeneratorClass, getWaterClass };
|
|
503
1583
|
//# sourceMappingURL=water.js.map
|