Bug on a terrain generation algorithm - c#

Long story short, the following is based on mesh generation and terrain heights
In my code everything seems to be fine. I have redone all of it and the same issue comes up, I don't know why.
All I know is that the last iteration of the Z for loop ain't giving the right height.
I could just set z-1 and have the game run on the rest of the map
but I feel that this will ruin my next phase of development and so I beg for hints on where might the issue be.
the code for the perlin noise is as follows
public static class PerlinFilter
{
public static float[] Filter(List<int> keyX, List<int> keyZ, int indexX = 0, int indexZ = 0, int sizeX = 100, int sizeZ = 100, int nOctaves = 3, float fBias = .6f)
{
float[] filtered = new float[(sizeX + 1) * (sizeZ + 1)];
for (int z = indexZ; z < sizeZ; z++)
{
for (int x = indexX; x < sizeX; x++)
{
float fNoise = 0.0f;
float fScale = 1.0f;
float fScaleAcc = 0.0f;
for (int o = 0; o < nOctaves; o++)
{
int nPitch = sizeZ >> o;
int nSampleX1 = x / nPitch * nPitch;
int nSampleZ1 = z / nPitch * nPitch;
int nSampleX2 = (nSampleX1 + nPitch) % sizeX;
int nSampleZ2 = (nSampleZ1 + nPitch) % sizeX;
float fBlendX = (float)(x - nSampleX1) / nPitch;
float fBlendZ = (float)(z - nSampleZ1) / nPitch;
float fSampleT = (1.0f - fBlendX) * keyX[nSampleZ1 * sizeX + nSampleX1] + fBlendX * keyZ[nSampleZ1 * sizeZ + nSampleX2];
float fSampleB = (1.0f - fBlendX) * keyX[nSampleZ2 * sizeX + nSampleX1] + fBlendX * keyZ[nSampleZ2 * sizeZ + nSampleX2];
fNoise += (fBlendZ * (fSampleB - fSampleT) + fSampleT) * fScale;
fScaleAcc += fScale;
fScale /= fBias;
}
filtered[z * sizeX + x] = fNoise / fScaleAcc;
}
}
return filtered;
}
}
and the code for the mesh is as follows:
void Generate(bool flat)
{
vertices = new Vector3[(x + 1) * (z + 1)];
for (int i = 0, iz = 0; iz <= z; iz++)
{
for (int ix = 0; ix <= x; ix++, i++)
{
if (flat)
vertices[i] = new Vector3(ix, 0, iz);
else
vertices[i] = new Vector3(ix, PerlinHeight(ix, iz), iz);
}
}
triangles = new int[x * z * 6];
for (int tris = 0, vert = 0, iz = 0; iz < z; iz++, vert++)
{
for (int ix = 0; ix < x; ix++, vert++, tris += 6)
{
triangles[tris + 0] = vert + 0;
triangles[tris + 1] = vert + x + 1;
triangles[tris + 2] = vert + 1;
triangles[tris + 3] = vert + 1;
triangles[tris + 4] = vert + x + 1;
triangles[tris + 5] = vert + x + 2;
}
}
}
public int PerlinHeight(int _x, int _z) => (int)(keyPerlin[_z * x + _x] * 1f);
keyPerlin is the result of the PerlinFilter.Filter.
If it becomes obvious that I need to add more code here let me know, this was done a few months ago, and I have been working on other parts of the game while accepting the z-1 workaround, but at this point I really need to sort this issue out.

