I've been trying to create a plane mesh in Unity using code, and I've come across a very interesting problem. I created an int[], filled it up with some values, and it's length is somehow zero. I've never encountered anything this quirky, so I'd enjoy a bit of help.
mesh.triangles = new int[]
{
4, 6, 5, 5, 6, 7
};
... // Not important stuff
Debug.Log(mesh.triangles.Length);
I don't know what is happening, so I really haven't tried anything. But in the console, there is an error message stating Failed setting triangles. Some indices are referencing out of bounds vertices. IndexCount: 6, VertexCount: 4.This is probably really important, but I don't understand some parts of the message(especially the last part). And if it makes a difference, I have an array concatenation method being called to add the first triangles to these ones. I initially identified this problem when the half of my mesh still wasn't appearing. I would really appreciate help; thanks.
Edit:
To cut confusion, I'm just going to paste my whole entire method.
private void CreateQuad(ref Mesh mesh, Vector3 offset, bool first)
{
if (first)
{
mesh.vertices = new Vector3[]
{
Vector3.zero, Vector3.right, Vector3.forward, new Vector3(1, 0, 1)
};
mesh.triangles = new int[]
{
0, 2, 1, 1, 2, 3
};
mesh.normals = new Vector3[]
{
Vector3.back, Vector3.back, Vector3.back, Vector3.back
};
mesh.tangents = new Vector4[]
{
new Vector4(1, 0, 0, -1),
new Vector4(1, 0, 0, -1),
new Vector4(1, 0, 0, -1),
new Vector4(1, 0, 0, -1)
};
mesh.uv = new Vector2[]
{
Vector2.zero, Vector2.right, Vector2.up, Vector2.one
};
}
else if (!first)
{
mesh.vertices = new Vector3[]
{
Vector3.zero + offset,
Vector3.right + offset,
Vector3.forward + offset,
new Vector3(1, 0, 1) + offset
};
mesh.triangles = new int[]
{
4, 6, 5, 5, 6, 7
};
mesh.normals = new Vector3[]
{
Vector3.back, Vector3.back, Vector3.back, Vector3.back
};
mesh.tangents = new Vector4[]
{
new Vector4(1, 0, 0, -1),
new Vector4(1, 0, 0, -1),
new Vector4(1, 0, 0, -1),
new Vector4(1, 0, 0, -1)
};
mesh.uv = new Vector2[]
{
Vector2.zero, Vector2.right, Vector2.up, Vector2.one
};
Debug.Log(mesh.triangles.Length);
}
}
You only have FOUR vertices!
mesh.vertices = new Vector3[]
{
Vector3.zero + offset,
Vector3.right + offset,
Vector3.forward + offset,
new Vector3(1, 0, 1) + offset
};
So the indices 4, 6, 5, 5, 6, 7 are all invalid! If you have only four vertices you can maximum have the indices 0, 1, 2, 3
=> Unity simply rejects them all. You should have already taken that hint from the error you get
Failed setting triangles. Some indices are referencing out of bounds vertices. IndexCount: 6, VertexCount: 4
Now it is a bit unclear what exactly you are trying to achieve here but
either you want to REPLACE the vertices: In this case there is no reason to set new triangle instances etc at all! It is enough to connect them only once:
private void CreateQuad(ref Mesh mesh, Vector3 offset, bool first)
{
if (first)
{
mesh.vertices = new Vector3[]
{
Vector3.zero, Vector3.right, Vector3.forward, new Vector3(1, 0, 1)
};
mesh.triangles = new int[]
{
0, 2, 1, 1, 2, 3
};
mesh.normals = new Vector3[]
{
Vector3.back, Vector3.back, Vector3.back, Vector3.back
};
mesh.tangents = new Vector4[]
{
new Vector4(1, 0, 0, -1),
new Vector4(1, 0, 0, -1),
new Vector4(1, 0, 0, -1),
new Vector4(1, 0, 0, -1)
};
mesh.uv = new Vector2[]
{
Vector2.zero, Vector2.right, Vector2.up, Vector2.one
};
}
else if (!first)
{
mesh.vertices = new Vector3[]
{
Vector3.zero + offset,
Vector3.right + offset,
Vector3.forward + offset,
new Vector3(1, 0, 1) + offset
};
}
}
the other properties can simply be left untouched since you only want to update the vertex positions.
Or you actually wanted to ADD more faces. In that case you rather want to append to the existing arrays:
private void CreateQuad(ref Mesh mesh, Vector3 offset, bool first)
{
if (first)
{
mesh.vertices = new Vector3[]
{
Vector3.zero, Vector3.right, Vector3.forward, new Vector3(1, 0, 1)
};
mesh.triangles = new int[]
{
0, 2, 1, 1, 2, 3
};
mesh.normals = new Vector3[]
{
Vector3.back, Vector3.back, Vector3.back, Vector3.back
};
mesh.tangents = new Vector4[]
{
new Vector4(1, 0, 0, -1),
new Vector4(1, 0, 0, -1),
new Vector4(1, 0, 0, -1),
new Vector4(1, 0, 0, -1)
};
mesh.uv = new Vector2[]
{
Vector2.zero, Vector2.right, Vector2.up, Vector2.one
};
}
else if (!first)
{
// fist get already existing verts etc
var oldVerts = mesh.vertices;
var oldTris = mesh.triangles;
// create new vertices and triangles arrays with additional space for the new quad
var newVerts = new Vector3[oldVerts.Length + 4];
var newTris = new int[oldTris.Length + 6];
// copy over the existing vertices and triangles
Array.Copy(oldVerts, newVerts, olVerts.Length);
Array.Copy(oldTris, newtris, oldtris.Length);
// then append the new vertices
newVerts[oldverts.Length + 0] = Vector3.zero + offset;
newVerts[oldverts.Length + 1] = Vector3.right + offset;
newVerts[oldverts.Length + 2] = Vector3.forward + offset;
newVerts[oldverts.Length + 3] = new Vector3(1, 0, 1) + offset;
// append the new triangles
newTris[oldTris.Length + 0] = oldverts.Length + 0;
newTris[oldTris.Length + 1] = oldverts.Length + 2;
newTris[oldTris.Length + 2] = oldverts.Length + 1;
newTris[oldTris.Length + 3] = oldverts.Length + 1;
newTris[oldTris.Length + 4] = oldverts.Length + 2;
newTris[oldTris.Length + 5] = oldverts.Length + 3;
// get the min and max points for filling the uvs (not the most efficient way probably but it is what it is ^^)
// we later want to spread out the UV values linear between 0 (min) and 1 (max) on the given vertices
var min = Vector3.zero;
var max = Vector3.zero;
foreach(var vertex in newVerts)
{
min = Vector3.Min(min, vertex);
max = Vector3.Max(max, vertex);
}
// also fill new tangents and normals and uvs (if really necessary)
var newNormals = new Vector3[newVerts.Length];
var newTangents = new Vector4[newVerts.Length];
var newUVs = new Vector2[newVerts.Length];
for(var i = 0; i < newVerts.Length; i++)
{
var vertex = newVerts[i];
newUVs[i] = new Vector2((vertex.x - min.x) / (max.x - min.x), (vertex.z - min.z) / (max.z - min.z));
newNormals[i] = Vector3.back;
newTangents[i] = new Vector4(1, 0, 0, -1);
};
// finally set them all back
mesh.vertices = newVerts;
mesh.triangles = newTris;
mesh.normals = newNormals;
mesh.tangents = newTangents;
mesh.uv = newUs;
}
}
You first need to set the vertex array before altering the triangles. As Unity writes "It is recommended to assign a triangle array after assigning the vertex array, in order to avoid out of bounds errors."
mesh.vertices = new Vector3[] { new Vector3(-1,0,1), new Vector3(-1,0,-1),
new Vector3(1,0,-1), new Vector3(1,0,1) };
mesh.triangles = new int[] {0,1,2,0,2,3};
I have an ellipse which is growing with time.
To detect the ellipse I have used CvInvoke.AbsDiff method .
and I gets an image like this
I want to put this ellipse to fit-ellipse method and gain the radius es of it.
This is the approach I took.
CvInvoke.AbsDiff(First, img, grayscale);
CvInvoke.CvtColor(grayscale, grayscale, ColorConversion.Bgr2Gray);
CvInvoke.GaussianBlur(grayscale, grayscale, new System.Drawing.Size(11, 11), 15, 15);
CvInvoke.Threshold(grayscale, grayscale, Convert.ToInt16(Threshold), Convert.ToInt16(Threshold * 2), ThresholdType.Binary );
Mat element = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Rectangle, new System.Drawing.Size(3, 3), new System.Drawing.Point(-1, -1));
CvInvoke.Dilate(grayscale, grayscale, element, new System.Drawing.Point(-1, 1), 5, BorderType.Constant, new MCvScalar(255, 255, 255));
CvInvoke.Canny(grayscale, grayscale, Threshold, MaxThreshold * 2, 3);
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
CvInvoke.FindContours(grayscale, contours, null, RetrType.Ccomp, ChainApproxMethod.ChainApproxTc89Kcos);
double area = 0;
double ContourArea = 0;
int contour = 0;
int CenterX;
int CenterY;
for (int i = 0; i < contours.Size; i++)
{
System.Drawing.Rectangle rec = CvInvoke.BoundingRectangle(contours[i]);
output.Draw(rec, new Bgr(255, 0, 255), 2);
CenterX = ((rec.Width) / 2) + rec.X;
CenterY = ((rec.Height) / 2) + rec.Y;
ContourArea = rec.Width * rec.Height; ;
if ((HWidth - CenterFactor) < CenterX && CenterX < (HWidth + CenterFactor) && (HHeight - CenterFactor) < CenterY && CenterY< (HHeight + CenterFactor) )
{
if (ContourArea < 1000000)
if (area < ContourArea)
{
area = ContourArea;
contour = i;
}
}
}
//if (contour == 0)
//{
// return arr;
//}
System.Drawing.Rectangle rect = CvInvoke.BoundingRectangle(contours[contour]);
output.Draw(rect, new Bgr(0, 255, 0), 3);
But i am not getting the best ellipse everytime. This is the contour which I'm getting
Is there any other way to do this?
Although this method is not completely perfect, this could be a possible direction that you could take.
Mat input = CvInvoke.Imread(#"C:\Users\ajones\Desktop\Images\inputImg.png", ImreadModes.AnyColor);
Mat input2 = input.Clone();
Mat thresh = new Mat();
CvInvoke.GaussianBlur(input, thresh, new System.Drawing.Size(7, 7), 10, 10);
CvInvoke.Threshold(thresh, thresh, 3, 10, ThresholdType.Binary);
CvInvoke.Imshow("The Thresh", thresh);
CvInvoke.WaitKey(0);
Mat output = new Mat();
CvInvoke.CvtColor(thresh, output, ColorConversion.Bgr2Gray);
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
CvInvoke.FindContours(output, contours, null, RetrType.External, ChainApproxMethod.ChainApproxSimple);
CvInvoke.DrawContours(input, contours, -1, new MCvScalar(0, 255, 0), 3, LineType.FourConnected);
CvInvoke.Imshow("The Image", input);
CvInvoke.WaitKey(0);
int biggest = 0;
int index = 0;
for (int i = 0; i<contours.Size; i++)
{
if (contours[i].Size > biggest)
{
biggest = contours[i].Size;
index = i;
}
}
CvInvoke.DrawContours(input2, contours, index, new MCvScalar(0, 255, 0), 3, LineType.FourConnected);
CvInvoke.Imshow("The Image2", input2);
CvInvoke.WaitKey(0);
First blur the image using a Gaussian filter.
Then, using a binary threshold.
Afterwards, find all contours on the image
Finally, all you would need to do is just sort through your contours until you found the biggest one.
Like I said, its not completely perfect, but I should help push you in the right direction.
I'm trying to draw a polygon of a solid color. I'm given a vector of 2D vectors, ordered such that there will be an edge from v0 to v1 to v2 to ... to vn to v0.
Does such a primitive exist?
Credit to Stefan Agartsson for the post this answer's code is based upon.
To describe the vertices as edges instead of triangles, You can use the PrimitiveType.LineStrip instead of PrimitiveType.TriangleList you have to adjust the index and counts as well since each vertex is used only once.
BasicEffect basicEffect = new BasicEffect(device);
basicEffect.Texture = myTexture;
basicEffect.TextureEnabled = true;
VertexPositionTexture[] vert = new VertexPositionTexture[4];
vert[0].Position = new Vector3(0, 0, 0); //These connect in order
vert[1].Position = new Vector3(100, 0, 0);
vert[2].Position = new Vector3(100, 100, 0);
vert[3].Position = new Vector3(0, 100, 0);
vert[0].TextureCoordinate = new Vector2(0, 0);
vert[1].TextureCoordinate = new Vector2(1, 0);
vert[2].TextureCoordinate = new Vector2(1, 1);
vert[3].TextureCoordinate = new Vector2(0, 1);
short[] ind = new short[n+1]; // the +1 is to close the shape
for(int i = 0; i < n; i++)
ind[i] = i;
ind[n] = 0; // return to start to close.
Then in your render loop you do this:
foreach (EffectPass effectPass in basicEffect.CurrentTechnique.Passes)
{
effectPass.Apply();
device.DrawUserIndexedPrimitives<VertexPositionTexture>(
PrimitiveType.LineStrip, vert, 0, vert.Length, ind, 0, ind.Length);
}
With the function below, I'm running into problems trying to access the WriteableBitmap.PixelBuffer property. The message I am getting is:
'WriteableBitmap' does not contain a definition for 'PixelBuffer' and no extension method 'PixelBuffer' accepting a first argument of type 'WriteableBitmap' could be found (are you missing a using directive or an assembly reference?)
I have read other places that I need to include
using System.Runtime.InteropServices.WindowsRuntime;
But when I use this include, nothing changes in my code. Looking through the references of my solution, I don't see anything like System.Runtime.InteropServices. Im frustrated as this seems to be the solution to other people trying to access the PixelBuffer of a WriteableBitmap.
private WriteableBitmap ChangeBrightness(WriteableBitmap source, byte change_value)
{
WriteableBitmap dest = new WriteableBitmap(source);
byte[] color = new byte[4];
using (Stream s = source.PixelBuffer.AsStream())
{
using (Stream d = dest.PixelBuffer.AsStream())
{
// read the pixel color
while (s.Read(color, 0, 4) > 0)
{
// color[0] = b
// color[1] = g
// color[2] = r
// color[3] = a
// do the adding algo per byte (skip the alpha)
for (int i = 0; i < 4; i++)
{
if ((int)color[i] + change_value > 255) color[i] = 255; else color[i] = (byte)(color[i] + change_value);
}
// write the new pixel color
d.Write(color, 0, 4);
}
}
}
// return the new bitmap
return dest;
}
Make sure you are referencing the assembly that package belongs to:
System.Runtime.WindowsRuntime assembly
I've ended up going about solving my original problem via other means. To adjust the brightness of my image, I ended up using this functions instead:
public ImageSource AdjustBrightness(BitmapImage Image, int Value, int mod)
{
Bitmap TempBitmap = BitmapImage2Bitmap(Image);
Bitmap NewBitmap = new Bitmap(TempBitmap.Width, TempBitmap.Height);
Graphics NewGraphics = Graphics.FromImage(NewBitmap);
float FinalValue = (float)Value / 255.0f;
float[][] FloatColorMatrix ={
new float[] {1, 0, 0, 0, 0},
new float[] {0, 1, 0, 0, 0},
new float[] {0, 0, 1, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {mod * FinalValue, mod * FinalValue, mod * FinalValue, 1, 1}
};
ColorMatrix NewColorMatrix = new ColorMatrix(FloatColorMatrix);
ImageAttributes Attributes = new ImageAttributes();
Attributes.SetColorMatrix(NewColorMatrix);
NewGraphics.DrawImage(TempBitmap, new Rectangle(0, 0, TempBitmap.Width, TempBitmap.Height), 0, 0, TempBitmap.Width, TempBitmap.Height, GraphicsUnit.Pixel, Attributes);
Attributes.Dispose();
NewGraphics.Dispose();
return Bitmap2BitmapImage(NewBitmap);
}
I am making a simple process which will create a colour changing spiral so I can test a range of variables and learn some C#. However, though I can not find a problem in the code, when I debug it, I am returned with a blank blue screen. Can any one find the problem. Here is all the code containing the variables needed for the ball point:
Vector2 Tripos;
List<Color> Tricol;
List<Vector2> datatripos;
List<int> count;
Color currentcol;
float Tri_angle;
float Triscale;
int Tri_speed;
int screenwidth;
int screenheight;
int addtocount;
Texture2D Ball;
int colourchangespeed;
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
Tripos = new Vector2(screenwidth / 2, screenheight / 2);
Triscale = 1;
Tri_angle = 1;
Tri_speed = 1;
colourchangespeed = 1;
Ball = Content.Load<Texture2D>("ball");
currentcol = new Color(0, 0, 0);
addtocount = 0;
datatripos = new List<Vector2>();
Tricol = new List<Color>();
}
This is called by the update method:
private void Posgen()
{
Tripos.X += (float)Math.Sin(MathHelper.ToRadians(Tri_angle))*Tri_speed;
Tripos.Y += (float)Math.Cos(MathHelper.ToRadians(Tri_angle))*Tri_speed;
Tri_angle++;
}
private void colchanger()
{
currentcol.R += (byte)colourchangespeed;
if (currentcol.R == 255)
{
currentcol.R = 0;
currentcol.G += (byte)colourchangespeed;
}
if (currentcol.G == 255)
{
currentcol.G = 0;
currentcol.B += (byte)colourchangespeed;
}
if (currentcol.B == 255)
{
currentcol.B = 0;
}
}
private void dataadd()
{
addtocount++;
Tricol.Add(currentcol);
datatripos.Add(Tripos);
count.Add(addtocount);
}
Called by the draw method:
private void drawtri()
{
foreach (Vector2 data in datatripos)
{
spriteBatch.Draw(Ball, data, null, currentcol, 0, new Vector2(5, 5), Triscale, SpriteEffects.None, 0);
}
}
If you want the full code ask in advance. There are some variables I don't use but I intend to use for later so ignore these.
Thanks in advance.
Yours Mona.
Check that you are calling dataadd().
As a precaution, colourchangespeed should be declared as a byte rather than as an int because you're only casting to a byte anyway. When checking you colour values, the current value should be compared as >= 255 in the case that colourchangespeed is not 1.
A tip to writing good questions: Remove everything that's unrelated. Everything.