i do have 2 points on a 2d plane. one has already an vector that does determine in which direction it will move.
now i want to add a vector to this existing vector. so he accelerates in the direction of the other point.
to be a bit more clear, it is about 2 asteroids flying in space (only 2d) and gravitation should move them a bit closer to each other.
what i did build till now is this:
c = body.position - body2.position;
dist = c.Length();
acc = (body.masse * body2.masse) / (dist * dist);
xDist = body2.position.X - body.position.X;
yDist = body2.position.Y - body.position.Y;
direction = MathHelper.ToDegrees((float)(Math.Atan2((double)yDist, (double)xDist)));
body.velocity.Y = body.velocity.Y + (float)(Math.Sin(direction) * acc);
body.velocity.X = body.velocity.X + (float)(Math.Cos(direction) * acc);
in the moment the direction calculated is completly off. surely i am making just a stupid mistake, but i have no idea.
You need to pass your direction angle in in radians to Math.sin and Math.Cos (rather then in degree as you do in your smaple code).
see also:
http://msdn.microsoft.com/en-us/library/system.math.sin.aspx
The angle, a, must be in radians. Multiply by Math.PI/180 to convert degrees to radians.
My mechanics and linear algebra are a bit rusty but I think you should be able to do it without resorting to trigonometry. These formulae probably need tweaking, I'm not sure if I got u and -u mixed up.
Here it is in pseudo code
T is whatever time period you're iterating over
G is the gravitational constant
body1 starts with a velocity of v1
body2 starts with a velocity of v2
c = body.position - body2.position
c1 is a vector
use the vector c to get a vector of length 1 in the direction of the force
u = c1 / c.Length()
body1 should have an acceleration vector of a1 = G * body2mass/c.Length()^2 * (-u)
body2 should have an acceleration vector of a2 = G * body1mass/c.Length()^2 * (u)
body1 has a new velocity vector of v1 + a1/T
body2 has a new velocity vector of v1 + a2/T
rinse and repeat
Not completely sure what you try to do. Why can't you just use Vector2.Add(v1, v2)?
Related
I've already figured out how to make a 3D trajectory using a start point and an angle.
However, I am trying to make a trajectory from a start point, an end point, and a height.
I tried taking the approach of a parabola on a 2D plane in a 3D space. I calculated the Prabola's A, B, and C values as well as the plane it's on given 3 points on the Parabola.
However, I've had a few complications with this sort of calculation, I assume it has to do with the inability to properly calculate a Z-axis without a plane but I cannot tell.
Other than a 2D parabola on a plane google did not provide another possible answer and a 3D trajectory yields a formula using a start point, an angle, and a power multiplier.
Is there any way to calculate a 3D trajectory given the start point, end point, and height?
Appreciating your help
Edit:
My code to calculate a parabola using 3 points (in case someone would like to know how I've done that and perhaps fix what I've done wrong)
public Parabola(Vector3 pa, Vector3 pb, Vector3 pc)
{
this.pa = pa;
this.pc = pc;
float a1 = -pa.x * pa.x + pb.x * pb.x, b1 = -pa.x + pb.x, c1 = -pa.y + pb.y;
float a2 = -pb.x * pb.x + pc.x * pc.x, b2 = -pb.x + pc.x, c2 = -pb.y + pc.y;
float bm = -(b2 / b1), a3 = bm * a1 + a2, c3 = bm * c1 + c2;
float a = c3 / a3, b = (c1 - a1 * a) / b1, c = pa.y - a * pa.x * pa.x - b * pa.x;
this.a = a; this.b = b; this.c = c;
plane = Vector3.Cross(pb - pa, pc - pa);
}
public Vector3 GetPoint(float x)
{
float angle = Mathf.Atan2(pc.z - pa.z, pc.x - pa.x) * Mathf.Rad2Deg;
float xs = Mathf.Cos(angle * Mathf.Deg2Rad) * x, zs = Mathf.Sin(angle * Mathf.Deg2Rad) * x;
return new Vector3(xs, a * x * x + b * x + c, zs);
}
public Vector3 ProjectOn(float x) => Vector3.ProjectOnPlane(GetPoint(x), plane);
The result looks ok when it's only on 2 Axis, but not 3.
here are 2 images for demonstration:
Looking at the second image, the parabola seems to be correct aside from being scaled incorrectly. Let's take a look at your code.
public Vector3 GetPoint(float x)
{
float angle = Mathf.Atan2(pc.z - pa.z, pc.x - pa.x) * Mathf.Rad2Deg;
float xs = Mathf.Cos(angle * Mathf.Deg2Rad) * x, zs = Mathf.Sin(angle * Mathf.Deg2Rad) * x;
return new Vector3(xs, a * x * x + b * x + c, zs);
}
I'm making a lot of assumptions here, but it seems like x is meant as a value that goes from 0.0 to 1.0, representing the start and end of the parabola, respectively. If so, you are determining the X and Z coordinates of this point based exclusively on the sine/cosine of the angle and x. This means that the values xs and zs should only ever be able to be between -1 and 1, limiting yourself to the confines of the unit circle.
The values xs and zs look like they need to be scaled by a factor s calculated by measuring the 2D distance of the start and end points when projected onto the XZ plane. This should stretch the parabola just enough to reach the end point.
I found an answer, but it's kinda a workaround.
Before messing around with Parabolas in 3D, I messed around with linear equations in 3D.
Unlike parabolas, lines have a defined equation even in 3D(Pn = P0 + t x V)(Pn vector containing XYZ, P0 initial point containing XYZ, t float, V Vector3)
In addition, there's only ONE line that goes through 2 points, even in 3D.
I used that to make a trajectory that's made out of 2 points and a height.
I make a new point in the center of those two points and add the height value to the highest Y value of the points, thus creating an Apex.
then I use the same calculations as before to calculate the A, B, and C values that
a parabola with those 3 points would have had.
I made a method that takes in an X value and returns a Vector3 containing the point this X is on a linear equation, but instead, changing the vector's Y value based on the parabola's equation.
Practically creating an elevated line, I made something that looks and behaves perfectly like a 3D parabola.
If you're in C#, here is the code(images):
FIX!!
in the Linear's GetX(float x) method.
it should be:
public Vector3 GetX(float x) => => r0 + (x - r0.x)/v.x * v;
I made a slight mistake in the calculations which I noticed immediately and changed.
May I ask you for piece of advice writing my raytracer in c#. Here's the rpoblem:
I've got a problem detecting hits of the rays and geometry in my raytracer. I've implemented several functions based on this articles: https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/ray-triangle-intersection-geometric-solution
Here's the code of calculating hitpoint:
public Vector3 GetHitPoint(Vector3 origin, Vector3 ray)
{
float D = Vector3.Dot(this.GetNormal(), vertices[0]);
float up = Vector3.Dot(this.GetNormal(), origin);
up = -1 * (up + D); //50
float down =Vector3.Dot(this.GetNormal(), ray); //0.999975
float t = up / -1* down; //50,00125003125078
Console.WriteLine(origin + Vector3.Multiply(t, ray));
return origin + Vector3.Multiply(t, ray);
}
Not very elegant, but shall work. I've got the problem with precision. I've prepared test triangle that is located perpendicular to camera (center -> 0,0,50). The code calculates the point of intersection between triangle and ray.
Origin stands for camera position, ray is the normalized vector that comes from camera to geometry, vertices[0] is the position of vertex and GetNormal() function gives correct normal vector of triangle. The problem in this case is the precision of calculation. After doing all these calculation, my hitpoint has the z coordinate of 49.99975 instead of 50.0.
This is a problem, because I use another algorithm (based on baricentric coordinates) in order to check if hitpoint is inside the triangle.
public bool CheckHitPoint(Vector3 P)
{
Vector3 v0 = vertices[1] - vertices[0];
Vector3 v1 = vertices[2] - vertices[0];
Vector3 v2 = P - vertices[0];
float d00 = Vector3.Dot(v0, v0);
float d01 = Vector3.Dot(v0, v1);
float d11 = Vector3.Dot(v1, v1);
float d20 = Vector3.Dot(v2, v0);
float d21 = Vector3.Dot(v2, v1);
float denom = d00 * d11 - d01 * d01;
float v = (d11 * d20 - d01 * d21);
float w = (d00 * d21 - d01 * d20);
float u = 1.0f - v - w;
if (u < 0 || v < 0 || w < 0)
{
return false;
}
else if (u > 1 || v > 1 || w > 1)
{
return false;
}
else return true;
}
The conditions in algorithm and in the article is the same, but because of inaccurate result of previous function, u v w coefficients are completely wrong (since hitpoint is actually in front of the triangle).
Can I ask you to help me fixing the precision issue in the first algorithm, or introduce some kind of bias into the second algorithm, so I can get the precise hitpoint and successfully detect it inside triangle?
EDIT: Sorry, I thought that problem is preety much clear. Let me explain it deeper. Let's see the triangle:
Vector3[] vertices =
{
new Vector3(-5,-5,50),
new Vector3(5,-5,50),
new Vector3(0,5,50)
};
Vector3[] normals =
{
new Vector3(0,0,-1),
new Vector3(0,0,-1),
new Vector3(0,0,-1)
};
It is clear that Normal Vector for this triangle is n(0,0,-1) and in combination with any point on it's surface, it may describe mathematically the surface.
D is the distance between between (0,0,0) and point on surface, that the triangle lies on. Since the surface may be described as a pair of parameters (normal vector and any point on surface), dot product of these parameter describes D.
Next four lines describes the equation:
t = N(A,B,C)⋅O + D/−N(A,B,C)⋅R
where
N(A,B,C) - normal vector of triangle
O - camera Position
D - Distance from (0,0,0) to surface
R - Normalized Ray Vector
Equation calculates the distance from camera position to point of intersection.
Following these equations, with triangle parameters I attached and camera position (0,0,0) poinitng at (0,0,50) the return value shall be the point with coordinates (x,y,50), no matter what is the pixel I create the ray for.
The problem is, vector methods in c# generally use floats for computations, and this is why the z coordinate is close, but not precisely 50.
Mathematically this is 100% correct, but the precision is poor.
This makes a problem, when I try to check, if the point lies inside triangle using transformation to baricentric coordinates.
The second method is ok mathematically too. Provided that Hitpoint is on the surface, if all coordinates are between 0 and 1 that means that point lies on the triangle. Details here: https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/barycentric-coordinates
If only I could precisely count the coordinates from previous method, that would work. The problem is, because of lack of precision, the hitpoint is slightly on top or below the surface, and baricentric coordinates have crazy values.
The question is, how can I make the first method to be more precise, that means reproduce the t - distance between camera and hitpoint to be enough precise to be 50. What solution would be the best, rounding, creating custom methods for vectors replacing the built-in float-based methods or maybe some algorithm modification?
Would be grateful, if someone with experience with raytracers would gave me the piece of advice.
Is it possible to calculate the length of a vector by rotating it to, and along an axis, and then use that axis to measure the length of the vector? If so, is it less expensive than calculating length by Pythagoras/square-root?
i am working in unity (C#)
Example:
Vector3 myVector(x, y, z);
Vector3 myVectorRealigned = Quaternion.FromToRotation(myVector, Vector3.up) * myVector;
float myVectorLength1 = sqrt(myVector.x^2 + myVector.y^2 + myVector.z^2);
float myVectorLength2 = myVectorRealigned.y;
when i tried this it seemed to work! however which of these methods is the best to use/is the least expensive?
I am no mathematician, so please correct me if I am wrong.
As you have tested, both approaches should work, but I guess that the Quaternion approach is more costly.
The norm approach requires 3 multiplications, 2 additions and 1 sqrt.
In contrast, the first step in the quaternion approach (Quaternion.FromToRotation) alone requires is more costly than calculating the norm. A way of calculating the quaternion describing the rotation from one vector to another is this:
Quaternion q;
vector a = crossproduct(v1, v2)
q.xyz = a;
q.w = sqrt((v1.Length ^ 2) * (v2.Length ^ 2)) + dotproduct(v1, v2)
As you see, this alone is more costly than norm = sqrt(myVector.x^2 + myVector.y^2 + myVector.z^2).
Additionally you use that quaternion to rotate your vector again involves dot products, cross products and several multiplications and additions.
E.g.: rotatedVec = 2 * dot(q.xyz, v) * q.xyz + (q.w^2 - dot(q.xyz, q.xyz)) * v + 2 * q.w * cross(q.xyz, v).
References: from-to-quaternion, rotate vector by quaternion
Side Note: If you are concerned with performance and you don't need the exact length of the vector (e.g. for determining the closest object to position x), you can use Vector3.sqrMagnitude (squared norm) as well.
I stumbled on a working concept for a fast rotation & orientation system today, based on a two-term quaternion that represents either a rotation about the X axis (1,0,0) in the form w + ix, a rotation about the Y axis (0,1,0) in the form w + jy, or a rotation about the Z axis (0,0,1) in the form w + kz.
They're similar to complex numbers, but a) are half-angled and double-sided like all quaternions (they're simply quaternions with two of three imaginary terms zeroed out), and b) represent rotations about one of three 3D axes specifically.
My problem and question is...I can't find any representation of such a system online and have no idea what to search for. What are these complex numbers called? Who else has done something like this before? Where can I find more information on the path I'm headed down? It seems too good to be true and I want to find the other shoe before it drops on me.
Practical example I worked out (an orientation quaternion from Tait-Bryan angles):
ZQuat Y, YQuat P, XQuat R; // yaw, pitch, roll
float w = Y.W * P.W;
float x = -Y.Z * P.Y;
float y = Y.W * P.Y;
float z = Y.Z * P.W;
Quaternion O; // orientation
O.W = x * R.W + w * R.X;
O.X = y * R.W + z * R.X;
O.Y = z * R.W - y * R.X;
O.Z = w * R.W - x * R.X;
Quaternions in 2D would degenerate to just being a single component being no diferrent than an rotation angle. That's propably why you do not find anything. With quaternions you do f.e. not have the problem of gimbal lock, appearing when two rotation axes align because of rotation order. In normal 2D space you do not have more than a single rotation axis, so it has neither order (how do you sort a single element) and there are no axes to align. The lack of rotation axes in 2D is because you get a rotation axis when being perpendicular to two other axes.
This gives 3 axes for 3D:
X&Y=>Z
X&Z=>Y
Y&Z=>X
But only one for 2D:
X&Y=>Z
Hi I'm using this C# code to rotate polygons in my app - they do rotate but also get skewed along the way which is not what i want to happen. All the polygons are rectangles with four corners defined as 2D Vectors,
public Polygon GetRotated(float radians)
{
Vector origin = this.Center;
Polygon ret = new Polygon();
for (int i = 0; i < points.Count; i++)
{
ret.Points.Add(RotatePoint(points[i], origin, radians));
}
return ret;
}
public Vector RotatePoint(Vector point, Vector origin, float angle)
{
Vector ret = new Vector();
ret.X = (float)(origin.X + ((point.X - origin.X) * Math.Cos((float)angle)) - ((point.Y - origin.Y) * Math.Sin((float)angle)));
ret.Y = (float)(origin.Y + ((point.X - origin.X) * Math.Sin((float)angle)) - ((point.Y - origin.Y) * Math.Cos((float)angle)));
return ret;
}
Looks like your rotation transformation is incorrect. You should use:
x' = x*Cos(angle) - y*Sin(angle)
y' = x*Sin(angle) + y*Cos(angle)
For more information, check various sources on the internet. :)
I don't have any answer to why it's skewing yet, but I do have a suggestion to make the code clearer:
public Vector RotatePoint(Vector point, Vector origin, float angle)
{
Vector translated = point - origin;
Vector rotated = new Vector
{
X = translated.X * Math.Cos(angle) - translated.Y * Math.Sin(angle),
Y = translated.X * Math.Sin(angle) + translated.Y * Math.Cos(angle)
};
return rotated + origin;
}
(That's assuming Vector has appropriate +/- operators defined.)
You may still need a couple of casts to float, but you'll still end up with fewer brackets obfuscating things. Oh, and you definitely don't need to cast angle to float, given that it's already declared as float.
EDIT: A note about the rotation matrices involved - it depends on whether you take the angle to be clockwise or anticlockwise. I wouldn't be at all surprised to find out that the matrix is indeed what's going wrong (I did try to check it, but apparently messed up)... but "different" doesn't necessarily mean "wrong". Hopefully the matrix is what's wrong, admittedly :)
I think your rotation matrix is incorrect. There should be a + instead of - in the second equation:
+cos -sin
+sin +cos
Assuming that origin is 0,0. From your formula I would get:
X' = (X + ((X - 0) * Cos(angle)) - ((Y - 0) * Sin(angle)));
X' = X + (X * Cos(angle)) - (Y * Sin(angle));
Which differs from the initial formula
x' = x * cos angle - y * cos angle
So I think Jon Skeet's answer is correct and clearer.
Just a wild guess - are you sure the aspect ratio of your desktop resolution is the same as of the physical screen? That is, are the pixels square? If not, then rotating your rectangles in an arbitrary angle can make them look skewed.