Choosing which side to rotate - c++

I'm implementing a homing bullet that targets the nearest enemy.
I'm able to calculate the angle between the player's forward vector and the vector from the player to the target by doing a dot product.
If I put the result to acos(), it will give me the angle between the 2 vectors in terms of radian.
Now I want my object to rotate and face toward the enemy as it is flying. But here comes the problem, how do I know which side to rotate to? I know the angle between the 2 vectors, but I dot producted value doesnt tell me whether or not the target is on the left side or right side of the player.
I'm wondering if I'm taking a longer route, and I might not be aware of a easier way to determine how much and to which side I need to rotate to face the target.

You can calculate dot product for side vector like this:
vector Side( Front.Y, -Front.X );
float dotSide = dot( Target, Side );
if( dotSide <= 0 )
{
// one side
}
else
{
// another side
}

If I understand you right, you want to get the direction, in which your spaceship vecS should rotate in order to look at the target vecT.
I would suggest to calculate the angle alpha, which vecS and the x-axis enclose, as well as the angle beta, which vecT and the x-axis enclose.
If alpha is greater than beta you would rotate to the right, otherwise to the left.
Here is the pseudocode to calculate the angle and the proper rotation direction:
// Pseudocode:
alpha = arctan( vecS.y / vecS.x );
beta = arctan ( vecT.y / vecS.x );
if(alpha > beta)
// Rotate right by alpha - beta
else
// Rotate left by alpha - beta

Related

Move 3d object right/left + up/down independent of its rotation

