* Assorted terrain fixes

afrisby
Adam Frisby 2007-07-25 10:08:16 +00:00
parent aa704172d1
commit cd88a4914d
6 changed files with 176 additions and 14 deletions

View File

@ -277,7 +277,7 @@ namespace OpenSim.Region.Terrain
resultText += "terrain save grdmap <filename> <gradient map> - creates a PNG snapshot of the region using a named gradient map\n"; resultText += "terrain save grdmap <filename> <gradient map> - creates a PNG snapshot of the region using a named gradient map\n";
resultText += "terrain rescale <min> <max> - rescales a terrain to be between <min> and <max> meters high\n"; resultText += "terrain rescale <min> <max> - rescales a terrain to be between <min> and <max> meters high\n";
resultText += "terrain fill <val> - fills a terrain at the specified height\n"; resultText += "terrain fill <val> - fills a terrain at the specified height\n";
resultText += "terrain erode aerobic <windspeed> <pickupmin> <dropmin> <carry> <rounds> <lowest>\n"; resultText += "terrain erode aerobic <windspeed> <pickupmin> <dropmin> <carry> <rounds> <lowest t/f> <fluid dynamics t/f>\n";
resultText += "terrain erode thermal <talus> <rounds> <carry>\n"; resultText += "terrain erode thermal <talus> <rounds> <carry>\n";
resultText += "terrain erode hydraulic <rain> <evaporation> <solubility> <frequency> <rounds>\n"; resultText += "terrain erode hydraulic <rain> <evaporation> <solubility> <frequency> <rounds>\n";
resultText += "terrain multiply <val> - multiplies a terrain by <val>\n"; resultText += "terrain multiply <val> - multiplies a terrain by <val>\n";
@ -426,11 +426,14 @@ namespace OpenSim.Region.Terrain
private bool ConsoleErosion(string[] args, ref string resultText) private bool ConsoleErosion(string[] args, ref string resultText)
{ {
double min = heightmap.FindMin();
double max = heightmap.FindMax();
switch (args[1].ToLower()) switch (args[1].ToLower())
{ {
case "aerobic": case "aerobic":
// WindSpeed, PickupMinimum,DropMinimum,Carry,Rounds,Lowest // WindSpeed, PickupMinimum,DropMinimum,Carry,Rounds,Lowest
heightmap.AerobicErosion(Convert.ToDouble(args[2]), Convert.ToDouble(args[3]), Convert.ToDouble(args[4]), Convert.ToDouble(args[5]), Convert.ToInt32(args[6]), Convert.ToBoolean(args[7]), true); heightmap.AerobicErosion(Convert.ToDouble(args[2]), Convert.ToDouble(args[3]), Convert.ToDouble(args[4]), Convert.ToDouble(args[5]), Convert.ToInt32(args[6]), Convert.ToBoolean(args[7]), Convert.ToBoolean(args[8]));
break; break;
case "thermal": case "thermal":
heightmap.ThermalWeathering(Convert.ToDouble(args[2]), Convert.ToInt32(args[3]), Convert.ToDouble(args[4])); heightmap.ThermalWeathering(Convert.ToDouble(args[2]), Convert.ToInt32(args[3]), Convert.ToDouble(args[4]));
@ -444,6 +447,9 @@ namespace OpenSim.Region.Terrain
resultText = "Unknown erosion type"; resultText = "Unknown erosion type";
return false; return false;
} }
heightmap.Normalise(min, max);
tainted++; tainted++;
return true; return true;
} }

View File

@ -257,5 +257,21 @@ namespace libTerrain
{ {
return Sum() / (w * h); return Sum() / (w * h);
} }
public bool ContainsNaN()
{
int x, y;
for (x = 0; x < w; x++)
{
for (y = 0; y < h; y++)
{
double elm = map[x, y];
if (Double.IsNaN(elm))
return true;
}
}
return false;
}
} }
} }

View File