In your noise filter generation you do
float[] filtered = new float[(sizeX + 1) * (sizeZ + 1)];
for (int z = indexZ; z < sizeZ; z++)
{
for (int x = indexX; x < sizeX; x++)
{
...
=> You don't fill the complete array with valid values! The last row for z== SizeZ and x==SizeX keeps the default value 0.
While in the mesh you do
vertices = new Vector3[(x + 1) * (z + 1)];
for (int i = 0, iz = 0; iz <= z; iz++)
{
for (int ix = 0; ix <= x; ix++, i++)
{
...
=> You set the last row of vertices all to 0.

Related

Matrix Multiplication returning wrong value

I am calculating values by using weights and bias from MATLAB trained ANN. trying to code a sigmoid simulation equation, but for some reason C# calculations vary too much than that of MATLAB. i.e. error is too high. I tried to check each step of the equation and found out the specific part that is creating the problem (Emphasized part), but I don't know how to solve this issue, if someone could help, would be a huge favour.
1+(purelin(net.LW{2}×(tansig(net.IW{1}×(1-(abs(2×([inputs]-1)))))+net.b{1}))+net.b{2}))/2
//Normalization of Data
public double Normalization(double x, double xMAx, double xMin)
{
double xNorm = 0.0;
xNorm = (x - xMin) / (xMAx - xMin);
if (xNorm < 0)
xNorm = 0;
if (xNorm > 1)
xNorm = 1;
xNorm = Math.Round(xNorm, 4);
return xNorm;
}
// Equation to calculate ANN based Output Values
public double MetrixCalc(double[] Pn, double[,] W1, double[] W2, double[] b1, double b2, double maxValue, double minValue)
{
double FinalValue = 0;
double[] PnCalc1 = new double[Pn.Length];
double[] PnCalc2 = new double[W1.Length / Pn.Length];
for (int i = 0; i < Pn.Length; i++)
{
PnCalc1[i] = 1 - Math.Abs(2 * (Pn[i] - 1));
}
for (int i = 0; i < (W1.Length / Pn.Length); i++)
{
double PnCalc = 0.0;
for (int j = 0; j < Pn.Length; j++)
{
PnCalc = PnCalc + (W1[i, j] * PnCalc1[j]);
}
PnCalc2[i] = PnCalc;
}
for (int i = 0; i < PnCalc2.Length; i++)
{
//PnCalc2[i] = Math.Tanh(PnCalc2[i] + b1[i]);
PnCalc2[i] = PnCalc2[i] + b1[i];
PnCalc2[i] = 2.0 / (1 + Math.Exp(-2 * (PnCalc2[i]))) - 1;
PnCalc2[i] = Math.Round(PnCalc2[i], 4);
}
double FinalCalc = 0.0;
for (int i = 0; i < PnCalc2.Length; i++)
{
*FinalCalc = FinalCalc + (W2[i] * (PnCalc2[i]));*
//FinalValue = FinalCalc;
}
FinalValue = FinalCalc + b2;
FinalValue = 1 + FinalValue;
FinalValue = (1 + FinalValue) / 2.0;
FinalValue = (FinalValue * (maxValue - minValue)) + minValue;
FinalValue = Math.Round(FinalValue, 4);
FinalValue = Math.Abs(FinalValue);
return FinalValue;
}
Problem is solved.
Problem was with the weights matrix copied from MATLAB. debugging mode saved my life. :)

Dynamic Mesh Calculation in Unity is not Indexing Triangles Properly

I'm building a game with Unity and I want to generate a map of square tiles and I am using mesh for it, but for some reason my mesh does not render properly. The last column and a half are invisible.
Here are some pictures:
Shaded view
Wireframe view
And here is the code:
void GenerateMesh()
{
mesh = GetComponent<MeshFilter>().mesh;
mesh.Clear();
Vector3[] vertices = new Vector3[(Map.WIDTH + 1) * (Map.HEIGHT + 1)];
int nextIndex = 0;
for (int x = 0; x <= Map.WIDTH; x++)
{
for (int y = 0; y <= Map.HEIGHT; y++)
{
vertices[nextIndex] = new Vector3(x * Square.SIZE, 0, y * Square.SIZE);
nextIndex++;
}
}
int[] triangles = new int[6 * Map.WIDTH * Map.HEIGHT];
nextIndex = 0;
for (int x = 0; x < Map.WIDTH; x++)
{
for (int y = 0; y < Map.HEIGHT; y++)
{
triangles[nextIndex] = x * Map.HEIGHT + y;
triangles[nextIndex + 1] = x * Map.HEIGHT + y + 1;
triangles[nextIndex + 2] = (x + 1) * Map.HEIGHT + y + 1;
nextIndex += 3;
triangles[nextIndex] = x * Map.HEIGHT + y;
triangles[nextIndex + 1] = (x + 1) * Map.HEIGHT + y + 1;
triangles[nextIndex + 2] = (x + 1) * Map.HEIGHT + y;
nextIndex += 3;
}
}
mesh.vertices = vertices;
mesh.triangles = triangles;
}
Map.WIDTH, Map.HEIGHT and Square.SIZE are constants and their values are 80, 45, 1.
Thanks in advance!
Your first inner loop for y values is using <=
for (int y = 0; y <= Map.HEIGHT; y++)
So your second set of loops should be using Map.Height + 1 for its index calculations:
for (int x = 0; x < Map.WIDTH; x++)
{
for (int y = 0; y < Map.HEIGHT; y++)
{
triangles[nextIndex] = x * (Map.HEIGHT + 1) + y;
triangles[nextIndex + 1] = x * (Map.HEIGHT + 1) + y + 1;
triangles[nextIndex + 2] = (x + 1) * (Map.HEIGHT + 1) + y + 1;
nextIndex += 3;
triangles[nextIndex] = x * (Map.HEIGHT + 1) + y;
triangles[nextIndex + 1] = (x + 1) * (Map.HEIGHT + 1) + y + 1;
triangles[nextIndex + 2] = (x + 1) * (Map.HEIGHT + 1) + y;
nextIndex += 3;
}
}

how to write the value to each matrix index

For example, I have set up a formula to find my Xnew[k+1], Ynew[k+1] and Anew[k+1].
How do I pass the value to a 3 by 1 matrix if I want my
index 1,1 be Xnew[k+1],
index 1,2 be Ynew[k+1],
index 1,3 be Anew[k+1].
Here's what I got so far.
for (k = 0; k < 5; k++)
{
Xnew[k+1] = cX + (T * MPCV[k]) * Math.Cos(cA);
Ynew[k+1] = cY + (T * MPCV[k]) * Math.Sin(cA);
Anew[k+1] = cA + (T * MPCW[k]);
double[,] qK = new double[3, 1];
int i, j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 1; j++)
{
qK[i, j] = 1;
}
}
}
Thank you for the help.
Suposing Xnew[k+1], Ynew[k+1] and Anew[k+1] are doubles:
for ( k = 0; k < 5; k++ ) {
Xnew[k + 1] = cX + (T * MPCV[k]) * Math.Cos(cA);
Ynew[k + 1] = cY + (T * MPCV[k]) * Math.Sin(cA);
Anew[k + 1] = cA + (T * MPCW[k]);
double[,] qk = { { Xnew[k + 1] , Ynew[k + 1] , Anew[k + 1] } };
}
This will make you a 1x3 matrix (arrays start in 0) with:
qk[0,0] = Xnew[k+1]
qk[0,1] = Ynew[k+1]
qk[0,2] = Anew[k+1]
But if you want a 3x1 matrix use instead.
double[,] qk = { { Xnew[k + 1] }, {Ynew[k + 1] }, {Anew[k + 1] } };
That will give you:
qk[0,0] = Xnew[k+1]
qk[1,0] = Ynew[k+1]
qk[2,0] = Anew[k+1]

