Dynamic Mesh Calculation in Unity is not Indexing Triangles Properly - c#

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;
}
}

Related

Bug on a terrain generation algorithm

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.

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]

Set opacity of particular pixels (and these radius) using Bitmap.LockBits and BitmapData

I'm trying to set opacity of surroundings of particular pixels in bitmap.
For now I can set opacity of pixels that meets some conditions. (e.g. pixel on left or rigt or top or down is not 100% white)
I'm using Bitmap.LockBits and BitmapData, becouse application will process very big images.
Here is my code:
private void SetOpacity(Bitmap processedBitmap, int radius)
{
int opacityStep = 255 / radius;
int opacity = 0;
unsafe
{
BitmapData bitmapData = processedBitmap.LockBits(new Rectangle(0, 0, processedBitmap.Width, processedBitmap.Height), ImageLockMode.ReadWrite, processedBitmap.PixelFormat);
int bytesPerPixel = System.Drawing.Bitmap.GetPixelFormatSize(processedBitmap.PixelFormat) / 8;
int heightInPixels = bitmapData.Height;
int widthInBytes = bitmapData.Width * bytesPerPixel;
byte* ptrFirstPixel = (byte*)bitmapData.Scan0;
for (int y = 0; y < heightInPixels; y++)
{
byte* currentLine = ptrFirstPixel + (y * bitmapData.Stride);
byte* previousLine = ptrFirstPixel + ((y - 1) * bitmapData.Stride);
byte* nextLine = ptrFirstPixel + ((y + 1) * bitmapData.Stride);
for (int x = 0; x < widthInBytes; x = x + bytesPerPixel)
{
if (currentLine[x] + currentLine[x + 1] + currentLine[x + 2] == 765)
{
if (currentLine[x + bytesPerPixel] + currentLine[x + bytesPerPixel + 1] + currentLine[x + bytesPerPixel + 2] != 765)
{
currentLine[x + 3] = (byte)opacity;
}
else if (currentLine[x - bytesPerPixel] + currentLine[x - bytesPerPixel - 1] + currentLine[x - bytesPerPixel - 2] != 765)
{
currentLine[x + 3] = (byte)opacity;
}
else if (previousLine[x] + previousLine[x + 1] + previousLine[x + 2] != 765)
{
currentLine[x + 3] = (byte)opacity;
}
else if (nextLine[x] + nextLine[x + 1] + nextLine[x + 2] != 765)
{
currentLine[x + 3] = (byte)opacity;
}
}
}
}
processedBitmap.UnlockBits(bitmapData);
}
}
Slow variant of this code is:
for (int x = 0; x < processedBitmap.Width; x++)
{
for (int y = 0; y < processedBitmap.Height; y++)
{
if (processedBitmap.GetPixel(x, y) == Color.White)
{
if (processedBitmap.GetPixel(x - 1, y) != Color.White || processedBitmap.GetPixel(x + 1, y) != Color.White
|| processedBitmap.GetPixel(x, y - 1) != Color.White || processedBitmap.GetPixel(x, y + 1) != Color.White)
{
processedBitmap.SetPixel(x, y, Color.FromArgb(0, processedBitmap.GetPixel(x, y)));
}
}
}
}
What I need is to set opacity not only of pixels that meet conditions, but also pixels in some radius.
Also I need some opacity steps.
What I'm trying to do is:
for (int r = Radius; Radius > 0; r--)
{
for (int x = 0; x < processedBitmap.Width; x++)
{
for (int y = 0; y < processedBitmap.Height; y++)
{
if (processedBitmap.GetPixel(x, y) == Color.White)
{
if (processedBitmap.GetPixel(x - 1, y) != Color.White || processedBitmap.GetPixel(x + 1, y) != Color.White
|| processedBitmap.GetPixel(x, y - 1) != Color.White || processedBitmap.GetPixel(x, y + 1) != Color.White)
{
processedBitmap.SetPixel(x, y, Color.FromArgb(0, processedBitmap.GetPixel(x, y)));
for (int i = -r; i < r; i++)
{
for (int j = -r; j < r; j++)
{
if ((i * i + j * j) < (r * r))
{
processedBitmap.SetPixel(x + i, y + j, Color.FromArgb(OpacityStep * r, processedBitmap.GetPixel(x + i, y + i)));
}
}
}
}
}
}
}
}
But way faster.
Pixel format of bitmaps i use is 32bbpArgb
Thanks for any suggestions.

Sobel image processing

My algorithm output is wrong. I tried many solutions, but nothing comes out.
View my result.
SourceImage
I'm sorry Lena
for (int x = 1; x < fimage.Bitmap.Width - 1; x++)
{
for (int y = 1; y < fimage.Bitmap.Height - 1; y++)
{
double sumX = 0, sumY = 0, sum = 0;
for ( int i = -1; i <= 1; i++ )
{
for ( int j = -1; j <= 1; j++ )
{
sumX += fimage[y + i, x + j].R * kernel1[i + 1, j + 1];
sumY += fimage[y + i, x + j].R * kernel2[i + 1, j + 1];
}
}
sum = Math.Sqrt(sumX * sumX + sumY * sumY);
sum = sum > 255 ? 255 : sum < 0 ? 0 : sum;
fimage[x, y] = Color.FromArgb((byte)sum, (byte)sum, (byte)sum);
}
}
Two things that are fishy:
for ( int j = -1; j <= 1; j++ )
{
sumX += fimage[y + i, x + j].R * kernel1[i + 1, j + 1];
sumY += fimage[y + i, x + j].R * kernel2[i + 1, j + 1];
}
You only respect the red component of the image here, why is that?
The other major thing is changing the input picture while iterating through it:
sum = Math.Sqrt(sumX * sumX + sumY * sumY);
sum = sum > 255 ? 255 : sum < 0 ? 0 : sum;
fimage[x, y] = Color.FromArgb((byte)sum, (byte)sum, (byte)sum);
You should save the value to a different output image (create a new Bitmap(fimage.Width, fimage.Height) with the dimensions from the source image). That could explain the weird diagonal symmetry in your picture, where there's basically a symteric copy of the other side.

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