@ -57,13 +57,16 @@ namespace libTerrain
public void SaveImage(string filename) public void SaveImage(string filename)
{ {
Channel outmap = this.Copy();
outmap.Normalise();
Bitmap bit = new Bitmap(w, h, System.Drawing.Imaging.PixelFormat.Format24bppRgb); Bitmap bit = new Bitmap(w, h, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
int x, y; int x, y;
for (x = 0; x < w; x++) for (x = 0; x < w; x++)
{ {
for (y = 0; y < h; y++) for (y = 0; y < h; y++)
{ {
int val = Math.Min(255, (int)(map[x,y] * 255)); int val = Math.Min(255, (int)(outmap.map[x,y] * 255));
Color col = Color.FromArgb(val,val,val); Color col = Color.FromArgb(val,val,val);
bit.SetPixel(x, y, col); bit.SetPixel(x, y, col);
} }

View File

@ -43,13 +43,20 @@ namespace libTerrain
int x, y; int x, y;
for (x = 0; x < w; x++) if (max != min)
{ {
for (y = 0; y < h; y++) for (x = 0; x < w; x++)
{ {
map[x, y] = (map[x, y] - min) * (1.0 / (max - min)); for (y = 0; y < h; y++)
{
map[x, y] = (map[x, y] - min) * (1.0 / (max - min));
}
} }
} }
else
{
this.Fill(0.5);
}
return this; return this;
} }
@ -244,6 +251,76 @@ namespace libTerrain
map = manipulated; map = manipulated;
} }
public void Distort(Channel mask, double str)
{
// Simple pertubation filter
double[,] manipulated = new double[w, h];
double amount;
int x, y;
for (x = 0; x < w; x++)
{
for (y = 0; y < h; y++)
{
amount = mask.map[x, y];
double offset_x = (double)x + (amount * str) - (0.5 * str);
double offset_y = (double)y + (amount * str) - (0.5 * str);
if (offset_x > w)
offset_x = w - 1;
if (offset_y > h)
offset_y = h - 1;
if (offset_y < 0)
offset_y = 0;
if (offset_x < 0)
offset_x = 0;
double p = GetBilinearInterpolate(offset_x, offset_y);
manipulated[x, y] = p;
SetDiff(x, y);
}
}
map = manipulated;
}
public void Distort(Channel mask, Channel mask2, double str)
{
// Simple pertubation filter
double[,] manipulated = new double[w, h];
double amountX;
double amountY;
int x, y;
for (x = 0; x < w; x++)
{
for (y = 0; y < h; y++)
{
amountX = mask.map[x, y];
amountY = mask2.map[x, y];
double offset_x = (double)x + (amountX * str) - (0.5 * str);
double offset_y = (double)y + (amountY * str) - (0.5 * str);
if (offset_x > w)
offset_x = w - 1;
if (offset_y > h)
offset_y = h - 1;
if (offset_y < 0)
offset_y = 0;
if (offset_x < 0)
offset_x = 0;
double p = GetBilinearInterpolate(offset_x, offset_y);
manipulated[x, y] = p;
SetDiff(x, y);
}
}
map = manipulated;
}
public Channel Blend(Channel other, double amount) public Channel Blend(Channel other, double amount)
{ {
int x, y; int x, y;

View File

@ -76,13 +76,19 @@ namespace libTerrain
/// <param name="lowest">Drop sediment at the lowest point?</param> /// <param name="lowest">Drop sediment at the lowest point?</param>
public void AerobicErosion(double windspeed, double pickupTalusMinimum, double dropTalusMinimum, double carry, int rounds, bool lowest, bool usingFluidDynamics) public void AerobicErosion(double windspeed, double pickupTalusMinimum, double dropTalusMinimum, double carry, int rounds, bool lowest, bool usingFluidDynamics)
{ {
bool debugImages = true;
Channel wind = new Channel(w, h) ; Channel wind = new Channel(w, h) ;
Channel sediment = new Channel(w, h); Channel sediment = new Channel(w, h);
int x, y, i, j; int x, y, i, j;
this.Normalise();
wind = this.Copy(); wind = this.Copy();
wind.Normalise(); // Cheap wind calculations wind.Noise();
wind *= windspeed;
if (debugImages)
wind.SaveImage("testimg/wind_start.png");
if (usingFluidDynamics) if (usingFluidDynamics)
{ {
@ -90,9 +96,12 @@ namespace libTerrain
} }
else else
{ {
wind.Pertubation(30); // Can do better later wind.Pertubation(30);
} }
if (debugImages)
wind.SaveImage("testimg/wind_begin.png");
for (i = 0; i < rounds; i++) for (i = 0; i < rounds; i++)
{ {
// Convert some rocks to sand // Convert some rocks to sand
@ -127,7 +136,14 @@ namespace libTerrain
if (usingFluidDynamics) if (usingFluidDynamics)
{ {
sediment.navierStokes(7, 0.1, 0.0, 0.1); sediment.navierStokes(7, 0.1, 0.0, 0.1);
wind.navierStokes(10, 0.1, 0.0, 0.0);
Channel noiseChan = new Channel(w, h);
noiseChan.Noise();
wind.Blend(noiseChan, 0.01);
wind.navierStokes(10, 0.1, 0.01, 0.01);
sediment.Distort(wind, windspeed);
} }
else else
{ {
@ -137,6 +153,9 @@ namespace libTerrain
sediment.seed++; sediment.seed++;
} }
if (debugImages)
wind.SaveImage("testimg/wind_" + i.ToString() + ".png");
// Convert some sand to rock // Convert some sand to rock
for (x = 1; x < w - 1; x++) for (x = 1; x < w - 1; x++)
{ {
@ -174,11 +193,21 @@ namespace libTerrain
} }
} }
if (debugImages)
sediment.SaveImage("testimg/sediment_" + i.ToString() + ".png");
wind.Normalise();
wind *= windspeed;
this.Normalise();
} }
Channel myself = this; Channel myself = this;
myself += sediment; myself += sediment;
myself.Normalise(); myself.Normalise();
if (debugImages)
this.SaveImage("testimg/output.png");
} }
} }
} }

