I manually (from editor) create empty object with boxes. It rotate around center.
But if I create same object with boxes from script. It rotate around unknown point for me.
I found the cause. It happening because boxes has scale (0.1, 0.2, 0.1). If I set (1,1,1) - it work.
How to fix it? I want small boxes.
var wall = new GameObject();
//wall.transform.parent = room.transform;
wall.transform.name = "Wall";
wall.transform.position = new Vector3(0,0,0);
for (int x = -3; x < width-3; x++)
{
for (int y = -3; y < height-3; y++)
{
var plate = Instantiate(SimplePlate);
var pos = plate.transform.position;
float posZ = pos.z - (x * plate.transform.lossyScale.z);
float posY = pos.y + (y * plate.transform.lossyScale.y);
var newPos = new Vector3(0, posY, posZ);
plate.transform.position = newPos;
plate.transform.parent = wall.transform;
plate.name = "Plate " + x;
}
}
You could create another empty GameObject and stuff your box inside. Then rotate the parent you just created?
Also, how can you rotate an object with a scale of (0,0,0). Did you mean (1,1,1)?
Related
I'm trying to make a chess game in Augmented Reality. I wrote a script which places chessboard on the Plane in AR. Then I created mesh with 64 squares which match chessboard tiles. I have a problem placing mesh to match my chessboard(screenshots). I think I should rotate mesh by Y axis, but I wasn't able to do that.
placing chessboard:
GameObject placedObject = Instantiate(objectToPlace, placementPose.position, placementPose.rotation * Quaternion.Euler(-90f, 0f, 0f));
script that creates and places mesh:
private float yAdjust = 0F;
private Vector3 boardCenter = GameObject.Find("Interaction").GetComponent<TapToPlaceObject>().placementPose.position;
private void GenerateSquares(float squareSize)
{
adjust = new Vector3(-4 * squareSize, 0, -4 * squareSize) + boardCenter;
squares = new GameObject[8,8];
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
squares[i, j] = CreateSquare(squareSize,i,j);
}
}
}
private GameObject CreateSquare(float squareSize, int i, int j)
{
GameObject square = new GameObject(string.Format("{0},{1}", i, j));
square.transform.parent = transform;
Vector3[] vertices = new Vector3[4];
vertices[0] = new Vector3(i * squareSize, yAdjust, j * squareSize) + adjust;
vertices[1] = new Vector3(i * squareSize, yAdjust, (j + 1) * squareSize) + adjust;
vertices[2] = new Vector3((i + 1) * squareSize, yAdjust, j * squareSize) + adjust;
vertices[3] = new Vector3((i + 1) * squareSize, yAdjust, (j + 1) * squareSize) + adjust;
int[] triangles = new int[] { 0, 1, 2, 1, 3, 2 };
Mesh mesh = new Mesh();
square.AddComponent<MeshFilter>().mesh = mesh;
square.AddComponent<MeshRenderer>().material = squareMaterial;
//square.transform.rotation = Quaternion.Euler(new Vector3(0, boardRotation.eulerAngles.y, 0));
//square.transform.rotation = boardRotation;
mesh.vertices = vertices;
mesh.triangles = triangles;
square.AddComponent<BoxCollider>();
return square;
}
screenshot of my problem
You could probably try and just add another
* Quaternion.Euler(0f, 45f, 0f)
In general though for your squares there is Transform.SetParent which allows you to pass the optional parameter worldPositionStays as false which is probably what you would want to do. By setting
transform.parent = parent
equals calling
transform.SetParent(parent);
which equals calling
transform.SetParent(parent, true);
so the objects keep their original world space orientation and position.
However, I would actually rather recommend you already create that board once in edit mode, make the entire board a prefab and now when you spawn the board you only need to take care of placing and rotating one single object and all children will already be their correctly placed and rotated within the board.
I instantiate a Board GameObject using this code:
mainBoard.transform.position = camera.ViewportToWorldPoint(new Vector3(0f, 0f, camera.nearClipPlane));
Then I try to fill this board by instantiating Tiles GameObjects with loop:
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
Vector3 tempPosition = camera.ViewportToWorldPoint(new Vector3(x, y, camera.nearClipPlane));
GameObject backgroundTile = Instantiate(tilePrefab, tempPosition, Quaternion.identity) as GameObject;
backgroundTile.transform.SetParent(this.transform);
backgroundTile.name = "( " + x + "," + y + ")";
allTiles[x, y] = backgroundTile;
}
}
But the tiles are placed on wrong place. They should be placed one next to each other at the bottom left of the screen but only the first Tile is at correct position.
How can I get all tiles correctly placed on the board?
EDIT
Here is the prefab I am instantiating:
This is what I get:
and this is what I am trying to get:
Thank you.
I did not fully look at your code but try this;
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
Vector3 tempPosition = camera.ViewportToWorldPoint(new Vector3(x, y, camera.nearClipPlane));
GameObject backgroundTile = Instantiate(tilePrefab, tempPosition, Quaternion.identity,this.transform) as GameObject;
backgroundTile.name = "( " + x + "," + y + ")";
allTiles[x, y] = backgroundTile;
}
}
give it a try, sometimes UI makes stupid things if you set parent after you instantiate. So it is better to setparent when you instantiate like this;
GameObject backgroundTile = Instantiate(tilePrefab, tempPosition, Quaternion.identity,this.transform) as GameObject;
If it is for building UI element, I would use the grid component or the vertical/horizontal layout depending on what you want to do. Just set the instantiated element to the grid parent that will take care of the layout
There is an input of points with size of n like below:
S = {x1,y1,x2,y2,...,xn,yn}
I want to display scatter graph of S sequence in a picture box. So for transforming them into picture box dimensions, I have normalized them and multiplied them by width and height of picture box with respecting picture box left and top:
waveData= wave.GetWaveData();
normalizedData = GetSignedNormalized();
n = normalizedData.Count;
picW = pictureBox1.Width;
picH = pictureBox1.Height;
picL = pictureBox1.Left;
picT = pictureBox1.Top;
normalizedInPictureBox = new List<float>();
for (int i=0;i< n; i +=2)
{
float px = normalizedData[i];
float py = normalizedData[i+1];
px = px * (picW - picL);
py = py * (picH - picT) ;
normalizedInPictureBox.Add(px);
normalizedInPictureBox.Add(py);
}
Normalize Method is also:
public List<float> GetSignedNormalized()
{
List<float> data = new List<float>();
short max = waveData.Max();
int m = waveData.Count;
for(int i=0;i< m; i++)
{
data.Add((float)waveData[i] / (float)max);
}
return data;
}
Now I am thinking normalizedInPictureBox List contains vertices in the range of picture box, and here is the code for drawing them on picture box:
In the paint method of picture box:
Graphics gr = e.Graphics;
gr.Clear(Color.Black);
for(int i=0;i< n; i +=2)
{
float x = normalizedInPictureBox[i] ;
float y = normalizedInPictureBox[i+1];
gr.FillEllipse(Brushes.Green, new RectangleF(x, y, 2.25f, 2.25f));
}
But the result is shown below:
I don't Know whats going wrong here , but I think the graph should be horizontal not diagonal ,the desire result is something like this:
I know that I can transform it to center of picture box after this. but How can change my own result to the desire one?
Thanks in advance.
I don't really know why your code doesn't work correctly without having a look at the actual data and playing around with it, but having done chart drawing before, I suggest you go the full way and clearly define your axis ranges and do proper interpolating. It get's much clearer from there.
Here is what I came up with
static Bitmap DrawChart(float[] Values, int Width, int Height)
{
var n = Values.Count();
if (n % 2 == 1) throw new Exception("Invalid data");
//Split the data into lists for easy access
var x = new List<float>();
var y = new List<float>();
for (int i = 0; i < n - 1; i += 2)
{
x.Add(Values[i]);
y.Add(Values[i + 1]);
}
//Chart axis limits, change here to get custom ranges like -1,+1
var minx = x.Min();
var miny = y.Min();
var maxx = x.Max();
var maxy = y.Max();
var dxOld = maxx - minx;
var dyOld = maxy - miny;
//Rescale the y-Range to add a border at the top and bottom
miny -= dyOld * 0.2f;
maxy += dyOld * 0.2f;
var dxNew = (float)Width;
var dyNew = (float)Height;
//Draw the data
Bitmap res = new Bitmap(Width, Height);
using (var g = Graphics.FromImage(res))
{
g.Clear(Color.Black);
for (int i = 0; i < x.Count; i++)
{
//Calculate the coordinates
var px = Interpolate(x[i], minx, maxx, 0, dxNew);
var py = Interpolate(y[i], miny, maxy, 0, dyNew);
//Draw, put the ellipse center around the point
g.FillEllipse(Brushes.ForestGreen, px - 1.0f, py - 1.0f, 2.0f, 2.0f);
}
}
return res;
}
static float Interpolate(float Value, float OldMin, float OldMax, float NewMin, float NewMax)
{
//Linear interpolation
return ((NewMax - NewMin) / (OldMax - OldMin)) * (Value - OldMin) + NewMin;
}
It should be relatively self explanatory. You may consider drawing lines instead of single points, that depends on the look and feel you want to achive. Draw other chart elements to your liking.
Important: The y-Axis is actually inversed in the code above, so positive values go down, negative go up, it is scaled like the screen coordinates. You'll figure out how to fix that :-)
Example with 5000 random-y points (x is indexed):
I recently made an application with C# and OpenGL using OpenTK. I've integrated a frustum culling system in order to improve performance, but for some reasons, objects aren't culled correctly. What I mean is that instead of showing all visibles objects nicely, it just cull random objects and when I rotate the camera, some objects appears and disappears. I know it's normal but not when I should see them. The actual frustum culling code is a C# port of my working C++/DirectXMath code used in something else.
Here's how I create the six frustum planes :
// Create a new view-projection matrices.
var vp = viewMatrix * projMatrix;
// Left plane.
frustumPlanes[0] = new Vector4
{
X = vp.M14 + vp.M11,
Y = vp.M24 + vp.M21,
Z = vp.M34 + vp.M31,
W = vp.M44 + vp.M41
};
// Right plane.
frustumPlanes[1] = new Vector4
{
X = vp.M14 - vp.M11,
Y = vp.M24 - vp.M21,
Z = vp.M34 - vp.M31,
W = vp.M44 - vp.M41
};
// Top plane.
frustumPlanes[2] = new Vector4
{
X = vp.M14 - vp.M12,
Y = vp.M24 - vp.M22,
Z = vp.M34 - vp.M32,
W = vp.M44 - vp.M42
};
// Bottom plane.
frustumPlanes[3] = new Vector4
{
X = vp.M14 + vp.M12,
Y = vp.M24 + vp.M22,
Z = vp.M34 + vp.M32,
W = vp.M44 + vp.M42
};
// Near plane.
frustumPlanes[4] = new Vector4
{
X = vp.M13,
Y = vp.M23,
Z = vp.M33,
W = vp.M43,
};
// Far plane.
frustumPlanes[5] = new Vector4
{
X = vp.M14 - vp.M13,
Y = vp.M24 - vp.M23,
Z = vp.M34 - vp.M33,
W = vp.M44 - vp.M43
};
// Normalize all the planes.
for (int i = 0; i < 6; i++)
frustumPlanes[i] = Vector4.Normalize(frustumPlanes[i]);
And I check if a sphere should be culled here :
public bool CullSphere(Vector3 position, float radius = 0.0f)
{
foreach (var plane in frustumPlanes)
{
// Verify if the point is behind the plane.
if (Vector3.Dot(plane.Xyz, position) + plane.W < -radius)
return true;
}
return false;
}
I saw on some other posts people multiplying the view and projection matrices manually, but I'm not sure that it's the cause of the problem. What I did wrong ?
Thanks
Try use my code implementation https://github.com/ALEXGREENALEX/LED_Engine/tree/master/LED_Engine/LED_Engine ("FrustumCulling.cs" and Draw call in "Game.cs"):
static void Draw(Mesh m)
{
m.CalculateMatrices(MainCamera);
FrustumCulling.ExtractFrustum(MainCamera.GetViewMatrix() * MainCamera.GetProjectionMatrix());
float Scale = Math.Max(m.Scale.X, Math.Max(m.Scale.Y, m.Scale.Z));
if (FrustumCulling.SphereInFrustum(m.Position, m.BoundingSphere.Outer * Scale))
for (int i = 0; i < m.Parts.Count; i++)
// ...
Draw(m, m.Parts[i]);
}
P.S.
1) After extracting frustum you must check intersection with Scaled objects (take maximum value of skale and multiply it by outer BoundingSphere radius).
2) In some old examples we can see MVP matrix in ExtractFrustum function (like there: http://www.codesampler.com/oglsrc/oglsrc_12.htm#ogl_frustum_culling). That's wrong name! They are use old API and Model matrix in this calculation is identity matrix (they call MV - ModelView matrix, but really thats only View matrix):
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
updateViewMatrix();
calculateFrustumPlanes();
void calculateFrustumPlanes(void)
{
float p[16]; // projection matrix
float mv[16]; // **VIEW MATRIX!!!**
float mvp[16]; // **View-Projection matrix!!!**
glGetFloatv( GL_PROJECTION_MATRIX, p );
glGetFloatv( GL_MODELVIEW_MATRIX, mv );
//...
}
I am using the following to create a circle using VertexPositionTexture:
public static ObjectData Circle(Vector2 origin, float radius, int slices)
{
/// See below
}
The texture that is applied to it doesn't look right, it spirals out from the center. I have tried some other things but nothing does it how I want. I would like for it to kind-of just fan around the circle, or start in the top-left end finish in the bottom-right. Basically wanting it to be easier to create textures for it.
I know that are MUCH easier ways to do this without using meshes, but that is not what I am trying to accomplish right now.
This is the code that ended up working thanks to Pinckerman:
public static ObjectData Circle(Vector2 origin, float radius, int slices)
{
VertexPositionTexture[] vertices = new VertexPositionTexture[slices + 2];
int[] indices = new int[slices * 3];
float x = origin.X;
float y = origin.Y;
float deltaRad = MathHelper.ToRadians(360) / slices;
float delta = 0;
float thetaInc = (((float)Math.PI * 2) / vertices.Length);
vertices[0] = new VertexPositionTexture(new Vector3(x, y, 0), new Vector2(.5f, .5f));
float sliceSize = 1f / slices;
for (int i = 1; i < slices + 2; i++)
{
float newX = (float)Math.Cos(delta) * radius + x;
float newY = (float)Math.Sin(delta) * radius + y;
float textX = 0.5f + ((radius * (float)Math.Cos(delta)) / (radius * 2));
float textY = 0.5f + ((radius * (float)Math.Sin(delta)) /(radius * 2));
vertices[i] = new VertexPositionTexture(new Vector3(newX, newY, 0), new Vector2(textX, textY));
delta += deltaRad;
}
indices[0] = 0;
indices[1] = 1;
for (int i = 0; i < slices; i++)
{
indices[3 * i] = 0;
indices[(3 * i) + 1] = i + 1;
indices[(3 * i) + 2] = i + 2;
}
ObjectData thisData = new ObjectData()
{
Vertices = vertices,
Indices = indices
};
return thisData;
}
public static ObjectData Ellipse()
{
ObjectData thisData = new ObjectData()
{
};
return thisData;
}
ObjectData is just a structure that contains an array of vertices & an array of indices.
Hope this helps others that may be trying to accomplish something similar.
It looks like a spiral because you've set the upper-left point for the texture Vector2(0,0) in the center of your "circle" and it's wrong. You need to set it on the top-left vertex of the top-left slice of you circle, because 0,0 of your UV map is the upper left corner of your texture.
I think you need to set (0.5, 0) for the upper vertex, (1, 0.5) for the right, (0.5, 1) for the lower and (0, 0.5) for the left, or something like this, and for the others use some trigonometry.
The center of your circle has to be Vector2(0.5, 0.5).
Regarding the trigonometry, I think you should do something like this.
The center of your circle has UV value of Vector2(0.5, 0.5), and for the others (supposing the second point of the sequence is just right to the center, having UV value of Vector2(1, 0.5)) try something like this:
vertices[i] = new VertexPositionTexture(new Vector3(newX, newY, 0), new Vector2(0.5f + radius * (float)Math.Cos(delta), 0.5f - radius * (float)Math.Sin(delta)));
I've just edited your third line in the for-loop. This should give you the UV coordinates you need for each point. I hope so.