libGDX cone rotation while maintaing location in X,Y,Z - java

I am trying to create some sort of "lighthouse" effect by creating a cone and rotating it around the X/Y. The result "runs off" on the Z axis and is also wrong on the Y/X axis if there is a combination of both a Yaw and Pitch degrees.
(The Z axis goes from right to left, X towards the screen, Y upwards).
The yellow cone is the effect. it starts as the see-through cone.
This is hoe the x,y,z locations of the cone are set:
float c = this.height/2;
this.locationX = player.getPosition().x - c*((float)Math.sin(Math.toRadians(tiltOnY)));
this.locationY = player.getPosition().y + c*((float)Math.sin(Math.toRadians(tiltOnX)));
this.locationZ = player.getPosition().z-c;
where height is the height of the cone, and tilt starts at 0 and is added or reduced (as a result of input) with module of 360 degrees.
This is the code in render:
inst = new ModelInstance(this._game_.viewConeModel);
inst.transform.setToTranslation(cone.getX(),cone.getY(),cone.getZ())
.rotate(Vector3.Y,cone.getTiltOnY()).rotate(Vector3.X,cone.getTiltOnX()).rotate(Vector3.X,90);
this._game_.modelBatch.render(inst,this._game_.environment);
The desired result is that the point of the cone remains in the same location, but the cone itself rotates by the tilts on X and Y axis.

Related

How to calculate a point out of an angle and a distance?

I searched and implemented things from this forum, it doesn't come out right.
What I'm trying to achieve is to calculate a spawnPoint for player bullets relative to his position and rotation.
The spawnPoint should be and his X + his width (the player is set to point to the right by default) and y + height/2 (to spawn from his center on the Y axis).
This is what I got from this forum:
this.bulletSpawn.x = (float)(this.position.x + this.width/2 + this.width * Math.cos(rotation));
this.bulletSpawn.y = (float)(this.position.y + this.height/2 + this.height/2 * Math.sin(rotation));
The rotation is in Radians. The this is the Player class.
Images showing what I expect to happen:
Original Position
Expected Behaviour
The red dot is the spawnPoint I'm trying to calculate knowing the player position and rotation.
The player Sprite is what rotates, and it rotates related to his center x and y, which is done with a lib, i do not have these variables. The entire arrow would be the player , the arrow direction is where the player is pointing at, and the red dot would be the bulletSpawn point (or the expected one)
Using the code I posted, the bullets seem to be spawning from somewhere else. Even at the beggining they have an offset and when I rotate the player the spawnPoint seems to be relative to a different origin than what I'm expecting.
This is the bullet position code:
position.x = holder.bulletSpawn.x - (float)(this.width/2 * holder.rotation);
position.y = holder.bulletSpawn.y - (float)(this.height/2 * holder.rotation);
This is inside the Bullet class. The position variable is a Vector2 of bullet, and holder is the player instance. This code is merely to give an offset for the bullet to spawn at the center of its own size
I added some fixes related to the comments, but the bullets still have a tiny offset that looks wrong at certain angles.
Basically the distance i want to get is the width of the player, and his center y which is height/2.
Let's initial position is X0, Y0, rotation is about center point CX, CY, and rotation angle is Theta. So new position after rotation is:
NX = CX + (X0-CX) * Cos(Theta) - (Y0-CY) * Sin(Theta)
NY = CY + (X0-CX) * Sin(Theta) + (Y0-CY) * Cos(Theta)
This equations describe affine transformation of rotation of arbitrary point about center point, and affine matrix is combination of translation, rotation, and back translation matrices.
About center CX, CY - you wrote
it rotates related to his x and y origin at his bottom left
About initial point coordinate - for bullet it seems to be
X + Width, Y + Height/2
Swift extension:
extension CGSize {
static func offsetFrom(angle:CGFloat, distance:CGFloat) -> CGSize {
let rad = angle * CGFloat.pi / 180
return CGSize(width: sin(rad) * distance, height: cos(rad) * distance)
}
}

How to rotate points without moving them?

