I am trying to rotate my perspective camera around my model. The model is at the centre (0,0,0) point. This is my rotate camera method:
private void rotateCameraAroundModel() {
camera.position.set(0,0,0);
camera.position.rotate(Vector3.Y, 5);
camera.position.add(0f, 0f, 200f);
camera.up.set(Vector3.Y);
camera.lookAt(0,0,0);
camera.update();
}
I am trying to go to the centre, rotate by 5 degrees, then return to the same distance away. However, the rotate doesn't seem to be working and I can't figure out why, any help is greatly appreciated.
I figured it out :)
private void rotateCameraAroundModel(float angle) {
camera.position.set(centreX, centerY, centerZ);
camera.rotate(Vector3.Y, (float) Math.toDegrees(angle)); // Rotate around Y axis by angle in degrees
float x = (float) (centerX + radius * (Math.sin(totalPhi)));
float z = (float) (centerZ + radius * (Math.cos(totalPhi)));
camera.position.add(x, 0f, z); //Move back out 2m using pythagorean theorem to calculate the position on the circle
camera.up.set(Vector3.Y);
camera.lookAt(0, 0, 0);
camera.update();
}
So I needed to calculate the new position on the circle whilst rotating, which I did using some basic trigonometry
Related
i'm creating an android app(top-down shooter) on libgdx and have a problem with bullet positioning(No, with math for real)
So the problem is calculating a position of bullet
I want to spawn bullet here:
example
(where the red line is)
I calculating a position as:
bullet.setPosition(world.getPlayer().getX() + world.getPlayer().getWidth() * (float) Math.cos(Math.toRadians(world.getPlayer().getRotation())),
world.getPlayer().getY() + world.getPlayer().getHeight() * (float) Math.sin(Math.toRadians(world.getPlayer().getRotation())));
And it works well while rotation = 0, but as soon as i start to rotate my player it goes wrong :(
I am assuming that your player object is a libGDX Sprite. Therefore, the getX and getY are the coordinates of the bottom-left corner of the sprite and the getRotation is the rotation of the sprite about the origin (assumed to be at the centre of the player).
By doing some basic trigonometry you can convert the angle and a displacement to an (x,y) coordinate as you have attempted. The bullet needs to be rotated about the centre of the player. This can be done with the following code:
Sprite player = world.getPlayer(); //Just to tidy up the code
//Half width, half height and rotation
float hw = player.getWidth() / 2.0f;
float hh = player.getHeight() / 2.0f;
float rot = Math.toRadians(player.getRotation());
bullet.setPosition(player.getX() + hw + hw * (float) Math.cos(rot),
player.getY() + hh + hh * (float) Math.sin(rot));
after creating a very simple animation using libGDX i have some questions I'd like to clarify in order to make sure I understand everything prior to start with any other development with more complexity.
I have a box created like this:
public void createBaseCube(Model modelCube) {
ModelBuilder modelBuilder = new ModelBuilder();
modelCube = modelBuilder.createBox(1f, 1f, 1f,
new Material(ColorAttribute.createDiffuse(Color.GREEN)),
VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal);
this.cubeInstance.transform.translate(0.5f, 0.5f, 0.5f);
}
As it is centered in position (0,0,0) and a want its corner to be allocated in (0, 0, 0) I applied the translation in last line.
Here is how it looks like (I added a set of tiles to have some reference):
Afterwards, I create the animation. I want to overturn the box, so it will be positioned over the white tile, and rotating over its bottom-right edge
public class CubeAnimation {
...
<<definition of attributes>>
...
public CubeAnimation (ModelInstance cubeModel, float fromAngle, float toAngle, float speed, float alpha){
this.cubeInstance = cubeModel;
this.fromAngle = fromAngle; //value set to 0
this.toAngle = toAngle; //value set to 90f
this.speed = speed; //value set to 1f
this.alpha = alpha; //value set to 0
}
public void update(float delta) {
alpha += delta * speed;
if (alpha >= 1f) {
finished =true;
return;
}
float angle = alpha * (toAngle - fromAngle);
fromAngle = angle;
Vector3 t = new Vector3(0.5f, -0.5f, 0);
cubeInstance.transform.idt().translate(t).rotate(Vector3.Z, -angle).translate(t.scl(-1));
}
Everything seems to be fine, and code is quite simple, BUT (and here are the issues) when applying the animation, the box is translated to the center again (so first translate when box was created is undone), and -surprise- although I'm passing 90f as parameter to the animation, cube only rotates 45 degrees (when I set 180, it rotated as expected: 90).
Here how it looks like after the animation:
What is wrong here? Thanks in advance for your help!
You want to rotate the cube from angle fromAngle to angle toAngle
You are attempting to do so gradually by calculating the percentage completed over time, stored in your alpha variable.
alpha += delta * speed;
if (alpha >= 1f) {
finished =true;
return;
}
This part is fine for calculating the percentage as an angular-velocity multiplied by time passed. ie
angle_percentage/seconds * seconds_passed
You then get the distance between the start and stop angles in this line
float angle = alpha * (toAngle - fromAngle);
This code works for a starting angle of 0, but will fail for non zero starting points. The equation for a line is y = mx + b, so to correct this, you should include the b value:
float angle = fromAngle + alpha * (toAngle - fromAngle);
This will start the animation at fromAngle and push it over the distance required.
The extra line fromAngle = angle; changes your starting location on every iteration, so you end up with an unpredictable animation, which will be different depending on the speed you choose... I'm fairly certain the factor of two is merely a coincidence ;)
Finally this loop ends when the value is set to 100%, but never actually updates to 100%. Try this instead.
public void update(float delta) {
alpha += delta * speed;
if (alpha <= 1f) {
float angle = fromAngle + alpha * (toAngle - fromAngle);
Vector3 t = new Vector3(0.5f, -0.5f, 0);
cubeInstance.transform.idt().translate(t).rotate(Vector3.Z, -angle).translate(t.scl(-1));
} else {
finished = true;
}
}
I am making a space game for a school project and my ships' AI rely on the ability to move towards another ship. My current implementation does not work because it rotates the ship to both directions of my destination vector, so occasionally it attacking ship will go in the exact opposite direction, while other times it will go the correct direction. Any feedback would be greatly appreciated!
//ship heading (already calculated)
Vector3f heading /* = ... */;
heading.normalize();
//direction of enemy ship relative to ours
Vector3d direction = new Vector3f(enemy.x - ship.x, enemy.y - ship.y, enemy.z - ship.z);
direction.normalize();
//angle between vectors
float angle = heading.angle(direction);
//axis to rotate upon
Vector3f axis = new Vector3f();
axis.cross(heading, direction);
axis.normalize();
//initialize matrix to hold rotation
Matrix4f rot = new Matrix4f();
rot.setIdentity();
//rotate the ship if we are more than 10 deg off
if (angle > Math.toRadians(10)) {
rot.setRotation(new AxisAngle4f(axis, rotationVelocity * deltaTime));
}
Alright I have figured out a better way to do it, which involves some linear interpolation.
The following still remains the same:
//ship heading (already calculated)
Vector3f heading /* = ... */;
heading.normalize();
//direction of enemy ship relative to ours
Vector3d direction = new Vector3f(enemy.x - ship.x, enemy.y - ship.y, enemy.z - ship.z);
direction.normalize();
//angle between vectors
float angle = heading.angle(direction);
Now I calculate the percent of heading vector to be interpolated to the direction vector:
//calculate angle to rotate
float deltaRotation = rotationVelocity * deltaTime;
//calcuate percent of rotation
float percent = Math.min(deltaRotation / angle, 1.0f);
//create interpolated vector representing the new forward direction
Vector3f inter = new Vector3f(heading.x + percent * (direction.x - heading.x), heading.y + percent * (direction.y - heading.y), heading.z + percent * (direction.z - heading.z));
inter.normalize();
Now we can create the new rotation matrix:
//the object's default forward size without any transformations
Vector3f forward = new Vector3f(0.0f, 0.0f, 1.0f);
//rotation axis
Vector3f axis = new Vector3f();
axis.cross(forward, inter);
axis.normalize();
//New rotation matrix to be applied
Matrix4f rotationMatrix = new Matrix4f();
rotationMatrix.setIdentity();
rotationMatrix.setRotation(new AxisAngle4f(axis, forward.angle(inter)));
Now my ship always faces the correct direction! :)
Can someone tell me why my camera class isn't working correctly? I set the position vector to (0,0,-10) and the look at vector to (0,0,0) but when I draw something on (0,0,0) it isn't there. I'm very new to vector math and matrix stuff, so I'm betting it's LookThrough() where the problem is.
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.Matrix3f;
import org.lwjgl.util.vector.Vector3f;
public class Camera {
//3d vector to store the camera's position in
Vector3f position = null;
Vector3f lookAt = null;
//the rotation around the Y axis of the camera
float yaw = 0;
//the rotation around the X axis of the camera
float pitch = 0;
//the rotation around the Z axis of the camera
float roll = 0;
public Camera(float x, float y, float z)
{
//instantiate position Vector3f to the x y z params.
position = new Vector3f(x, y, z);
lookAt = new Vector3f();
}
public void lookThrough()
{
Matrix3f m = new Matrix3f();
Vector3f out = new Vector3f();
Vector3f.sub(position, lookAt, out);
out.normalise();
//set forward vector
m.m00 = out.x;
m.m01 = out.y;
m.m02 = out.z;
//set right vector
m.m10 = 1;
m.m11 = 0;
m.m12 = 0;
//set up vector
m.m20 = 0;
m.m21 = 1;
m.m22 = 0;
yaw = (float) -(Math.tan(m.m10/m.m00));
pitch = (float) -(Math.tan((-m.m20)/(Math.sqrt(Math.pow(m.m21, 2) + Math.pow(m.m22, 2)))));
roll = (float) -(Math.tan(m.m21/m.m22));
//roatate the pitch around the X axis
GL11.glRotatef(pitch, 1.0f, 0.0f, 0.0f);
//roatate the yaw around the Y axis
GL11.glRotatef(yaw, 0.0f, 1.0f, 0.0f);
//roatate the yaw around the Y axis
GL11.glRotatef(roll, 0.0f, 0.0f, 1.0f);
//translate to the position vector's location
GL11.glTranslatef(position.x, position.y, position.z);
}
}
There are a couple of things about your class that I would highlight:
1) You are fixing your 'right' and 'up' vectors, leaving only one degree of rotational freedom. As the camera re-orients in 3D space these will need to change. As it stands, your calculation for pitch always evaluates to 0, while your calculation to roll always evaluates to tan(1/0).
2) Though I'm not familiar with Java, you appear to be using the calculation (position - lookAt) to derive your forward vector. Ought it not be the reverse? The forward vector points away from the viewer's position.
3) Again - not familiar with java - but calling pow() to do a single multiplication is likely overkill.
1 & 2 could be the cause of your woes. Ultimately I would suggest taking a look at gluLookAt - assuming the GLU library is available in Java. If it is not, then look at the source code for gluLookAt (one variant is available here).
Alright, so this is how I am doing it:
float xrot = 0;
float yrot = 0;
float zrot = 0;
Quaternion q = new Quaternion().fromRotationMatrix(player.model.getRotation());
if (q.getW() > 1) {
q.normalizeLocal();
}
float angle = (float) (2 * Math.acos(q.getW()));
double s = Math.sqrt(1-q.getW()*q.getW());
// test to avoid divide by zero, s is always positive due to sqrt
// if s close to zero then direction of axis not important
if (s < 0.001) {
// if it is important that axis is normalised then replace with x=1; y=z=0;
xrot = q.getXf();
yrot = q.getYf();
zrot = q.getZf();
// z = q.getZ();
} else {
xrot = (float) (q.getXf() / s); // normalise axis
yrot = (float) (q.getYf() / s);
zrot = (float) (q.getZf() / s);
}
But it doesn't seem to work when I try to put it into use:
player.model.addTranslation(xrot * player.speed, 0, zrot * player.speed);
AddTranslation takes 3 numbers to move my model by than many spaces (x, y, z), but hen I give it the numbers above it doesn't move the model in the direction it has been rotated (on the XZ plane)
Why isn't this working?
Edit: new code, though it's about 45 degrees off now.
Vector3 move = new Vector3();
move = player.model.getRotation().applyPost(new Vector3(1,0,0), move);
move.multiplyLocal(-player.speed);
player.model.addTranslation(move);
xrot, yrot, and zrot define the axis of the rotation specified by the quaternion. I don't think you want to be using them in your addTranslation() call...in general, that won't have anything to do with the direction of motion.
What I mean by that is: your 3-D object -- let's say for the sake of argument that it's an airplane -- will have a certain preferred direction of motion in its original coordinate
system. So if the original orientation has the center of mass at the origin, and the
propeller somewhere along the +X axis, the plane wants to fly in the +X direction.
Now you introduce some coordinate transformation that rotates the airplane into some other orientation. That rotation is described by a rotation matrix, or equivalently, by a
quaternion. Which way does the plane want to move after the rotation?
You could find
that by taking a unit vector in the +X direction: (1.0, 0.0, 0.0), then applying the
rotation matrix or quaternion to that vector to transform it into the new coordinate
system. (Then scale it by the speed, as you're doing above.) The X, Y, and Z components
of the transformed, scaled vector give the desired incremental motion along each axis. That transformed vector is generally not going to be the rotation axis of the quaternion, and I think that's probably your problem.