170 lines
7.1 KiB
C#
170 lines
7.1 KiB
C#
/*
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are
|
|
met:
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
* Redistributions in binary form must reproduce the above
|
|
copyright notice, this list of conditions and the following
|
|
disclaimer in the documentation and/or other materials provided
|
|
with the distribution.
|
|
|
|
* Neither the name of libTerrain nor the names of
|
|
its contributors may be used to endorse or promote products
|
|
derived from this software without specific prior written
|
|
permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
|
|
namespace libTerrain
|
|
{
|
|
partial class Channel
|
|
{
|
|
// Ideas for Aerobic erosion
|
|
//
|
|
// Unlike thermal (gravity) and hydraulic (water suspension)
|
|
// aerobic erosion should displace mass by moving sediment
|
|
// in "hops". The length of the hop being dictated by the
|
|
// presence of sharp cliffs and wind speed.
|
|
|
|
// The ability to pickup sediment is defined by the total
|
|
// surface area, such that:
|
|
// 0 0 0
|
|
// 0 1 0
|
|
// 0 0 0
|
|
// Would be the best possible value for sediment to be
|
|
// picked up (total difference = 8) and flatter land
|
|
// will erode less quickly.
|
|
|
|
// Suspended particles assist the erosion process by hitting
|
|
// the surface and chiselling additional particles off faster
|
|
// than alone.
|
|
|
|
// Particles are deposited when one of two conditions is met
|
|
// First:
|
|
// When particles hit a wall - such that the
|
|
// wind direction points at a difference >= the
|
|
// deposition mininum talus.
|
|
// Second:
|
|
// When wind speed is lowered to below the minimum
|
|
// required for transit. An idea for this is to
|
|
// use the navier-stokes algorithms for simulating
|
|
// pressure across the terrain.
|
|
|
|
/// <summary>
|
|
/// An experimental erosion algorithm developed by Adam. Moves sediment by factoring the surface area of each height point.
|
|
/// </summary>
|
|
/// <param name="windspeed">0..1 The speed of the wind</param>
|
|
/// <param name="pickup_talus_minimum">The minimum angle at which rock is eroded 0..1 (recommended: <= 0.30)</param>
|
|
/// <param name="drop_talus_minimum">The minimum angle at which rock is dropped 0..1 (recommended: >= 0.00)</param>
|
|
/// <param name="carry">The percentage of rock which can be picked up to pickup 0..1</param>
|
|
/// <param name="rounds">The number of erosion rounds (recommended: 25+)</param>
|
|
/// <param name="lowest">Drop sediment at the lowest point?</param>
|
|
public void AerobicErosion(double windspeed, double pickup_talus_minimum, double drop_talus_minimum, double carry, int rounds, bool lowest)
|
|
{
|
|
Channel wind = new Channel(w, h) ;
|
|
Channel sediment = new Channel(w, h);
|
|
int x, y, i, j;
|
|
|
|
wind = this.copy();
|
|
wind.normalise(); // Cheap wind calculations
|
|
wind *= windspeed;
|
|
wind.pertubation(30); // Can do better later
|
|
|
|
for (i = 0; i < rounds; i++)
|
|
{
|
|
// Convert some rocks to sand
|
|
for (x = 1; x < w - 1; x++)
|
|
{
|
|
for (y = 1; y < h - 1; y++)
|
|
{
|
|
double me = get(x, y);
|
|
double surfacearea = 0.3; // Everything will erode even if it's flat. Just slower.
|
|
|
|
for (j = 0; j < 9; j++)
|
|
{
|
|
int[] coords = neighbours(NEIGHBOURS.NEIGHBOUR_MOORE, j);
|
|
double target = get(x + coords[0], y + coords[1]);
|
|
|
|
surfacearea += Math.Abs(target - me);
|
|
}
|
|
|
|
double amount = surfacearea * wind.map[x, y] * carry;
|
|
|
|
if (amount < 0)
|
|
amount = 0;
|
|
|
|
if (surfacearea > pickup_talus_minimum)
|
|
{
|
|
this.map[x, y] -= amount;
|
|
sediment.map[x, y] += amount;
|
|
}
|
|
}
|
|
}
|
|
sediment.pertubation(10); // Sediment is blown around a bit
|
|
sediment.seed++;
|
|
wind.pertubation(15); // So is the wind
|
|
wind.seed++;
|
|
|
|
// Convert some sand to rock
|
|
for (x = 1; x < w - 1; x++)
|
|
{
|
|
for (y = 1; y < h - 1; y++)
|
|
{
|
|
double me = get(x, y);
|
|
double surfacearea = 0.01; // Flat land does not get deposition
|
|
double min = double.MaxValue;
|
|
int[] minside = new int[2];
|
|
|
|
for (j = 0; j < 9; j++)
|
|
{
|
|
int[] coords = neighbours(NEIGHBOURS.NEIGHBOUR_MOORE, j);
|
|
double target = get(x + coords[0], y + coords[1]);
|
|
|
|
surfacearea += Math.Abs(target - me);
|
|
|
|
if (target < min && lowest)
|
|
{
|
|
minside = (int[])coords.Clone();
|
|
min = target;
|
|
}
|
|
}
|
|
|
|
double amount = surfacearea * (1.0 - wind.map[x, y]) * carry;
|
|
|
|
if (amount < 0)
|
|
amount = 0;
|
|
|
|
if (surfacearea > drop_talus_minimum)
|
|
{
|
|
this.map[x + minside[0], y + minside[1]] += amount;
|
|
sediment.map[x, y] -= amount;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
Channel myself = this;
|
|
myself += sediment;
|
|
myself.normalise();
|
|
}
|
|
}
|
|
} |