I need to rotate a triangle so that it lies on a plane given by a normal n and a constant d.
I have the normal n1 of the plane that the two triangles lie in. Now i need to rotate the right red triangle so that it results in the orange one.
The points of the triangles and the normals are stored as 3-dimensional vectors.
Until now, I did the following:
Get the normalized rotation quaternion (rotQuat) between n1 and n2.
Multiply every point of the triangle by the quaternion. Therefore I convert the point to a quaternion(point.x, point.y, point.z, 0) and do the multiplcation as follows: resultQuat = rotQuat * point * conjugate(rotQuat). I then apply x, y and z of the result to the point.
This is how i get the rotation between two vectors:
public static Quaternion getRotationBetweenTwoVector3f(Vector3f vec1, Vector3f vec2)
{
Vector3f cross = Vector3f.cross(vec1, vec2);
float w = (float) (java.lang.Math.sqrt(java.lang.Math.pow(vec1.getLength(), 2) * java.lang.Math.pow(vec2.getLength(), 2)) + Vector3f.dot(vec1, vec2));
Quaternion returnQuat = new Quaternion(cross.x, cross.y, cross.z, w);
returnQuat.normalize();
return returnQuat;
}
The problem is that the triangle has the correct orientation after the rotation, but the triangle also moves it's position. I need a rotation that rotates the triangle so that it's still connected to the two points of the left red triangle (like the orange one).
How is this possible?
Your problem is that rotation matrix/quaternions rotate points around an axis that passes through the origin. To rotate around different point than the origin, you need to translate the triangle points to the origin (just Substract the rotation point value from the triangle points), then multiply by the quaternion and then translate back.
So the algorithm becomes:
translatedPoints[i] = triPoints[i] - rotationPoint;
translatedPoints rotate using quaternion
translate translatedPoints back by adding the rotation point value.

How to make a circle move in circles?

Circle c1 = new Circle(20);
c1.relocate(200,200); //Set X and Y
What I want to do is make the circle move in circles around an invisible center of rotation. How can that be achieved?
Thanks.
Edit: I have extremely poor trigonometry skills.
You can use equations for a point on a circle using polar coordinates:
circle_x = rot_center_x + radius * cos(angle)
circle_y = rot_center_y + radius * sin(angle)
Using this you'll get a center point for your new circle. Then you just need to increase (counter clock wise) or decrease (clockwise) your angle, blank screen and draw the circle again.
The angle for trigonometric function is in radians, you have 2*pi radians in a full circle. So if you want angle zero degrees, put in 0. For 90 degrees, put in pi/2.0.
For any other angle use this conversion formula:
angle_rad = pi/180.0 * angle_degrees
If you want to time your rotation you have to choose the angular speed of rotation omega.
omega = 2*pi*f
where f is frequency of rotation, for example f=1Hz means your object will rotate in full circle after one seecond. Omega is in radians per second, so if you have omega 10 radians, then your object will rotate 10 radians during one second, or 100 radians during 10 seconds.
Now you have to determine how much angle you need to add each frame of animation:
ang_inc = omega / fps_avg;
ang += ang_inc;
where fps_avg is measured average of frames per second.

LWJGL: Rotate quad based on mouse position

I am trying to have a character hold a gun, but I want the gun to move with the mouse. For example, if the mouse is up, the gun points up. If the mouse is to the left, the gun points to the left. I used the player position and the mouse position to construct a right triangle, then used inverse sine to find the angle of elevation. However, this only works for 90 degrees of movement. Any ideas of how else I could approach this so that I get a full 360 degrees of rotation?
Code for calculating the angle:
private double calcAngle()
{
double mouseX,mouseY,subX,subY,playerToMouse,mouseToSub,angle;
mouseX = Mouse.getX();
mouseY = Mouse.getY();
subX = mouseX;
subY = y;
playerToMouse = Math.sqrt(Math.pow(x-mouseX,2)+Math.pow(y-mouseY,2));
mouseToSub = Math.sqrt(Math.pow(mouseX-subX,2)+Math.pow(mouseY-subY,2));
angle = Math.toDegrees(Math.asin(mouseToSub/playerToMouse));
return angle;
}
Current rotation (Pink represents player; Green represents gun; Yellow represents mouse):
You can use Math.atan2(mouseY-gunY, mouseX-gunX) which will return an angle between pi and -pi radians, or 180 and -180 degrees after you convert it to degrees. The problem with using asin is that 1/1 is equal to -1/-1 which makes it impossible for the function to tell them apart, and you want different results in each case.

