114 lines
3.6 KiB
C#
114 lines
3.6 KiB
C#
|
|
using Godot;
|
||
|
|
using System;
|
||
|
|
|
||
|
|
using Rokojori.Extensions;
|
||
|
|
namespace Rokojori
|
||
|
|
{
|
||
|
|
/** One ground texture in a ControlMapTerrain's set.
|
||
|
|
|
||
|
|
Its position in the terrain's `textures` array <marked>is</marked> its
|
||
|
|
index, and that index is what a control-map texel stores. So reordering
|
||
|
|
the array repaints the terrain - worth knowing before dragging entries
|
||
|
|
around.
|
||
|
|
|
||
|
|
<marked>Channel packing.</marked> Two textures per entry, not four:
|
||
|
|
albedo RGB + height in alpha, and normal RGB + roughness in alpha. The
|
||
|
|
packing is not an optimization here, it is the only affordable shape - a
|
||
|
|
fragment reads up to 8 of these ( 4 control taps, base and overlay each ),
|
||
|
|
so every extra sampler is 8 more fetches. Height has to be in alpha
|
||
|
|
because the blend weighting needs it at the same time as the albedo, and
|
||
|
|
roughness rides along with the normal because nothing needs it alone.
|
||
|
|
*/
|
||
|
|
[Tool]
|
||
|
|
[GlobalClass]
|
||
|
|
public partial class ControlMapTexture:Resource
|
||
|
|
{
|
||
|
|
Texture2D _albedo;
|
||
|
|
|
||
|
|
/** RGB albedo, alpha = height. The height drives the blend weighting, so an
|
||
|
|
entry with a flat alpha of 1 crossfades while one with real height
|
||
|
|
interlocks with its neighbours. A texture with no alpha channel at all
|
||
|
|
becomes opaque on import and therefore crossfades, which is the sane
|
||
|
|
fallback rather than a special case.
|
||
|
|
*/
|
||
|
|
[Export]
|
||
|
|
public Texture2D albedo
|
||
|
|
{
|
||
|
|
get => _albedo;
|
||
|
|
set { _albedo = value; EmitChanged(); }
|
||
|
|
}
|
||
|
|
|
||
|
|
Texture2D _normal;
|
||
|
|
|
||
|
|
/** RGB tangent-space normal, alpha = roughness. Left empty, the entry gets
|
||
|
|
a flat normal and full roughness.
|
||
|
|
*/
|
||
|
|
[Export]
|
||
|
|
public Texture2D normal
|
||
|
|
{
|
||
|
|
get => _normal;
|
||
|
|
set { _normal = value; EmitChanged(); }
|
||
|
|
}
|
||
|
|
|
||
|
|
float _metersPerTile = 4;
|
||
|
|
|
||
|
|
/** How many world meters one tile of this texture covers, before the
|
||
|
|
per-texel scale multiplies it. This is the per-texture setting that
|
||
|
|
matters most and the reason the parameter strip exists at all - gravel
|
||
|
|
and a cliff face cannot share a tile size.
|
||
|
|
*/
|
||
|
|
[Export]
|
||
|
|
public float metersPerTile
|
||
|
|
{
|
||
|
|
get => _metersPerTile;
|
||
|
|
set { _metersPerTile = Mathf.Max( 0.01f, value ); EmitChanged(); }
|
||
|
|
}
|
||
|
|
|
||
|
|
float _detile = 0;
|
||
|
|
|
||
|
|
/** Random rotation per control texel, 0 to 1 of a full turn, on top of the
|
||
|
|
painted rotation.
|
||
|
|
|
||
|
|
A texture with any visible structure reads as a grid at tile scale once
|
||
|
|
it covers a large area; rotating each texel's copy breaks that up. Costs
|
||
|
|
nothing - it is one hash and the rotation was already being applied -
|
||
|
|
but it fights with a texture that has a direction of its own, so it is
|
||
|
|
per texture rather than global.
|
||
|
|
*/
|
||
|
|
[Export( PropertyHint.Range, "0,1" )]
|
||
|
|
public float detile
|
||
|
|
{
|
||
|
|
get => _detile;
|
||
|
|
set { _detile = Mathf.Clamp( value, 0, 1 ); EmitChanged(); }
|
||
|
|
}
|
||
|
|
|
||
|
|
float _normalStrength = 1;
|
||
|
|
|
||
|
|
/** Scales the normal map's XY before it is normalized. */
|
||
|
|
[Export]
|
||
|
|
public float normalStrength
|
||
|
|
{
|
||
|
|
get => _normalStrength;
|
||
|
|
set { _normalStrength = value; EmitChanged(); }
|
||
|
|
}
|
||
|
|
|
||
|
|
float _roughness = 1;
|
||
|
|
|
||
|
|
/** Multiplies the roughness read from the normal map's alpha. */
|
||
|
|
[Export]
|
||
|
|
public float roughness
|
||
|
|
{
|
||
|
|
get => _roughness;
|
||
|
|
set { _roughness = value; EmitChanged(); }
|
||
|
|
}
|
||
|
|
|
||
|
|
/** The entry as the parameter strip's texel, in the order the shader's
|
||
|
|
ControlMap_textureParams unpacks it.
|
||
|
|
*/
|
||
|
|
public Color ToParams()
|
||
|
|
{
|
||
|
|
return new Color( metersPerTile, detile, normalStrength, roughness );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|