Goal:
Move a 3D object as if it is in 2D space (screen). So if the user moves the mouse left the object should move left (the same should apply for all other directions: right, up, down).
Description:
I am working with OpenTK (OpenGL - 3D space)
Since the object itself should always rotate around it's center I first apply the rotation then the translation matrix.
What works
With trying out I was able to get the translation for the x-Axis and y-Axis (both 2d space) working separately.
// works for x-Axis movement
var rotation = _control.Rotation;
// vector is a 2d vector that contains the vector from the mouse drag start position
// (so the pixels the mouse was moved from the drag start to its current position)
// factor is a value that depends on the current zoom value - can be ignored for the problem itself
var xTranslationVector = new Vector3(
vector.X * (float)Math.Cos(rotation.Y) * factor,
0,
vector.X * (float)Math.Sin(rotation.Y) * factor);
// initial value is the original translation on drag start
_control.Translation = initialValue + xTranslationVector;
// vector for y-Axis
var yTranslationVector = new Vector3(0,
-vector.Y * (float) Math.Cos(rotation.X) * factor,
vector.Y * (float) Math.Sin(rotation.X) * factor);
// _control.Translation = initialValue + yTranslationVector;
Both work when used independent from each other.
Questions
How do I need to combine the xTranslationVector and yTranslationVector so that it would work as expected (multiplication doesn't work because any vector component could be 0 which results in no movement at all; addition does not work when the object is rotated around some axis partially)
I would like to understand what I am doing there, what are the mathematical terms i should look for to find explanations?
How can I do the same for rotation (f.e. the object is rotated 45° degrees around the y axis and I want to rotate - currently the object would tilt around it's x axis but i would like to tilt it always as if the object was not rotated around it's x axis - sorry not sure how to word this well)

How to use Analogue Sticks (joystick) output values to rotate an object using transform matrix?

Given that analog stick outputs values
float xaxisval = controller->left_stick_x_axis(); //-1 is left, 1 is right
float yaxisval = controller->left_stick_y_axis(); //-1 is up, 1 is down
Values go from 0 to 1 with which can be used for sensitivity.
I'm moving the character in the direction of the joystick in a 3D environment the same way you would in a game like Diablo. I'm adding and retracting these values from X and Z position to move him. But the character is always facing the same dierection.
How can I use these values and convert them into degrees?
xaxisval += controller->left_stick_x_axis() /100;
yaxisval += controller->left_stick_y_axis() /100;
distAdjust.SetTranslation(Vector4(xaxisval, 0, yaxisval));
rotateAdjust.RotationX(rotateDegrees);
player_->set_transform(player_transform *distAdjust *rotateAdjust)
Problem I have is the movement only works with fixed rotation, if I rotate the object then it moves into a different direction.
I don't know what your function "rotateAdjust.RotationX(rotateDegrees);" really do.
But, you should for every game cycle take the value from 0 to 1 from your joystick, then multiply it by a constant angle depending of your rotation speed.
const float Angle = 1.0f; // Or whatever you want. Set more to increase rotation speed.
...
// Game loop
while ( true )
{
...
float xSensitivity = controller->left_stick_x_axis(); // example 0.33f for that cycle
myGuy.xRotate(Angle * xSensitivity);
...
}
"Angle" is a constant and can be expressed in degree or radian depending of your rotation function.

Ellipse rotated not centered

I am trying to draw a rotated ellipse not centered at the origin (in c++).
so far my code "works":
for (double i = 0; i <= 360; i = i + 1) {
theta = i*pi / 180;
x = (polygonList[compt]->a_coeff / 2) * sin(theta) + polygonList[compt]->centroid->datapointx;
y = (polygonList[compt]->b_coeff / 2) * cos(theta) + polygonList[compt]->centroid->datapointy;
xTmp = (x - polygonList[compt]->centroid->datapointx)* cos(angle1) - (y - polygonList[compt]->centroid->datapointy)*sin(angle1) + polygonList[compt]->centroid->datapointx;
yTmp = (x - polygonList[compt]->centroid->datapointx)* sin(angle1) + (y - polygonList[compt]->centroid->datapointy)*cos(angle1) + polygonList[compt]->centroid->datapointy;
}
PolygonList is a list of "bloc" which will be replaced by an ellipse of same area.
My issue is that the angles are not quite exact, as if I had to put a protractor that'd fit the shape of my ellipse, the protractor would obviously get squeezed, and so would be the angles (is that clear ?)
Here is an example: I am trying to set a point on the top ellipse (E1) which would be lying on a line drawn between the centroid of E1, and any point on the second ellipse (E2).On this example, the point on E2 lies at an angle of ~220-230 degree. I am able to catch this angle, the angle seems ok.
The problem is that if I try to project this point on E1 by using this angle of ~225 degree, I end up on the second red circle on top. it looks like my angle is now ~265 degree, but in fact, if I shape the protractor to fit in my ellipse, I get the right angle (~225) ,cf img 2)
it is a bit hard to see the angle on that re-shaped protractor, but it does show ~225 degree.
My conclusion is that the ellipse is drawn like if I had to drew a circle and then I'd compress it, which changes the distance between the angles.
Could someone tell me how I could fix that ?
PS: to draw those ellipses I just use a for loop which plots a dot at every angle (from 0 to 360). we clearly see on the first picture that the distance between the dots are different whether we are at 0 or at 90 degree.
your parametrisation is exactly that, a circle is a case of ellipse with both axes are equal. It sounds like you need use rational representation of ellipse instead of standard: https://en.m.wikipedia.org/wiki/Ellipse
So, I've asked the question above so that I could find a possible overlap between 2 ellipses by checking the distance between any point on E2 and its projection on E1: if the distance between the centroid of E1 and the projected dot on E1 is larger than the distance between the centroid of E1 to a dot on E2 I'll assume an overlap. I reckon this solution has never been tried (or I haven't search enough) and should work fine. But before working I needed to get those angles right.
I have found a way to avoid using angles and projected dots, by checking the foci:
the sum of the distance between the focus A and B to any point around an axis is constant (let's call it DE1 for E1).
I then check the distance between my foci and any point on E2. If that distance becomes less than DE1, I'll assume a connection.
So far it seems to work fine :)
I'll put that here for anyone in need.
Flo

how to calculate which direction to rotate?

I'm trying to implement a simple AI system in my DirectX Application. I'm trying to get my Ai to rotate and face the direction I want it to face towards, which I manage to do, but can't figure out how to get it to determine how to rotate to the given direction (i.e should it rotate left or rotate right?).
Here is the code I've got which works out the angle it needs to rotate by to face the direction it's given:
D3DXVECTOR3 incident = destination - position;
float top = D3DXVec3Dot(&incident, &forwardVec);
float bottom = sqrt((incident.x * incident.x) + (incident.y * incident.y) + (incident.z * incident.z)) *
sqrt((forwardVec.x * forwardVec.x) + (forwardVec.y * forwardVec.y) + (forwardVec.z * forwardVec.z));
float remainingAngle = acos(top/bottom) * 180.0f / PI;
The forwardVec is a D3DXVECTOR3 of which way the AI is currently facing.
The dot product rule just tells you the shortest angle (which is always less than 180!), not which way to go. Do you have a way to get a direction angle out of a D3DXVECTOR (ie polar form kind of thing?) If so, then you can subtract (desired angle)-(current angle) and if that is within -180 to 180 go counterclockwise; otherwise, go clockwise.
I have a feeling that the cross product might also give a method, but I'd have to sit down with a piece of paper to work it out.
Let's suppose that straight ahead is 0 and you're counting degrees in a clockwise fashion.
If you need to turn 180 or less then you're moving right.
If you need to turn more than 180 you have to turn left. This turn is a left turn of 360 - value degrees.
I hope this answers your question.
The angle between 2 normalized vectors:
double GetAng (const D3DXVECTOR3& Xi_V1, const D3DXVECTOR3& Xi_V2)
{
D3DXVECTOR3 l_Axis;
D3DXVec3Cross(&l_Axis, &Xi_V1, &Xi_V2);
return atan2(D3DXVec3Length(&l_Axis), D3DXVec3Dot(&Xi_V1, &Xi_V2));
}
The returned angle is between -PI and PI and represents the shortest anglular rotation from v1 to v2.

Direct3D & iPhone Accelerometer Matrix

I am using a WinSock connection to get the accelerometer info off and iPhone and into a Direct3D application. I have modified Apples GLGravity's sample code to get my helicopter moving in relation to gravity, however I need to "cap" the movement so the helicopter can't fly upside down! I have tried to limit the output of the accelerometer like so
if (y < -0.38f) {
y = -0.38f;
}
Except this doesn't seem to work!? The only thing I can think of is I need to modify the custom matrix, but I can't seem to get my head around what I need to be changing. The matrix is code is below.
_x = acceleration.x;
_y = acceleration.y;
_z = acceleration.z;
float length;
D3DXMATRIX matrix, t;
memset(matrix, '\0', sizeof(matrix));
D3DXMatrixIdentity(&matrix);
// Make sure acceleration value is big enough.
length = sqrtf(_x * _x + _y * _y + _z * _z);
if (length >= 0.1f && kInFlight == TRUE) { // We have a acceleration value good enough to work with.
matrix._44 = 1.0f; //
// First matrix column is a gravity vector.
matrix._11 = _x / length;
matrix._12 = _y / length;
matrix._13 = _z / length;
// Second matrix is arbitrary vector in the plane perpendicular to the gravity vector {Gx, Gy, Gz}.
// defined by the equation Gx * x + Gy * y + Gz * z = 0 in which we set x = 0 and y = 1.
matrix._21 = 0.0f;
matrix._22 = 1.0f;
matrix._23 = -_y / _z;
length = sqrtf(matrix._21 * matrix._21 + matrix._22 * matrix._22 + matrix._23 * matrix._23);
matrix._21 /= length;
matrix._22 /= length;
matrix._23 /= length;
// Set third matrix column as a cross product of the first two.
matrix._31 = matrix._12 * matrix._23 - matrix._13 * matrix._22;
matrix._32 = matrix._21 * matrix._13 - matrix._23 * matrix._11;
matrix._33 = matrix._11 * matrix._22 - matrix._12 * matrix._21;
}
If anyone can help it would be much appreciated!
I think double integration is probably over-complicating things. If I understand the problem correctly, the iPhone is giving you a vector of values from the accelerometers. Assuming the user isn't waving it around, that vector will be of roughly constant length, and pointing directly downwards with gravity.
There is one major problem with this, and that is that you can't tell when the user rotates the phone around the horizontal. Imagine you lie your phone on the table, with the bottom facing you as you're sitting in front of it; the gravity vector would be (0, -1, 0). Now rotate your phone around 90 degrees so the bottom is facing off to your left, but is still flat on the table. The gravity vector is still going to be (0, -1, 0). But you'd really want your helicopter to have turned with the phone. It's a basic limitation of the fact that the iPhone only has a 2D accelerometer, and it's extrapolating a 3D gravity vector from that.
So let's assume that you've told the user they're not allowed to rotate their phone like that, and they have to keep it with the bottom point to you. That's fine, you can still get a lot of control from that.
Next, you need to cap the input such that the helicopter never goes more than 90 degrees over on it's side. Imagine the vector that you're given as being a stick attached to your phone, and dangling with gravity. The vector you have is describing the direction of gravity, relative to the phone's flat surface. If it were (0, -1, 0) the stick is pointing directly downwards (-y). if it were (1, 0, 0), the stick is pointing to the right of the phone (+x), and implies that the phone has been twisted 90 degrees clockwise (looking away from you at the phone).
Assume in this metaphor that the stick has full rotational freedom. It can be pointing in any direction from the phone. So moving the stick around describes the surface of a sphere. But crucially, you only want the stick to be able to move around the lower half of that sphere. If the user twists the phone so that the stick would be in the upper half of the sphere, you want it to cap such that it's pointing somewhere around the equator of the sphere.
You can achieve this quite cleanly by using polar co-ordinates. 3D vectors and polar co-ordinates are interchangeable - you can convert to and from without losing any information.
Convert the vector you have (normalised of course) into a set of 3D polar co-ordinates (you should be able to find this logic on the web quite easily). This will give you an angle around the horizontal plane, and an angle for vertical plane (and a distance from the origin - for a normalised vector, this should be 1.0). If the vertical angle is positive, the vector is in the upper half of the sphere, negative it's in the lower half. Then, cap the vertical angle so that it is always zero or less (and so in the lower half of the sphere). Then you can take the horizontal and capped vertical angle, and convert it back into a vector.
This new vector, if plugged into the matrix code you already have, will give you the correct orientation, limited to the range of motion you need. It will also be stable if the user turns their phone slightly beyond the 90 degree mark - this logic will keep your directional vector as close to the user's current orientation as possible, without going beyond the limit you set.
Try normalizing the acceleration vector first. (edit: after you check the length) (edit edit: I guess I need to learn how to read... how do I delete my answer?)
So if I understand this correctly, the iPhone is feeding you accelerometer data, saying how hard you're moving the iPhone in 3 axes.
I'm not familiar with that apple sample, so I don't know what its doing. However, it sounds like you're mapping acceleration directly to orientation, but I think what you want to do is doubly integrate the acceleration in order to obtain a position and look at changes in position in order to orient the helicopter. Basically, this is more of a physics problem than a Direct3D problem.
It looks like you are using the acceleration vector from the phone to define one axis of a orthogonal frame of reference. And I suppose +Y is points towards the ground so you are concerned about the case when the vector points towards the sky.
Consider the case when the iphone reports {0, -6.0, 0}. You will change this vector to {0, -.38, 0}. But they both normalize to {0, -1.0, 0}. So, the effect of clamping y at -.38 is influenced by magnitude of the other two components of the vector.
What you really want is to limit the angle of the vector to the XZ plane when Y is negative.
Say you want to limit it to be no more than 30 degrees to the XZ plane when Y is negative. First normalize the vector then:
const float limitAngle = 30.f * PI/180.f; // angle in radians
const float sinLimitAngle = sinf(limitAngle);
const float XZLimitLength = sqrtf(1-sinLimitAngle*sinLimitAngle);
if (_y < -sinLimitAngle)
{
_y = -sinLimitAngle;
float XZlengthScale = XZLimitLength / sqrtf(_x*_x + _z*_z);
_x *= XZlengthScale;
_z *= XZlengthScale;
}