how can I rotate an opengl 3d object to point to a GPS position (lat, long)?

I have a 3D arrow drawn with OpenGL that points to the coordinates (0, 0, 0) and I want it to point to a specific GPS location depending on my GPS position and Orientation.
I've tried calculating the azimuth (with my phone's orientation) and adjusting it to be the real north (not the magnetic north).
SensorManager.getOrientation(remappedRotationMatrix, orientation);
// convert radians to degrees
float azimuth = orientation[0];
azimuth = azimuth * 360 / (2 * (float) Math.PI);
GeomagneticField geoField = new GeomagneticField(
Double.valueOf(loc.getLatitude()).floatValue(),
Double.valueOf(loc.getLongitude()).floatValue(),
Double.valueOf(loc.getAltitude()).floatValue(),
System.currentTimeMillis());
// converts magnetic north into true north
azimuth -= geoField.getDeclination();
Then getting the bearing from my Location to the Location I want to point.
target.setLatitude(42.806484);
target.setLongitude(-1.632482);
float bearing = loc.bearingTo(target); // (it's already in degrees)
if (bearing < 0) {
bearing = bearing + 360;
}
float degrees = bearing - azimuth;
if (degrees < 0) {
degrees = degrees + 360;
}
and calculating the degrees I have to rotate the arrow
gl.glRotatef(degrees, 0.0f, 1.0f, 0.0f);
arrow.draw(gl);
Is there someway to do it? Could another possibility be to convert the GPS position to the OpenGL coordinates and use GLU.gluLookAt to point to it?
Thanks.
This seem to be purely a math problem.
Your question is pretty vague, I don't think I can help you without understanding more precisely how your scene is set up and what you want.
Do you know how to use 3D rotation matrices? If not, you probably should learn how they work.
It shouldn't be complicated to calculate the bearing and then rotate the arrow by the degrees you get. I have done the same in 2D although not in OpenGL. I based my code on the Radar sample (http://apps-for-android.googlecode.com/svn/trunk/Radar/). Here is how I draw the 2D arrow:
double bearingToTarget = mBearing - mOrientation;
// Draw an arrow in direction of target
canvas.rotate((float) bearingToTarget, center, center);
final int tipX = center;
final int tipY = center-radius;
canvas.drawLine(center, center, tipX, tipY, mArrowPaint);
final int tipLen = 30;
final int tipWidth = 20;
Path path = new Path();
path.moveTo(tipX, tipY);
path.lineTo(tipX + tipWidth/2, tipY + tipLen);
path.lineTo(tipX - tipWidth/2, tipY + tipLen);
path.lineTo(tipX, tipY);
path.close();
canvas.drawPath(path, mArrowPaint);
canvas.restore();
mBearing is calculated using the method GeoUtils.bearing from the Radar sample which takes care of the complicated math. mOrientation is just the orientation from the sensor listener. So the idea is to compute the difference between the bearing of the GPS location you want to point to (mBearing) and the current orientation of the phone (mOrientation). This gives us the angle bearingToTarget. We then rotate the view about its center by that angle before drawing the arrow along the y axis. This is the same as drawing the arrow rotated by bearingToTarget degrees.
You should be able to apply the same logic in OpenGL by rotating the view about the center of the screen by bearingToTarget degrees before you draw the arrow. Exactly what point you rotate about depends on how your view is set up. To make it simple, make the starting point of your arrow at the origin. Then you can simply rotate about the origin using glRotatef. Otherwise you would first need to translate to the center of the rotation, rotate and then translate back again (this is the common OpenGL technique for rotation about a point).

Categories