Homography array transformation

I am working on a homography method to copy and expand the relevant points from a rectangle area of depthImg array to a new array, but the bottomright points do not change the homographyImg array. Any ideas, suggestions appreciated. Thanks and happy holidays.
public short[] depthImg;
public int topleftx = 10;
public int toplefty = 20;
public int toprightx = 300;
public int toprighty = 20;
public int bottomleftx = 30;
public int bottomlefty = 200;
public int bottomrightx = 310;
public int bottomrighty = 220;
short[] homographyImg = new short[320 * 240];
for(int ii = 0; ii < 320 * 240; ii++)
{
int xx = ii % 320;
int yy = ii / 320;
int lx =(topleftx + (bottomleftx - topleftx)*(yy/240));
int rx =(toprightx + (bottomrightx - toprightx)*(yy/240));
if (xx < rx & xx > lx)
{
int px = 320*(xx-lx)/(rx-lx);
int ty =(toplefty + (toprighty - toplefty)*(px/320));
int by =(bottomlefty + (bottomrighty - bottomlefty)*(px/320));
if (yy > ty & yy < by)
{
int pxy = 240*(yy-ty)/(by-ty)*320 + px;
homographyImg[pxy] = depthImg[ii];
}
}
}
// I couldn't paste code in the conversation, so I uploaded here. This is a similar array transformation where they modify the corner coordinates to get a correct picture.
for(int yy = 0; yy < newHeight; yy++)
{
for(int xx = 0; xx < newWidth; xx++)
{
int TLidx = (xx * 2) + yy * 2 * width;
int TRidx = (xx * 2 + 1) + yy * width * 2;
int BLidx = (xx * 2) + (yy * 2 + 1) * width;
int BRidx = (xx * 2 + 1) + (yy * 2 + 1) * width;
dst[newWidth- xx - 1 + yy * newWidth] = Color32.Lerp(Color32.Lerp(src[BLidx],src[BRidx],.5F),
Color32.Lerp(src[TLidx],src[TRidx],.5F),.5F);
}
}

