I´m trying to rotate a Vector3D like this:
Vector3D i = new Vector3D(1, 1, 0);
i.Normalize();
Matrix3D m = Matrix3D.Identity;
Quaternion rot = GetShortestRotationBetweenVectors(i, new Vector3D(1, 0, 0));
m.Rotate(rot);
Vector3D j = new Vector3D(0, 1, 0);
Vector3D jRotated = m.Transform(j);
// j should be equal to i
public static Quaternion GetShortestRotationBetweenVectors(Vector3D vector1, Vector3D vector2)
{
vector1.Normalize();
vector2.Normalize();
float angle = (float)Math.Acos(Vector3D.DotProduct(vector1, vector2));
Vector3D axis = Vector3D.CrossProduct(vector2, vector1);
// Check to see if the angle is very small, in which case, the cross product becomes unstable,
// so set the axis to a default. It doesn't matter much what this axis is, as the rotation angle
// will be near zero anyway.
if (angle < 0.001f)
{
axis = new Vector3D(0.0f, 0.0f, 1.0f);
}
if (axis.Length < .001f)
{
return Quaternion.Identity;
}
axis.Normalize();
Quaternion rot = new Quaternion(axis, angle);
return rot;
}
I get the rotation matrix to pass from i = (0.77 ,0.77, 0) to (1,0,0) => 45º. So (0, 1, 0) rotates 45º, and the result should be (0.77, 0.77, 0). But the result is almost the same original vector (0,1,0), so no transform has been done.
How can I rotate vectors? I have a vector (x, y, z), and this vector should rotate to (1, 0, 0). For this operation, suppose we have to rotate 30º. So how do I rotate all the vectors I have this 30º?
At last I found the problem.
float angle = (float)Math.Acos(Vector3D.DotProduct(vector1, vector2));
gives the angle in radians.
Quaternion rot = new Quaternion(axis, angle);
expect the angle in degrees
So the solution is easy:
float angle = (float)(Math.Acos(Vector3D.DotProduct(vector1, vector2)) * (180 / Math.PI));
This means there is a bug in Avateering-XNA (Microsoft Official Software).
Related
A little bit confused - math is really not my strong point, so I'm not sure how to achieve.
Currently the objects instantiate, but I have no control over the distance from center or the rotation of each spawned object
public void instantiateInCircle()
{
for (int i = 0; i < amount; i++)
{
float radius = spawnDistance;
float angle = i * Mathf.PI * 2f / radius;
Vector3 newPos = transform.position + (new Vector3(Mathf.Cos(angle) * radius, spawnHeight, Mathf.Sin(angle) * radius ));
//Rotate objects to look at the center
GameObject instantiatedObject = Instantiate(itemToSpawn, newPos, Quaternion.Euler(0, 0, 0));
instantiatedObject.transform.LookAt(spawnAroundThis.transform);
//How to adjust the width of the radius, how far away from the center?
//Parent instantiated objects to disk
instantiatedObject.transform.parent = spawnAroundThis.transform;
instantiatedObject.transform.localScale = new Vector3(scale, scale, scale);
}
}
How to make the distance adjustable, move cubes in closer to center...?
Currently, you do not access the instantiated object, but the prefab instead. Cache the object and call the LookAt on them.
Since I do not know what type itemToSpawn is, I assumed it is a GameObject. You may want to use your type instead.
GameObject instantiatedObject = Instantiate(itemToSpawn, newPos, Quaternion.Euler(0, 0, 0));
instantiatedObject.transform.LookAt(spawnAroundThis.transform);
If you want to control the distance from center of the rotation:
for (int i = 0; i < amount; i++)
{
float radius = spawnDistance;
float angle = i * Mathf.PI * 2f / (float)amount; // divide by amount, NOT radius
// manipulate radius here as you want
Vector3 newPos = transform.position + (new Vector3(Mathf.Cos(angle) * radius, spawnHeight, Mathf.Sin(angle) * radius ));
...
}
I have a player object that's moving around the screen. The camera is a fixed camera, looking down on the player (like in Diablo).
Now I want the player object to rotate towards the mouse cursor. The player is not always on the center of the screen (for this case I already have a solution).
In order to do this, I think I need to project the mouse cursor to the same height (y-axis) that my player is on (y-axis is "up" in my game) and then check compare player position with cursor position on the same height in world space.
So far, my unprojecting method looks like this:
private bool Unproject(float winX, float winY, float winZ, out Vector3 position)
{
position = Vector3.Zero;
Matrix4 transformMatrix = Matrix4.Invert(World.CurrentWindow.GetViewMatrix() * World.CurrentWindow.GetProjectionMatrix());
Vector4 inVector = new Vector4(
(winX - World.CurrentWindow.X) / World.CurrentWindow.Width * 2f - 1f,
(winY - World.CurrentWindow.Y) / World.CurrentWindow.Height * 2f - 1f,
2f * winZ - 1f,
1f
);
Matrix4 inMatrix = new Matrix4(inVector.X, 0, 0, 0, inVector.Y, 0, 0, 0, inVector.Z, 0, 0, 0, inVector.W, 0, 0, 0);
Matrix4 resultMtx = transformMatrix * inMatrix;
float[] resultVector = new float[] { resultMtx[0, 0], resultMtx[1, 0], resultMtx[2, 0], resultMtx[3, 0] };
if (resultVector[3] == 0)
{
return false;
}
resultVector[3] = 1f / resultVector[3];
position = new Vector3(resultVector[0] * resultVector[3], resultVector[1] * resultVector[3], resultVector[2] * resultVector[3]);
return true;
}
Now I unproject the mouse cursor once for the near plane (winZ = 0) and the far plane (winZ = 1).
protected Vector3 GetMouseRay(MouseState s)
{
Vector3 mouseposNear = new Vector3();
Vector3 mouseposFar = new Vector3();
bool near = Unproject(s.X, s.Y, 0f, out mouseposNear);
bool far = Unproject(s.X, s.Y, 1f, out mouseposFar);
Vector3 finalRay = mouseposFar - mouseposNear;
return finalRay;
}
My problem is:
How do I know if the values are correct. The values in the "finalRay" Vector are quite small - always. I would have thought that i would get much bigger z-values because my near plane (perspective projection) is 0.5f and my far plane is 1000f.
And how can I find out if the mouse cursor is left/right (-x, +x) or behind/in front of (-z, +z) the player? (I know the player's position)
Where is my error?
And how can I find out if the mouse cursor is left/right (-x, +x) or behind/in front of (-z, +z) the player?
Do it in the opposite direction. Project the postion of the player to the screen. So you can easily compare the position of the player with the mouse position:
// positon of the player in world coordinates
Vector3 p_ws ....;
// positon of the player in view space
Vector4 p_view = World.CurrentWindow.GetViewMatrix() * Vector4(p_ws.X, p_ws.Y, p_ws.Z, 1.0);
// postion of the player in clip space (Homogeneous coordinates)
Vector4 p_clip = World.CurrentWindow.GetProjectionMatrix() * p_view;
// positon of the player in normailzed device coordinates (perspective divide)
Vec3 posNDC = new Vector3(p_clip.X / p_clip.W, p_clip.Y / p_clip.W, p_clip.Z / p_clip.W);
// screen position in pixel
float p_screenX = (posNDC.X * 0.5 + 0.5) * World.CurrentWindow.Width;
float p_screenY = (posNDC.Y * 0.5 + 0.5) * World.CurrentWindow.Height;
I want to instantiate gameobjects in a segment of a circle e.g in between 10 degrees and 100 degrees from a known vector3 position. (Imagine a shape of pizza). I found following code that helps me instantiate objects between 0 and 180 degrees. Can someone help me instantiate gameobjects between 10 and 100 degrees as an example.
Vector3 randomCircle ( Vector3 center , float radius )
{
float ang = Random.value * 180;
Vector3 pos;
pos.x = center.x + radius * Mathf.Sin(ang * Mathf.Deg2Rad);
pos.y = center.y + radius * Mathf.Cos(ang * Mathf.Deg2Rad);
pos.z = center.z;
return pos;
}
Copying and modifying my answer to different topic would do what you need.
// get the new position
public Vector3 OrbitPosition(Vector3 centerPoint, float radius, float angle)
{
Vector3 tmp;
// calculate position X
tmp.x = Mathf.Sin(angle * (Mathf.PI / 180)) * radius + centerPoint.x;
// calculate position Y
tmp.y = Mathf.Sin(angle * (Mathf.PI / 180)) * radius + centerPoint.y;
tmp.z = centerPoint.z;
return tmp;
}
// instantiate element at random orbit position
public GameObject InstantiateRandom(GameObject toInstantiate, Vector3 centerPoint)
{
// get calculated position
Vector3 newPosition = OrbitPosition(centerPoint, 10.0f, Random.Range(10.0f, 100.0f));
// instantiate a new instance of GameObject
GameObject newInstance = Instantiate(toInstantiate) as GameObject;
// check if instance was created
if ( newInstance )
{
// set position to the newly created orbit position
newInstance.transform.position = newPosition;
}
// return instance of the newly created object on correct position
return newInstance;
}
Hey I am trying to convert 2d mouse coords to a 3d direction vector to world space. The problem is that the direction vector of the ray is only fully working if the camera is not turning in Y-axis. For example: Camera looking down. Y is -0.999 thats perfect, but now I turn the camera 90° in Y-axis and the result is that X is now -0.999 and Y very small ( but still looking down ). The only direction thats working is Z.
This is the code for getting the mouse ray.
public Vector3 get3DMouseCoords(int mousex, int mousey)
{
Vector2 normalizedCoords = getNormalizedMouseCoords(mousex, mousey);
Vector4 clipCoords = new Vector4(normalizedCoords.X, normalizedCoords.Y, -1f, 1f);
Vector4 eyeRay = getEyeRay(clipCoords);
return getWorldRay(eyeRay);
}
private Vector3 getWorldRay(Vector4 eyeRay)
{
Matrix4 invertertedView = Matrix4.Invert(Camera.Transformation);
Vector3 worldRay = Vector4.Transform(invertertedView, eyeRay).Xyz;
return worldRay.Normalized();
}
private Vector4 getEyeRay(Vector4 clipCoords)
{
Matrix4 invertertedProj = Matrix4.Invert(Camera.PerspectiveProjection);
Vector4 eyeRay = Vector4.Transform(invertertedProj, clipCoords);
return new Vector4(eyeRay.X, eyeRay.Y, -1f, 0f);
}
private Vector2 getNormalizedMouseCoords(int mousex, int mousey)
{
float x = 2.0f * mousex / (float)screenWidth - 1;
float y = -(2.0f * mousey / (float)screenHeight - 1);
return new Vector2(x, y);
}
This is the view matrix code:
Vector3 lookat = new Vector3();
lookat.X = (float)(Math.Sin((float)orientation.X) * Math.Cos((float)orientation.Y));
lookat.Y = (float)Math.Sin((float)orientation.Y);
lookat.Z = (float)(Math.Cos((float)orientation.X) * Math.Cos((float)orientation.Y));
view = Matrix4.LookAt(Position, Position + lookat, Vector3.UnitY);
Thanks in Advance.
I need to move an object forward a specific distance from a start point in space. The start point does not have a forward vector, so I need to compute one from the start point to (0,0,0).
I can successfully compute a new start point with the correct forward vector, however when I use it to move an object it multiplies the move distance instead of adding it.
// "start" is actually a raycast hit point, but am using a Vector3 here for simplicity
float moveDistance = 2;
Vector3 start = new Vector3 (0, 0, 3);
Vector3 center = new Vector3 (0, 0, 0);
Vector3 fwd = start - center;
myObject.position = start + fwd * moveDistance;
Debug.Log (fwd); //returns: (0.0, 0.0, 0.3)
Debug.Log (myObject.position); //returns: (0.0, 0.0, 9.0)
The result is myObject.position = 0, 0, 9 // multiplying moveDistance
And the desired result is = 0, 0, 5 // adding moveDistance
The result does have a forward vector, but it's multiplying instead of adding distance. When I do the same calculation for myObject.position using the forward vector of a gameobject, it adds the distance.
Remember that vectors have both direction and magnitude. Multiplying a vector by a scalar will multiply each of its components. If fwd is (0,0,3), multiplying it by 2 will yield (0,0,6). To get a vector in the same direction with moveDistance length, you could normalize it first:
myObject.position = start + fwd.normalized * moveDistance;
(Personally, I would rather normalize the vector before assigning it to fwd, but that's up to you.)
You can always separate the direction and magnitude parts of a vector, which makes it easier to work with them separately:
Vector3 move = <some vector>
Vector3 moveDir = move.normalized; //a normalized vector has length 1
float moveDist = move.magnitude; //move = moveDir * moveDist
Try something like this:
float distanceToMove = 2;
Vector3 start = new Vector3 (0, 0, 3);
Vector3 center = new Vector3 (0, 0, 0);
Vector3 fwd = (center - start).normalized;
myObject.position = start + fwd * distanceToMove;
Debug.Log (myObject.position);