View File

@ -211,11 +211,11 @@ namespace libTerrain
int i; int i;
int j; int j;
for (i = 0; i <= N; i++) for (i = 1; i <= N; i++)
{ {
for (j = 0; j <= N; j++) for (j = 1; j <= N; j++)
{ {
doubles[i, j] = dens[nsIX(i, j, N)]; doubles[i - 1, j - 1] = dens[nsIX(i, j, N)];
} }
} }
} }
@ -229,7 +229,7 @@ namespace libTerrain
{ {
for (j = 1; j <= N; j++) for (j = 1; j <= N; j++)
{ {
dens[nsIX(i, j, N)] = doubles[i, j]; dens[nsIX(i, j, N)] = doubles[i - 1, j - 1];
} }
} }
} }
@ -272,5 +272,36 @@ namespace libTerrain
{ {
nsSimulate(this.h, rounds, dt, diff, visc); nsSimulate(this.h, rounds, dt, diff, visc);
} }
public void navierStokes(int rounds, double dt, double diff, double visc, ref double[,] uret, ref double[,] vret)
{
int N = this.h;
int size = (N * 2) * (N * 2);
double[] u = new double[size]; // Force, X axis
double[] v = new double[size]; // Force, Y axis
double[] u_prev = new double[size];
double[] v_prev = new double[size];
double[] dens = new double[size];
double[] dens_prev = new double[size];
nsDoublesToBuffer(this.map, N, ref dens);
nsDoublesToBuffer(this.map, N, ref dens_prev);
for (int i = 0; i < rounds; i++)
{
u_prev = u;
v_prev = v;
dens_prev = dens;
nsVelStep(N, ref u, ref v, ref u_prev, ref v_prev, visc, dt);
nsDensStep(N, ref dens, ref dens_prev, ref u, ref v, diff, dt);
}
nsBufferToDoubles(ref u, N, ref uret);
nsBufferToDoubles(ref v, N, ref vret);
nsBufferToDoubles(ref dens, N, ref this.map);
}
} }
} }