newly added class missing on AForge.Imaging.dll

im tryn to add a new adaptive threshold method to the AForge.Imaging.Filters
I have added the new cs file under
Sources\Imaging\Filters\Adaptive Binarization
Below is the code for the thresholding methods
namespace AForge.Imaging.Filters
{
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using AForge.Imaging;
class SauvolaAdaptiveThresholding : BaseInPlacePartialFilter
{
private const float DEFAULT_WeightingFactor = 0.3f;
private const short DEFAULT_WindowSize = 40;
private float weightingFactor ;
private short windowSize ;
// private format translation dictionary
private Dictionary<PixelFormat, PixelFormat> formatTranslations = new Dictionary<PixelFormat, PixelFormat>();
/// <summary>
/// Format translations dictionary.
/// </summary>
public override Dictionary<PixelFormat,PixelFormat> FormatTranslations
{
get { return formatTranslations; }
}
public float WeightingFactor
{
get{return this.weightingFactor;}
set{this.weightingFactor = value;}
}
public short WindowSize
{
get{return this.windowSize;}
set{this.windowSize = value;}
}
public SauvolaAdaptiveThresholding() :
this(DEFAULT_WeightingFactor,DEFAULT_WindowSize) { }
public SauvolaAdaptiveThresholding(float _weightFact , short _wsize)
{
this.WeightingFactor = _weightFact;
this.WindowSize =_wsize;
// initialize format translation dictionary
formatTranslations[PixelFormat.Format8bppIndexed] = PixelFormat.Format8bppIndexed;
formatTranslations[PixelFormat.Format16bppGrayScale] = PixelFormat.Format16bppGrayScale;
}
protected override unsafe void ProcessFilter(UnmanagedImage image, Rectangle rect)
{
int whalf = windowSize >> 1; //half of windowsize
whalf = windowSize >> 1;
byte* ptr = (byte*)image.ImageData.ToPointer(); //input
// Calculate the integral image, and integral of the squared image
ulong[,] integral_image = new ulong[image.Width , image.Height];
ulong[,] rowsum_image = new ulong[image.Width , image.Height];
ulong[,] integral_sqimg = new ulong[image.Width , image.Height];
ulong[,] rowsum_sqimg = new ulong[image.Width , image.Height];
int xmin, ymin, xmax, ymax, index;
double diagsum, idiagsum, diff, sqdiagsum, sqidiagsum, sqdiff, area;
double mean, std, threshold;
for (int j = 0; j < image.Height; j++)
{
rowsum_image[0, j] = (ulong)*(ptr + j);
rowsum_sqimg[0, j] = rowsum_image[0, j] * rowsum_image[0, j];
}
for (int i = 1; i < image.Width; i++)
{
for (int j = 0; j < image.Height; j++)
{
index = j * image.Width + i;
rowsum_image[i, j] = rowsum_image[i - 1, j] + (ulong)*(ptr + index);
rowsum_sqimg[i, j] = rowsum_sqimg[i - 1, j] + (ulong)(*(ptr + index) * *(ptr + index));
}
}
for (int i = 0; i < image.Width; i++)
{
integral_image[i, 0] = rowsum_image[i, 0];
integral_sqimg[i, 0] = rowsum_sqimg[i, 0];
}
for (int i = 0; i < image.Width; i++)
{
for (int j = 1; j < image.Height; j++)
{
integral_image[i, j] = integral_image[i, j - 1] + rowsum_image[i, j];
integral_sqimg[i, j] = integral_sqimg[i, j - 1] + rowsum_sqimg[i, j];
}
}
//Calculate the mean and standard deviation using the integral image
for (int i = 0; i < image.Width; i++)
{
for (int j = 0; j < image.Height; j++)
{
xmin = Math.Max(0, i - whalf);//max(0, i - whalf);
ymin = Math.Max(0, j - whalf);
xmax = Math.Min(image.Width - 1, i + whalf);
ymax = Math.Min(image.Height - 1, j + whalf);
area = (xmax - xmin + 1) * (ymax - ymin + 1);
if (xmin == 0 && ymin == 0)
{ // Point at origin
diff = integral_image[xmax, ymax];
sqdiff = integral_sqimg[xmax, ymax];
}
else if (xmin == 0 && ymin != 0)
{ // first column
diff = integral_image[xmax, ymax] - integral_image[xmax, ymin - 1];
sqdiff = integral_sqimg[xmax, ymax] - integral_sqimg[xmax, ymin - 1];
}
else if (xmin != 0 && ymin == 0)
{ // first row
diff = integral_image[xmax, ymax] - integral_image[xmin - 1, ymax];
sqdiff = integral_sqimg[xmax, ymax] - integral_sqimg[xmin - 1, ymax];
}
else
{ // rest of the image
diagsum = integral_image[xmax, ymax] + integral_image[xmin - 1, ymin - 1];
idiagsum = integral_image[xmax, ymin - 1] + integral_image[xmin - 1, ymax];
diff = diagsum - idiagsum;
sqdiagsum = integral_sqimg[xmax, ymax] + integral_sqimg[xmin - 1, ymin - 1];
sqidiagsum = integral_sqimg[xmax, ymin - 1] + integral_sqimg[xmin - 1, ymax];
sqdiff = sqdiagsum - sqidiagsum;
}
mean = diff / area;
std = Math.Sqrt((sqdiff - diff * diff / area) / (area - 1));
threshold = mean * (1 + WeightingFactor * ((std / 128) - 1));
if ((double)*(ptr + (j * image.Width + i)) < threshold)//if (gray_image[i, j] < threshold)
*(ptr + (j * image.Width + i)) = 0;
else
*(ptr + (j * image.Width + i)) = 255;
}
}
}
}
}
but when i build the project and use the AForge.Imaging.dll, the above class isn't available. When i try to use the object browser i see all the other classes except for the one i added newly.
Can someone please tell me what am i doing wrong?
It needs to be public
public class SauvolaAdaptiveThresholding : BaseInPlacePartialFilter
You can find more info about the C# access modifiers here: http://msdn.microsoft.com/en-us/library/ms173121.aspx

Categories