Allow erasing layers/painting over layers from the other splatmap.
Since Layers are hardcoded to 8, this commit also assumes that there will always be 2 splatmaps.
This commit is contained in:
@@ -67,11 +67,13 @@ namespace FlaxEditor.Tools.Terrain.Paint
|
||||
|
||||
// Prepare
|
||||
var splatmapIndex = ActiveSplatmapIndex;
|
||||
var splatmapIndexOther = (splatmapIndex + 1) % 2;
|
||||
var chunkSize = terrain.ChunkSize;
|
||||
var heightmapSize = chunkSize * FlaxEngine.Terrain.PatchEdgeChunksCount + 1;
|
||||
var heightmapLength = heightmapSize * heightmapSize;
|
||||
var patchSize = chunkSize * FlaxEngine.Terrain.UnitsPerVertex * FlaxEngine.Terrain.PatchEdgeChunksCount;
|
||||
var tempBuffer = (Color32*)gizmo.GetSplatmapTempBuffer(heightmapLength * Color32.SizeInBytes).ToPointer();
|
||||
var tempBuffer = (Color32*)gizmo.GetSplatmapTempBuffer(heightmapLength * Color32.SizeInBytes, splatmapIndex).ToPointer();
|
||||
var tempBufferOther = (Color32*)gizmo.GetSplatmapTempBuffer(heightmapLength * Color32.SizeInBytes, (splatmapIndex + 1) % 2).ToPointer();
|
||||
var unitsPerVertexInv = 1.0f / FlaxEngine.Terrain.UnitsPerVertex;
|
||||
ApplyParams p = new ApplyParams
|
||||
{
|
||||
@@ -81,8 +83,10 @@ namespace FlaxEditor.Tools.Terrain.Paint
|
||||
Options = options,
|
||||
Strength = strength,
|
||||
SplatmapIndex = splatmapIndex,
|
||||
SplatmapIndexOther = splatmapIndexOther,
|
||||
HeightmapSize = heightmapSize,
|
||||
TempBuffer = tempBuffer,
|
||||
TempBufferOther = tempBufferOther,
|
||||
};
|
||||
|
||||
// Get brush bounds in terrain local space
|
||||
@@ -131,11 +135,16 @@ namespace FlaxEditor.Tools.Terrain.Paint
|
||||
var sourceData = TerrainTools.GetSplatMapData(terrain, ref patch.PatchCoord, splatmapIndex);
|
||||
if (sourceData == null)
|
||||
throw new Exception("Cannot modify terrain. Loading splatmap failed. See log for more info.");
|
||||
|
||||
var sourceDataOther = TerrainTools.GetSplatMapData(terrain, ref patch.PatchCoord, splatmapIndexOther);
|
||||
if (sourceDataOther == null)
|
||||
throw new Exception("Cannot modify terrain. Loading splatmap failed. See log for more info.");
|
||||
|
||||
// Record patch data before editing it
|
||||
if (!gizmo.CurrentEditUndoAction.HashPatch(ref patch.PatchCoord))
|
||||
{
|
||||
gizmo.CurrentEditUndoAction.AddPatch(ref patch.PatchCoord, splatmapIndex);
|
||||
gizmo.CurrentEditUndoAction.AddPatch(ref patch.PatchCoord, splatmapIndexOther);
|
||||
}
|
||||
|
||||
// Apply modification
|
||||
@@ -144,6 +153,7 @@ namespace FlaxEditor.Tools.Terrain.Paint
|
||||
p.PatchCoord = patch.PatchCoord;
|
||||
p.PatchPositionLocal = patchPositionLocal;
|
||||
p.SourceData = sourceData;
|
||||
p.SourceDataOther = sourceDataOther;
|
||||
Apply(ref p);
|
||||
}
|
||||
}
|
||||
@@ -197,16 +207,34 @@ namespace FlaxEditor.Tools.Terrain.Paint
|
||||
/// The splatmap texture index.
|
||||
/// </summary>
|
||||
public int SplatmapIndex;
|
||||
|
||||
/// <summary>
|
||||
/// The splatmap texture index. If <see cref="SplatmapIndex"/> is 0, this will be 1.
|
||||
/// If <see cref="SplatmapIndex"/> is 1, this will be 0.
|
||||
/// </summary>
|
||||
public int SplatmapIndexOther;
|
||||
|
||||
/// <summary>
|
||||
/// The temporary data buffer (for modified data).
|
||||
/// </summary>
|
||||
public Color32* TempBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// The 'other" temporary data buffer (for modified data). If <see cref="TempBuffer"/> refers
|
||||
/// to the splatmap with index 0, this one will refer to the one with index 1.
|
||||
/// </summary>
|
||||
public Color32* TempBufferOther;
|
||||
|
||||
/// <summary>
|
||||
/// The source data buffer.
|
||||
/// </summary>
|
||||
public Color32* SourceData;
|
||||
|
||||
/// <summary>
|
||||
/// The 'other' source data buffer. If <see cref="SourceData"/> refers
|
||||
/// to the splatmap with index 0, this one will refer to the one with index 1.
|
||||
/// </summary>
|
||||
public Color32* SourceDataOther;
|
||||
|
||||
/// <summary>
|
||||
/// The heightmap size (edge).
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace FlaxEditor.Tools.Terrain.Paint
|
||||
var strength = p.Strength;
|
||||
var layer = (int)Layer;
|
||||
var brushPosition = p.Gizmo.CursorPosition;
|
||||
var layerComponent = layer % 4;
|
||||
var c = layer % 4;
|
||||
|
||||
// Apply brush modification
|
||||
Profiler.BeginEvent("Apply Brush");
|
||||
@@ -82,26 +82,38 @@ namespace FlaxEditor.Tools.Terrain.Paint
|
||||
for (int x = 0; x < p.ModifiedSize.X; x++)
|
||||
{
|
||||
var xx = x + p.ModifiedOffset.X;
|
||||
var src = p.SourceData[zz * p.HeightmapSize + xx];
|
||||
var src = (Color)p.SourceData[zz * p.HeightmapSize + xx];
|
||||
|
||||
var samplePositionLocal = p.PatchPositionLocal + new Vector3(xx * FlaxEngine.Terrain.UnitsPerVertex, 0, zz * FlaxEngine.Terrain.UnitsPerVertex);
|
||||
Vector3.Transform(ref samplePositionLocal, ref p.TerrainWorld, out Vector3 samplePositionWorld);
|
||||
|
||||
var sample = Mathf.Clamp(p.Brush.Sample(ref brushPosition, ref samplePositionWorld), 0f, 1f);
|
||||
var paintAmount = sample * strength * (1f - src[layerComponent] / 255f);
|
||||
|
||||
src[layerComponent] = (byte)Mathf.Clamp(src[layerComponent] + paintAmount * 255, 0, 255);
|
||||
src[(layerComponent + 1) % 4] = (byte)Mathf.Clamp(src[(layerComponent + 1) % 4] - paintAmount * 255, 0, 255);
|
||||
src[(layerComponent + 2) % 4] = (byte)Mathf.Clamp(src[(layerComponent + 2) % 4] - paintAmount * 255, 0, 255);
|
||||
src[(layerComponent + 3) % 4] = (byte)Mathf.Clamp(src[(layerComponent + 3) % 4] - paintAmount * 255, 0, 255);
|
||||
var sample = Mathf.Clamp(p.Brush.Sample(ref brushPosition, ref samplePositionWorld), 0f, 1f);
|
||||
var paintAmount = sample * strength * (1f - src[c]);
|
||||
|
||||
// Paint on the active splatmap texture
|
||||
src[c] = Mathf.Clamp(src[c] + paintAmount, 0, 1f);
|
||||
src[(c + 1) % 4] = Mathf.Clamp(src[(c + 1) % 4] - paintAmount, 0, 1f);
|
||||
src[(c + 2) % 4] = Mathf.Clamp(src[(c + 2) % 4] - paintAmount, 0, 1f);
|
||||
src[(c + 3) % 4] = Mathf.Clamp(src[(c + 3) % 4] - paintAmount, 0, 1f);
|
||||
|
||||
p.TempBuffer[z * p.ModifiedSize.X + x] = src;
|
||||
|
||||
// Remove 'paint' from the other splatmap texture
|
||||
var other = (Color)p.SourceDataOther[zz * p.HeightmapSize + xx];
|
||||
|
||||
other[c] = Mathf.Clamp(other[c] - paintAmount, 0, 1f);
|
||||
other[(c + 1) % 4] = Mathf.Clamp(other[(c + 1) % 4] - paintAmount, 0, 1f);
|
||||
other[(c + 2) % 4] = Mathf.Clamp(other[(c + 2) % 4] - paintAmount, 0, 1f);
|
||||
other[(c + 3) % 4] = Mathf.Clamp(other[(c + 3) % 4] - paintAmount, 0, 1f);
|
||||
|
||||
p.TempBufferOther[z * p.ModifiedSize.X + x] = other;
|
||||
}
|
||||
}
|
||||
Profiler.EndEvent();
|
||||
|
||||
// Update terrain patch
|
||||
TerrainTools.ModifySplatMap(p.Terrain, ref p.PatchCoord, p.SplatmapIndex, p.TempBuffer, ref p.ModifiedOffset, ref p.ModifiedSize);
|
||||
TerrainTools.ModifySplatMap(p.Terrain, ref p.PatchCoord, p.SplatmapIndexOther, p.TempBufferOther, ref p.ModifiedOffset, ref p.ModifiedSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,9 +36,43 @@ namespace FlaxEditor.Tools.Terrain
|
||||
"Layer 7",
|
||||
};
|
||||
|
||||
private IntPtr _cachedSplatmapData;
|
||||
private int _cachedSplatmapDataSize;
|
||||
private class SplatmapData
|
||||
{
|
||||
public IntPtr DataPtr { get; set; } = IntPtr.Zero;
|
||||
public int Size { get; set; } = 0;
|
||||
|
||||
public SplatmapData(int size)
|
||||
{
|
||||
EnsureCapacity(size);
|
||||
}
|
||||
|
||||
public void EnsureCapacity(int size)
|
||||
{
|
||||
if (Size < size)
|
||||
{
|
||||
if (DataPtr != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(DataPtr);
|
||||
}
|
||||
DataPtr = Marshal.AllocHGlobal(size);
|
||||
Size = size;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Free()
|
||||
{
|
||||
if (DataPtr == IntPtr.Zero)
|
||||
return;
|
||||
|
||||
Marshal.FreeHGlobal(DataPtr);
|
||||
DataPtr = IntPtr.Zero;
|
||||
Size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private EditTerrainMapAction _activeAction;
|
||||
private List<SplatmapData> _cachedSplatmapData = new();
|
||||
|
||||
/// <summary>
|
||||
/// The terrain painting gizmo.
|
||||
@@ -230,20 +264,18 @@ namespace FlaxEditor.Tools.Terrain
|
||||
/// Gets the splatmap temporary scratch memory buffer used to modify terrain samples. Allocated memory is unmanaged by GC.
|
||||
/// </summary>
|
||||
/// <param name="size">The minimum buffer size (in bytes).</param>
|
||||
/// <param name="splatmapIndex">The splatmap index for which to return/create the temp buffer.</param>
|
||||
/// <returns>The allocated memory using <see cref="Marshal"/> interface.</returns>
|
||||
public IntPtr GetSplatmapTempBuffer(int size)
|
||||
public IntPtr GetSplatmapTempBuffer(int size, int splatmapIndex)
|
||||
{
|
||||
if (_cachedSplatmapDataSize < size)
|
||||
if (_cachedSplatmapData.Count <= splatmapIndex)
|
||||
{
|
||||
if (_cachedSplatmapData != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(_cachedSplatmapData);
|
||||
}
|
||||
_cachedSplatmapData = Marshal.AllocHGlobal(size);
|
||||
_cachedSplatmapDataSize = size;
|
||||
_cachedSplatmapData.Add(new SplatmapData(size));
|
||||
return _cachedSplatmapData[splatmapIndex].DataPtr;
|
||||
}
|
||||
|
||||
return _cachedSplatmapData;
|
||||
_cachedSplatmapData[splatmapIndex].EnsureCapacity(size);
|
||||
return _cachedSplatmapData[splatmapIndex].DataPtr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -276,11 +308,9 @@ namespace FlaxEditor.Tools.Terrain
|
||||
base.OnDeactivated();
|
||||
|
||||
// Free temporary memory buffer
|
||||
if (_cachedSplatmapData != IntPtr.Zero)
|
||||
foreach (var splatmapData in _cachedSplatmapData)
|
||||
{
|
||||
Marshal.FreeHGlobal(_cachedSplatmapData);
|
||||
_cachedSplatmapData = IntPtr.Zero;
|
||||
_cachedSplatmapDataSize = 0;
|
||||
splatmapData.Free();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user