I am making a 3d car game and I have a problem with rotation.
I want to rotate a model around itself but when I move, it starts to move around
the world !
The question is: How do I make a center for the model to move around?
I tried to change the code like this :
effect.World = Matrix.CreateRotationZ(modelRotation) * effect.World = Matrix.CreateTranslation(position);
now instead of moving forward relative to the model, orientation it moves in a set direction !
& this is my code:
effect.World = Matrix.CreateTranslation(position) * Matrix.CreateRotationZ(modelRotation);
effect.View = camera.View;
effect.Projection = camera.Projection;
I have a few tips to get you started:
Matrix multiplication order in DirectX/Xna is differrent than you learned in school.
In school v = A B y meant: v = A (B y). So when chaining matrices, B is applied first.
If you want to combine matrix A and B, you multiply them like C = A B
In Directx/XNA, the order is reversed. To combine matrix B and A, you write var C = B * A;
To stop me from making mistakes, I adopt a naming convention: each matrix (or transform) is called AtoB: WorldToView, ModelToWorld, or ModelToRotatedModel.
This reminds you that the output of the first matrix must match the input of the right matrix :
var modelToView = modelToWorld * worldToView;
and not:
var nowhereToNowhere = worldToView * modelToWorld;
This helped me a lot, I hope it helps you sort out your matrix problems.
P.S.
I hope the origin of your car model is in the center of the car, otherwise the it will still move around strangely.
Try switching these values around:
effect.World = Matrix.CreateTranslation(position) * Matrix.CreateRotationZ(modelRotation);
so it becomes:
effect.World = Matrix.CreateRotationZ(modelRotation) * Matrix.CreateTranslation(position);
I follow a simple acronym thats called ISROT
Identity
Scale
Rotation
Orientation
Translation
You work right to left, so you always end your statement with Translation.
Related
I am trying to draw an arc between two points that represents a projectile's path. The angle that the projectile leaves point A at is known, and the X/Y coordinates of both points are known.
I'm trying to figure out the math behind this, and how to draw it up in c#.
Here is my failed attempt, based on some path examples I found
var g = new StreamGeometry();
var xDistance = Math.Abs(pointA.X - pointB.X);
var yDistance = Math.Abs(pointA.Y - pointB.Y);
var angle = 60;
var radiusX = xDistance / angle;
var radiusY = yDistance / angle;
using (var gc = g.Open())
{
gc.BeginFigure(
startPoint: pointA,
isFilled: false,
isClosed: false);
gc.ArcTo(
point: pointB,
size: new Size(radiusX, radiusY),
rotationAngle: 0d,
isLargeArc: false,
sweepDirection: SweepDirection.Clockwise,
isStroked: true,
isSmoothJoin: false);
}
Any help would be greatly appreciated!
Edit #2 (added clarity): For this problem assume that physics play no role (no gravity, velocity, or any outside forces). The projectile is guaranteed to land at point B and move along a parabolic path. The vertex will be halfway between point A and point B on the horizontal axis. The angle that it launches at is the angle up from the ground (horizontal).
So Point A (Ax, Ay) is known.
Point B (Bx, By) is known.
The angle of departure is known.
The X half of the vertex is known (Vx = Abs(Ax - Bx)).
Does this really boil down to needing to figure out the Y coordinate of the vertex?
Following on from the comments, we need a quadratic Bezier curve. This is defined by 3 points, the start, end, and a control point:
It is defined by the following equation:
We therefore need to find P1 using the given conditions (note that the gravity strength is determined implicitly). For a 2D coordinate we need two constraints / boundary conditions. They are given by:
The tangent vector at P0:
We need to match the angle to the horizontal:
The apex of the curve must be directly below the control point P1:
Therefore the vertical coordinate is given by:
[Please let me know if you would like some example code for the above]
Now for how to add a quadratic Bezier; thankfully, once you have done the above, it is not too difficult
The following method creates the parabolic geometry for the simple symmetric case. The angle is measured in degrees counterclockwise from the horizontal.
public Geometry CreateParabola(double x1, double x2, double y, double angle)
{
var startPoint = new Point(x1, y);
var endPoint = new Point(x2, y);
var controlPoint = new Point(
0.5 * (x1 + x2),
y - 0.5 * (x2 - x1) * Math.Tan(angle * Math.PI / 180));
var geometry = new StreamGeometry();
using (var context = geometry.Open())
{
context.BeginFigure(startPoint, false, false);
context.QuadraticBezierTo(controlPoint, endPoint, true, false);
}
return geometry;
}
A body movement subject only to the force of gravity (air resistance is ignored) can be evaluated with the following equations:
DistanceX(t) = dx0 + Vx0·t
DistanceY(t) = dy0 + Vy0·t - g/2·t^2
Where
g : gravity acceleration (9.8 m/s^2)
dx0 : initial position in the X axis
dy0 : initial position in the Y axis
Vy0 : initial X velocity component (muzzle speed)
Vy0 : initial Y velocity component (muzzle speed)
Well that doesn't seem very helpful, but lets investigate further. Your cannon has a muzzle speed V we can consider constant, so Vx0 and Vy0 can be written as:
Vx0 = V·cos(X)
Vy0 = V·sin(X)
Where X is the angle at which you are shooting. Ok, that seems interesting, we finally have an input that is useful to whoever is shooting the cannon: X. Lets go back to our equations and rewrite them:
DistanceX(t) = dx0 + V·cos(X)·t
DistanceY(t) = dy0 + V·sin(X)·t - g/2·t^2
And now, lets think through what we are trying to do. We want to figure out a way to hit a specific point P. Lets give it coordinates: (A, B). And in order to do that, the projectile has to reach that point in both projections at the same time. We'll call that time T. Ok, lets rewrite our equations again:
A = dx0 + V·cos(X)·T
B = dy0 + V·sin(X)·T - g/2·T^2
Lets get ourselves rid of some unnecessary constants here; if our cannon is located at (0, 0) our equations are now:
A = V·cos(X)·T [1]
B = V·sin(X)·T - g/2·T^2 [2]
From [1] we know that: T = A/(V·cos(X)), so we use that in [2]:
B = V·sin(X)·A/(V·cos(X)) - g/2·A^2/(V^2·cos^2(X))
Or
B = A·tan(X) - g/2·A^2/(V^2*cos^2(X))
And now some trigonometry will tell you that 1/cos^2 = 1 + tan^2 so:
B = A·tan(X) - g/2·A^2/V^2·(1+tan^2(X)) [3]
And now you have quadratic equation in tan(X) you can solve.
DISCLAIMER: typing math is kind of hard, I might have an error in there somewhere, but you should get the idea.
UPDATE The previous approach would allow you to solve the angle X that hits a target P given a muzzle speed V. Based on your comments, the angle X is given, so what you need to figure out is the muzzle speed that will make the projectile hit the target with the specified cannon angle. If it makes you more comfortable, don't think of V as muzzle speed, think of it as a form factor of the parabola you are trying to find.
Solve Vin [3]:
B = A·tan(X) - g/2·A^2/V^2·(1+tan^2(X))
This is a trivial quadratic equation, simply isolate V and take the square root. Obviously the negative root has no physical meaning but it will also do, you can take any of the two solutions. If there is no real number solution for V, it would mean that there is simply no possible shot (or parabola) that reaches P(angle X is too big; imagine you shoot straight up, you'll hit yourself, nothing else).
Now simply eliminate t in the parametrized equations:
x = V·cos(X)·t [4]
y = V·sin(X)·t - g/2·t^2 [5]
From [4] you have t = x/(V·cos(X)). Substitute in [5]:
y = tan(X)·x - g·x^2 /(2·V^2*cos^2(X))
And there is your parabola equation. Draw it and see your shot hit the mark.
I've given it a physical interpretation because I find it easier to follow, but you could change all the names I've written here to purely mathematical terms, it doesn't really matter, at the end of the day its all maths and the parabola is the same, any which way you want to think about it.
The following function calculates the target vector of my FPS camera to put in the OpenGL LookAt method. Camera orientation (in radians) (0,0,0) means the camera is parallel to the z axis looking in the negative direction and the camera right vector is parallel to the x axis in the positive direction.
static Matrix4 GetViewMatrix()
{
Vector3 cameraup = Vector3.Transform(Vector3.UnitY,(Quaternion.FromAxisAngle(LineOfSightVector, Orientation.Z)));
LineOfSightVector.X = (float)(Math.Sin((float)Orientation.X) * Math.Cos((float)Orientation.Y));
LineOfSightVector.Y = (float)Math.Sin((float)Orientation.Y);
LineOfSightVector.Z = (float)(Math.Cos((float)Orientation.X) * Math.Cos((float)Orientation.Y));
return Matrix4.LookAt(Position, Position + LineOfSightVector, cameraup) * View; //View = createperspectivefield of view matrix4
}
It works fine when the camera y axis is (0,1,0). However I have introduced a Z value to my camera orientation (roll). I use that to get the "cameraup" vector. I now need to adjust the 3 trig equations for the LineOfSightVector to take into account the change in the "up" vector so the camera controls go in the right direction. Can someone please advise me on this.
Thanks
Having
lineOfSight = vec3(sin(phi)*cos(ksi), sin(ksi), cos(phi)*cos(ksi));
you could compute right and up directions as follows:
right = vec3(cos(phi)*cos(ksi), 0, -sin(phi)*cos(ksi));
up = cross(lineOfSight, right);
up = normalize(up);
Notice that in such model cases of cos(ksi) == 0 should be handled separately.
I have a point in space represented by a 4x4 matrix. I'd like to get the screen coordinates for the point. Picking appears to be the exact opposite fo what I need. I'm using the screen coordinate to determine where to draw text.
Currently the text I draw is floating in space far in front of the points. I've attached a screenshot of zoomed-in and zoomed-out to better explain. As you can see in the screenshot, the distance between each point is the same when zoomed in, when it should be smaller.
Am I missing a transformation? World coordinates consider 0,0,0 to be the center of the grid. I'm using SlimDX.
var viewProj = mMainCamera.View * mMainCamera.Projection;
//Convert 4x4 matrix for point to Vector4
var originalXyz = Vector3.Transform(Vector3.Zero, matrix);
//Vector4 to Vector3
Vector3 worldSpaceCoordinates = new Vector3(originalXyz.X, originalXyz.Y, originalXyz.Z);
//Transform point by view projection matrix
var transformedCoords = Vector3.Transform(worldSpaceCoordinates, viewProj);
Vector3 clipSpaceCoordinates = new Vector3(transformedCoords.X, transformedCoords.Y, transformedCoords.Z);
Vector2 pixelPosition = new Vector2((float)(0.5 * (clipSpaceCoordinates.X + 1) * ActualWidth), (float)(0.5 * (clipSpaceCoordinates.Y + 1) * ActualHeight));
Turns out I was way overthinking this. Just project the point to the screen by passing Vector3.Project your viewport information. It's a 3 line solution.
var viewProj = mMainCamera.View * mMainCamera.Projection;
var vp = mDevice.ImmediateContext.Rasterizer.GetViewports()[0];
var screenCoords = Vector3.Project(worldSpaceCoordinates, vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ, viewProj);
I meet are having difficulty in moving my camera behind an object in a 3D world. I would create two view mode.
1: for fps (first person).
2nd: external view behind the character (second person).
I searched the net some example but it does not work in my project.
Here is my code used to change view if F2 is pressed
//Camera
double X1 = this.camera.PositionX;
double X2 = this.player.Position.X;
double Z1 = this.camera.PositionZ;
double Z2 = this.player.Position.Z;
//Verify that the user must not let the press F2
if (!this.camera.IsF2TurnedInBoucle)
{
// If the view mode is the second person
if (this.camera.ViewCamera_type == CameraSimples.ChangeView.SecondPerson)
{
this.camera.ViewCamera_type = CameraSimples.ChangeView.firstPerson;
//Calcul position - ?? Here my problem
double direction = Math.Atan2(X2 - X1, Z2 - Z1) * 180.0 / 3.14159265;
//Calcul angle - ?? Here my problem
this.camera.position = ..
this.camera.rotation = ..
this.camera.MouseRadian_LeftrightRot = (float)direction;
}
//IF mode view is first person
else
{
//....
Here is a very basic 3rd person camera (what you meant by 2nd person) in Xna. It assumes you have the player's world matrix stored and can access it:
Vector3 _3rdPersonCamPosition = playerWorldMatrix.Translation + (playerWorldMatrix.Backward * trailingDistance) + (playerWorldMatrix.Up * heightOffset);// add a right or left offset if desired too
Vector3 _3rdPersonCamTarget = playerWorldMatrix.Translation;//you can offset this similarly too if desired
view = Matrix.CreateLookAt(_3rdPersonCamPosition, _3rdPersonCamTarget , Vector3.Up);
If your FPS cam is working properly and assuming it is essentially the same location and orientation as the player, you can substitute it's view matrix in place of the playerWorldMatrix above like this:
Matrix FPSCamWorld = Matrix.Invert(yourWorkingFPSviewMatrixHere);
Now wherever I wrote playerWorldMatrix you can use FPSCamWorld instead.
If I were you, I would take your now-working FPS camera (I'm assuming that moves properly, has a positional matrix, etc?), and add another Translation Transform to it to "move it" back behind the player.
Put another way:
If your "translation/view matrix" for the FPS view is something like:
(sorry, haven't played with XNA in a while, so don't remember proper class names)
var camTranslateMatrix = [matrix representing player position];
var camDirectionMatrix = [matrix representing player direction, etc];
var camViewMatrix = camTranslateMatrix * camDirectionMatrix;
Then you could change it like so:
var camTranslateMatrix = [matrix representing player position];
var camDirectionMatrix = [matrix representing player direction, etc];
// If not in 3rd person, this will be identity == no effect
var camThirdPersonMatrix =
IsInThirdPersonMode ?
new TranslateMatrix(back a bit and up a bit) :
IdentityMatrix();
var camViewMatrix =
camTranslateMatrix *
camDirectionMatrix *
camThirdPersonMatrix;
Make sense? That way, it'd be trivial to toggle between the two views without tons of nasty math each time you do so.
Okay, so I am trying to simulate the collision of balls on a 2-Dimensional plane. I can detect the collisions pretty easily using a simple comparison of positions and the sum of radii, however, sometimes the simulation gets ahead of itself and the circles overlap, which plays havoc with the rest of the simulation.
So I have figured that finding the normal vector between the two circles at the point of contact and adding onto the position vectors in that direction is what I need to do basically, and luckily I had a similar algorithm handling the velocity changes due to collisions so I adapted it thusly:
Vector2 normal = orgA.getCenterPosition() - orgB.getCenterPosition();
Vector2 tangent = new Vector2((normal.Y * -1), normal.X);
float diff = (orgA.getRadius() + orgB.getRadius()) - normal.Length();
normal.Normalize();
float PAn = Vector2.Dot(normal, orgA.position);
float PAt = Vector2.Dot(tangent, orgA.position);
PAn += diff;
float PBn = Vector2.Dot(normal, orgB.position);
float PBt = Vector2.Dot(tangent, orgB.position);
PBn -= diff;
Vector2 PA = (PAn * normal) + (PAt * tangent);
Vector2 PB = (PBn * normal) + (PBt * tangent);
orgA.position = PA;
orgB.position = PB;
The trouble is that when I run the simulation, and two balls meet, the whole thing goes crazy and they're suddenly going all over the shop.
Can anyone see the flaw in my algorithm? I've looked at it loads and I still can't find what's causing this.
Hey buddy i think what you need is a loop. Its going crazy because once the balls touch they are constantly being upgraded with a new logic....
im not amazing at this but try putting the collision in a loop... should look something like this:
if ( diff < (orb radius))
{
Vector2 PA = (PAn * normal) + (PAt * tangent);
Vector2 PB = (PBn * normal) + (PBt * tangent);
orgA.position = PA;
orgB.position = PB;
}
something like that... I really hope this helps a little :/
from my understanding is this is in your update method, so keep in mind update runs constantly every millisecond... so its fine when your getting the difference between the spheres and sizes but after they collide and you you want them to move in a certain way you are calculating the same equation over and over...
Better yet make a bool such as isCollided and make sure you switch that true/false according to that statement
hope it helps i have an example project of collision if you want i can send it to you, samerhachem#hotmail.com