Settings portion of the WaterNetwork component, defining editable properties for water rendering, flow and performance and providing helpers to resolve material/profile and compute foam amount.
using System;
using Sandbox;
namespace RedSnail.WaterTool2;
public sealed partial class WaterNetwork
{
public const string DefaultMaterialPath = "watertool2/materials/lakewater.vmat";
/// <summary>
/// The water material every river and lake of the network is drawn with (an advancedwater.shader material). Connected
/// water is one surface, so it is one material; the default lake water when empty.
/// </summary>
[Property, Group("Surface"), Order(0)] public Material Material { get; set; }
/// <summary>
/// The waves every river and lake of the network moves with; each scales them by its own wave strength, so the
/// whole network shares one continuous wave field.
/// </summary>
[Property(Title = "Wave Profile"), Group("Surface"), Order(0)] public WaterDefinition WaveProfile { get; set; }
/// <summary>
/// How far apart the water's vertices are. Smaller follows the waves more closely and costs more.
/// </summary>
[Property(Title = "Cell Size"), Group("Surface"), Order(0), Range(16.0f, 256.0f)]
public float CellSize
{
get;
set
{
field = value.Clamp(8.0f, 2048.0f);
MarkDirty();
}
} = 48.0f;
/// <summary>
/// Scales the normal maps' tiling.
/// </summary>
[Property(Title = "Texture Scale"), Group("Surface"), Order(0), Range(0.1f, 4.0f)] public float TextureScale { get; set; } = 1.0f;
/// <summary>
/// The depth of water at which the material's deep colour has fully taken over.
/// </summary>
[Property(Title = "Colour Depth"), Group("Surface"), Order(0)] public float ColorDepth { get; set; } = 400.0f;
/// <summary>
/// How much a slope speeds a river up: at a drop of 1 in 10 the water runs this many tenths faster than on the flat.
/// </summary>
[Property(Title = "Slope Speed-Up"), Group("Flow"), Order(1), Range(0.0f, 40.0f)]
public float SlopeSpeedup
{
get;
set
{
field = value.Clamp(0.0f, 1000.0f);
MarkDirty();
}
} = 8.0f;
/// <summary>
/// How far the water takes to settle to a new speed: through a confluence, onto a slope, back onto the flat.
/// </summary>
[Property(Title = "Speed Smoothing"), Group("Flow"), Order(1), Range(50.0f, 5000.0f)]
public float SpeedSmoothing
{
get;
set
{
field = value.Clamp(1.0f, 100000.0f);
MarkDirty();
}
} = 800.0f;
[Property(Title = "Max Speed"), Group("Flow"), Order(1)]
public float MaxSpeed
{
get;
set
{
field = value.Clamp(1.0f, 100000.0f);
MarkDirty();
}
} = 1500.0f;
/// <summary>
/// How much the water slows towards the banks: 0 runs as fast at the bank as in the middle, 0.5 half as fast.
/// </summary>
[Property(Title = "Bank Drag"), Group("Flow"), Order(1), Range(0.0f, 0.9f)]
public float BankDrag
{
get;
set
{
field = value.Clamp(0.0f, 0.95f);
MarkDirty();
}
} = 0.3f;
/// <summary>
/// How long, in seconds, flowing water carries its waves and textures before the cycle starts over (the restart is
/// always cross-faded away). Longer travels further between restarts but stretches more in fast or bending water.
/// </summary>
[Property(Title = "Flow Cycle"), Group("Flow"), Order(1), Range(0.5f, 8.0f)] public float FlowCycle { get; set { field = value.Clamp(0.1f, 60.0f); } } = 2.0f;
/// <summary>
/// How far a river's current carries on into a lake, in river widths.
/// </summary>
[Property(Title = "Plume Length"), Group("Flow"), Order(1), Range(0.5f, 20.0f)]
public float PlumeLength
{
get;
set
{
field = value.Clamp(0.1f, 100.0f);
MarkDirty();
}
} = 4.0f;
/// <summary>
/// How far, in river widths, a river's wave strength takes to blend into the lake (or the next river) it runs into.
/// </summary>
[Property(Title = "Wave Blend"), Group("Flow"), Order(1), Range(0.0f, 10.0f)]
public float WaveBlend
{
get;
set
{
field = value.Clamp(0.0f, 100.0f);
MarkDirty();
}
} = 1.5f;
/// <summary>
/// How much foam fast water churns up, at most.
/// </summary>
[Property(Title = "Foam"), Group("Foam"), Order(2), Range(0.0f, 1.0f)]
public float FoamAmount
{
get;
set
{
field = value.Clamp(0.0f, 1.0f);
MarkDirty();
}
} = 0.6f;
/// <summary>
/// The speed water starts to foam at.
/// </summary>
[Property(Title = "Foam Start Speed"), Group("Foam"), Order(2)]
public float FoamStartSpeed
{
get;
set
{
field = value.Clamp(0.0f, 100000.0f);
MarkDirty();
}
} = 350.0f;
/// <summary>
/// The speed water is fully foaming at.
/// </summary>
[Property(Title = "Foam Full Speed"), Group("Foam"), Order(2)]
public float FoamFullSpeed
{
get;
set
{
field = value.Clamp(0.0f, 100000.0f);
MarkDirty();
}
} = 900.0f;
/// <summary>
/// A post-process volume (fog, wobble) switched on while the camera is under the water.
/// </summary>
[Property(Title = "Underwater Volume"), Group("Post Processing"), Order(3)] public PostProcessVolume UnderwaterPostProcessVolume { get; set; }
/// <summary>
/// Skips every piece of water outside the camera's view.
/// </summary>
[Property(Title = "Frustum Culling"), Group("Performance"), Order(4)] public bool FrustumCulling { get; set; } = true;
/// <summary>
/// Slack added round each piece before the frustum test, so pieces at the screen's edge don't pop.
/// </summary>
[Property(Title = "Cull Padding"), Group("Performance"), Order(4)] public float CullPadding { get; set; } = 256.0f;
/// <summary>
/// Pieces further than this are skipped. 0 for no limit.
/// </summary>
[Property(Title = "Max Render Distance"), Group("Performance"), Order(4)] public float MaxRenderDistance { get; set; } = 30000.0f;
/// <summary>
/// Rivers are built in pieces of about this length: a change only rebuilds the pieces it touches, and only the
/// pieces in view are drawn.
/// </summary>
[Property(Title = "River Chunk Length"), Group("Performance"), Order(4)]
public float ChunkLength
{
get;
set
{
field = value.Clamp(256.0f, 100000.0f);
MarkDirty();
}
} = 3000.0f;
/// <summary>
/// Lakes are cut into square tiles of this size, so only the parts in view are drawn.
/// </summary>
[Property(Title = "Lake Tile Size"), Group("Performance"), Order(4)]
public float LakeTileSize
{
get;
set
{
field = value.Clamp(256.0f, 100000.0f);
MarkDirty();
}
} = 2048.0f;
private Material m_FallbackMaterial;
/// <summary>
/// The material the water is drawn with: the network's own, or the default lake water.
/// </summary>
public Material ResolvedMaterial
{
get
{
if (Material.IsValid())
return Material;
m_FallbackMaterial ??= Sandbox.Material.Load(DefaultMaterialPath);
return m_FallbackMaterial;
}
}
/// <summary>
/// The wave profile the water moves with: the network's own, or gentle lake waves.
/// </summary>
public WaterDefinition ResolvedProfile => WaveProfile.IsValid() ? WaveProfile : WaterDefinition.Fallback;
/// <summary>
/// How much foam water running at a speed has.
/// </summary>
internal float FoamFor(float _Speed)
{
if (FoamAmount <= 0.0f)
return 0.0f;
float range = MathF.Max(1.0f, FoamFullSpeed - FoamStartSpeed);
float t = Math.Clamp((_Speed - FoamStartSpeed) / range, 0.0f, 1.0f);
return FoamAmount * t * t * (3.0f - 2.0f * t);
}
}