I'm trying to use 3D in LibGDX however the camera flips upside down and nothing I do seems to prevent it with no known cause as to why it happens.
I've tested each axis of rotation individually and it works perfectly however when they both are used together it sometimes flips upside down.
public void create () {
environment = new Environment();
environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -2.5f, -5, -10));
modelBatch = new ModelBatch();
cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
cam.position.set(0, 0, 0);
cam.lookAt(-10,-10,-10);
cam.near = 1f;
cam.far = 300f;
cam.update();
ModelBuilder modelBuilder = new ModelBuilder();
model = modelBuilder.createBox(5, 5, 5,
new Material(ColorAttribute.createDiffuse(Color.GREEN)),
Usage.Position | Usage.Normal);
instance = new ModelInstance(model);
instance.transform.translate(-10, -10, -10);
Gdx.input.setCursorCatched(true);
Gdx.input.setCursorPosition(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2);
}
#Override
public void render () {
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
isup = false;
ispressed = false;
Vector3 direction = cam.direction.cpy();
Vector3 crossProduct = new Vector3(); //CROSSPRODUCT OF PLAYER DIRECTION AGAINST Y AXIS
crossProduct.x = -direction.z;
crossProduct.y = 0;
crossProduct.z = direction.x;
differencey = -Gdx.input.getY() + (Gdx.graphics.getHeight() / 2);
if ((cam.direction.y > -0.8 || differencey > 0) && (cam.direction.y < 0.8 || differencey < 0)) {
if (differencey > 50) {
differencey = 50;
}
cam.rotate(crossProduct, differencey / 10);
cam.update();
}
differencex = Gdx.input.getX() - (Gdx.graphics.getWidth() / 2);
cam.rotate(new Vector3(0, -1, 0), differencex / 10);
cam.update();
modelBatch.begin(cam);
modelBatch.render(instance, environment);
modelBatch.end();
Gdx.input.setCursorPosition(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2);
if (Gdx.input.isKeyPressed(Keys.ESCAPE)) {
Gdx.app.exit();
}
The camera movement should be restricted so that the camera cannot be moved upwards or downwards any further if the user is looking almost straight up or straight down respectively however the camera sometimes moves past this restriction anyway.
Related
I have been trying to make some 3d stuff with JOGL.
When rendering 2 2d boxes in the 3d plane FPS can drop to under 15
when I move the camera closer. I don't know exactly what is taking down the performance so much.
float camX = (float) Main.cameraX;
float camY = (float) Main.cameraY;
float camZ = (float) Main.cameraZ;
float camRotX = (float) Main.cameraRotX;
float camRotY = (float) Main.cameraRotY;
float camRotZ = (float) Main.cameraRotZ;
gl.glRotatef(camRotX, 1, 0, 0);
gl.glRotatef(camRotY, 0, 1, 0);
gl.glRotatef(camRotZ, 0, 0, 1);
gl.glTranslatef(x - camX, y - camY, z - camZ);
gl.glVertexPointer(3, GL2.GL_FLOAT, 0, verticesBuffer);
gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
gl.glDrawArrays(GL2.GL_TRIANGLES, 0, vertices.length / 3);
gl.glTranslatef(-x + camX, -y + camY, -z + camZ);
gl.glRotatef(-camRotZ, 0, 0, 1);
gl.glRotatef(-camRotY, 0, 1, 0);
gl.glRotatef(-camRotX, 1, 0, 0);
I am working on an Android application using OpenGL.
In a database, I store the rotation of objects using local Euler rotation, x, y, then z, but in the editor, I would like to apply a global rotation by the x, y or z global axis. I took two approaches, outlined below.
I've simplified these methods to remove irrelevant Android code.
I've tried taking the matrix approach, but the object appears to rotate in an axis not aligned with the global x, y or z after calling the method a second time. I've read somewhere that the floating point error builds up over time making the rotation matrix "numerically unstable", which I assume is what's happening in the first method.
// rotAxis = 0 means rotation around the X global axis
// rotAxis = 1 means rotation around the Y global axis
// rotAxis = 2 means rotation around the Z global axis
public void executeRotationWithMatrix(float rotAngle, int rotAxis){
float[] rotationMatrix = new float[16];
// Matrix class is in android.opengl
Matrix.setIdentityM(rotationMatrix, 0);
switch (rotAxis){
case 0:
Matrix.rotateM(rotationMatrix, 0, rotAngle, 1.f, 0.f, 0.f);
break;
case 1:
Matrix.rotateM(rotationMatrix, 0, rotAngle, 0.f, 1.f, 0.f);
break;
case 2:
Matrix.rotateM(rotationMatrix, 0, rotAngle, 0.f, 0.f, 1.f);
break;
}
float rotx = getLocalRotationOfObjectOnX(); // Pseudocode
float roty = getLocalRotationOfObjectOnY(); // Pseudocode
float rotz = getLocalRotationOfObjectOnZ(); // Pseudocode
Matrix.rotateM(rotationMatrix, 0, rotx, 1.f, 0.f, 0.f);
Matrix.rotateM(rotationMatrix, 0, roty, 0.f, 1.f, 0.f);
Matrix.rotateM(rotationMatrix, 0, rotz, 0.f, 0.f, 1.f);
Vector3f rotationVector = rotationMatrixToEulerAngles(rotationMatrix);
saveLocalRotationOfObjectOnX(rotationVector.x); // Pseudocode
saveLocalRotationOfObjectOnY(rotationVector.y); // Pseudocode
saveLocalRotationOfObjectOnZ(rotationVector.z); // Pseudocode
}
In the second method, I tried to take the rotation quaternion approach by applying the rotations, but I get even weirder results whenever I try to use this method.
// rotAxis = 0 means rotation around the X global axis
// rotAxis = 1 means rotation around the Y global axis
// rotAxis = 2 means rotation around the Z global axis
public void executeRotationWithQuat(float rotAngle, int rotAxisInd){
Quat4f rotationQuat = new Quat4f(0, 0, 0, 1);
Quat4f tempQuat = new Quat4f(0, 0, 0, 1);
switch (rotAxisInd){
case 0:
QuaternionUtil.setRotation(tempQuat, new Vector3f(1, 0, 0), rotAngle);
break;
case 1:
QuaternionUtil.setRotation(tempQuat, new Vector3f(0, 1, 0), rotAngle);
break;
case 2:
QuaternionUtil.setRotation(tempQuat, new Vector3f(0, 0, 1), rotAngle);
break;
}
tempQuat.normalize();
rotationQuat.mul(tempQuat);
rotationQuat.normalize();
float rotx = getLocalRotationOfObjectOnX(); // Pseudocode
float roty = getLocalRotationOfObjectOnY(); // Pseudocode
float rotz = getLocalRotationOfObjectOnZ(); // Pseudocode
QuaternionUtil.setRotation(tempQuat, new Vector3f(1, 0, 0), rotx); tempQuat.normalize();
rotationQuat.mul(tempQuat);
rotationQuat.normalize();
QuaternionUtil.setRotation(tempQuat, new Vector3f(0, 1, 0), roty); tempQuat.normalize();
rotationQuat.mul(tempQuat);
rotationQuat.normalize();
QuaternionUtil.setRotation(tempQuat, new Vector3f(0, 0, 1), rotz); tempQuat.normalize();
rotationQuat.mul(tempQuat);
rotationQuat.normalize();
float qw = rotationQuat.w;
float qx = rotationQuat.x;
float qy = rotationQuat.y;
float qz = rotationQuat.z;
float[] rotationMatrix = new float[]{
1.0f - 2.0f*qy*qy - 2.0f*qz*qz, 2.0f*qx*qy - 2.0f*qz*qw, 2.0f*qx*qz + 2.0f*qy*qw, 0.0f,
2.0f*qx*qy + 2.0f*qz*qw, 1.0f - 2.0f*qx*qx - 2.0f*qz*qz, 2.0f*qy*qz - 2.0f*qx*qw, 0.0f,
2.0f*qx*qz - 2.0f*qy*qw, 2.0f*qy*qz + 2.0f*qx*qw, 1.0f - 2.0f*qx*qx - 2.0f*qy*qy, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
Vector3f rotationVector = rotationMatrixToEulerAngles(rotationMatrix);
saveLocalRotationOfObjectOnX(rotationVector.x); // Pseudocode
saveLocalRotationOfObjectOnY(rotationVector.y); // Pseudocode
saveLocalRotationOfObjectOnZ(rotationVector.z); // Pseudocode
}
The following are helper methods used in the above two methods.
public Vector3f rotationMatrixToEulerAngles(float[] m){
float sy = (float)Math.sqrt(m[6]*m[6] + m[10]*m[10]);
float x, y, z;
x = (float)Math.atan2(m[6], m[10]);
y = (float)Math.atan2(-m[2], sy);
z = (float)Math.atan2(m[1], m[0]);
//convert angles from radians to degrees
float conFactor = (float)(180/Math.PI);
x *= conFactor;
y *= conFactor;
z *= conFactor;
return new Vector3f(x, y, z);
}
public class QuaternionUtil {
public static void setRotation(Quat4f q, Vector3f axis, float angle) {
float d = axis.length();
assert (d != 0f);
float s = (float)Math.sin(angle * 0.5f) / d;
q.set(axis.x * s, axis.y * s, axis.z * s, (float) Math.cos(angle * 0.5f));
}
}
public class Vector3f{
public final float length() {
return (float)Math.sqrt((double)(this.x * this.x + this.y * this.y + this.z * this.z));
}
}
Any help would be greatly appreciated!
My Y-axis is flip so it's in the top left corners, but this problem only occurs with the
bounds = new Rectangle()
I am using the OrthographicCamera like this
camera= new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
My question is, how do I flip the Y-axis so the (0,0) ends up in the Bottom-left corner
public class MyGdxGame extends ApplicationAdapter {
SpriteBatch batch;
Player player;
Player2 player2;
InputProcessor inputprocessor;
Texture img;
Vector2 pos;
Rectangle bounds;
GameTime gameTime;
ShapeRenderer sr;
Rectangle p1,p2,p3,p4;
Rectangle tSwitch;
Rectangle Bplayer;
Vector2 p;
Vector2 button1,button2,button3,button4;
Vector2 tButton;
BitmapFont font;
OrthographicCamera camera;
int xi = 0;
int yi = 0;
int Movetime = 0;
int playerSwitch = 0;
float totalTime = 3*60;
Rectangle touchPos;
#Override
public void create () {
camera= new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch = new SpriteBatch();
img = new Texture("badlogic.jpg");
player = new Player(new Vector2(Gdx.graphics.getHeight() / 2 , Gdx.graphics.getWidth() / 2),"badlogic.jpg");
player2 = new Player2(new Vector2(Gdx.graphics.getHeight() / 2 , Gdx.graphics.getWidth() / 2),"Fagot.jpg");
pos = new Vector2(player.getPosition().x,player.getPosition().y);
gameTime = new GameTime();
button1 = new Vector2(0,0);
button2 = new Vector2(200,0);
button3 = new Vector2(1620,0);
button4 = new Vector2(1820,0);
tButton = new Vector2(800,0);
p1 = new Rectangle(button1.x + 100,button1.y+1225,100,100);
p2 = new Rectangle(button2.x + 100,button2.y+1225,100,100);
p3 = new Rectangle(button3.x + 100,button3.y+1225,100,100);
p4 = new Rectangle(button4.x + 100,button4.y+1225,100,100);
Bplayer = new Rectangle(player2.getPosition().x,player2.getPosition().y,100,100);
tSwitch = new Rectangle(tButton.x+100, tButton.y+1225 ,100,100);
sr = new ShapeRenderer();
font = new BitmapFont();
player.getPosition().x = 100;
player.getPosition().y = 100;
player2.setPosition(new Vector2(500, 500));
bounds = new Rectangle(player.getPosition().x , player.getPosition().y , 255, 255);
touchPos = new Rectangle(Gdx.input.getX(), Gdx.input.getY(),200,200);
}
#Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update(false);
bounds.setPosition(player.getPosition().x,player.getPosition().y);
//bounds = new Rectangle(player.getPosition().x, player.getPosition().y + 800, 255, 255);
float deltaTime = Gdx.graphics.getRawDeltaTime();
totalTime -= deltaTime;
String time = String.valueOf(totalTime);
String meow = String.valueOf(playerSwitch);
String Mtime = String.valueOf(Movetime);
batch.begin();
font.draw(batch, meow, 500, 500);
batch.end();
if(Gdx.input.isTouched(1)){
xi = Gdx.input.getX();
yi = Gdx.input.getY();
}
if(Gdx.input.isTouched()) {
Vector3 pointerPos = new Vector3();
pointerPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
touchPos.x = pointerPos.x /*+ 64 / 2*/;
touchPos.y = pointerPos.y /* + 64 / 2*/;
}
if(touchPos.overlaps(tSwitch)&& Gdx.input.isTouched()){
playerSwitch++;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//}else if(touchPos.overlaps(tSwitch)&& Gdx.input.isTouched() ){
// playerSwitch=1;
}
if(touchPos.overlaps(bounds)&& Gdx.input.isTouched()){
batch.begin();
font.draw(batch,"K",900,1000);
batch.end();
}
if(playerSwitch == 1){
if(touchPos.overlaps(p1)&& Gdx.input.isTouched()){
player.getPosition().x += 5f;
Movetime++;
}
if(touchPos.overlaps(p2)&& Gdx.input.isTouched()){
player.getPosition().y += 5f;
Movetime++;
}
if(touchPos.overlaps(p3)&& Gdx.input.isTouched()){
player.getPosition().x -= 5f;
Movetime++;
}
if(touchPos.overlaps(p4)&& Gdx.input.isTouched()){
player.getPosition().y -= 5f;
Movetime++;
}
}
if(playerSwitch == 2){
if(touchPos.overlaps(p1)&& Gdx.input.isTouched()){
player2.getPosition().x += 5f;
}
if(touchPos.overlaps(p2)&& Gdx.input.isTouched()){
player2.getPosition().y += 5f;
}
if(touchPos.overlaps(p3)&& Gdx.input.isTouched()){
player2.getPosition().x -= 5f;
}
if(touchPos.overlaps(p4)&& Gdx.input.isTouched()){
player2.getPosition().y -= 5f;
}
}
//Draw method
font.setScale(5, 5);
batch.begin();
batch.draw(player.getTexture(), player.getPosition().x, player.getPosition().y);
batch.draw(player2.getTexture(),player2.getPosition().x, player2.getPosition().y);
font.draw(batch, time, 900, 1100);
font.draw(batch, meow, 500, 500);
font.draw(batch, Mtime, 200,200 );
batch.end();
sr.begin(ShapeType.Line);
sr.setColor(255,255,255,255);
sr.rect(player.getPosition().x , player.getPosition().y, 255, 255);
sr.rect(player2.getPosition().x, player2.getPosition().y, 200, 200);
sr.end();
}
}
I did a simple app based on the sample of getting started at developer.android.com. It was working fine, but I changed the rotation logic and now it doesn't show the triangle. I'm not sure I understood the matrix stuff, so I would like if someone could check my code.
This is the SurfaceView method I think may have a problem:
#Override
public boolean onTouchEvent(MotionEvent e){
float x = e.getX();
float y = e.getY();
switch(e.getAction()){
case MotionEvent.ACTION_MOVE:
float rotateX = 0.0f;
float rotateY = 0.0f;
float rotateZ = 0.0f;
//na coluna da esquerda, rotação no eixo Z
if(x < getWidth() / 3){
rotateZ = (y - previousY);
}
//na coluna do meio, rotação no eixo X
if(getWidth()/3 < x && x < 2*getWidth()/3){
rotateX = (y - previousY);
}
//na coluna da direita, rotação no eixo Z invertido
if(x > getWidth() / 3){
rotateZ = - (y - previousY);
}
//na linha superior, rotação no eixo Z
if(y < getHeight() / 3){
rotateZ = (x - previousX);
}
//na linha do meio, rotação no eixo Y
if(getHeight()/3 < y && y < 2*getHeight()/3){
rotateY = (x - previousY);
}
//na linha inferior, rotação no eixo Z invertido
if(y > 2*getHeight() / 3){
rotateZ = - (x - previousX);
}
mRenderer.setAngulo(mRenderer.getAnguloX() + (rotateX) * TOUCH_SCALE_FACTOR,
mRenderer.getAnguloY() + (rotateY) * TOUCH_SCALE_FACTOR,
mRenderer.getAnguloZ() + (rotateZ) * TOUCH_SCALE_FACTOR);
requestRender();
}
previousX = x;
previousY = y;
return true;
}
This is the renderer method:
#Override
public void onDrawFrame(GL10 unused) {
//desenha o fundo
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
//define a posição da camera
//Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -5f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
//cria uma matrix para a rotação de cada angulo
Matrix.setRotateM(xRotationMatrix, 0, anguloX, 1, 0, 0);
Matrix.setRotateM(yRotationMatrix, 0, anguloY, 0, 1, 0);
Matrix.setRotateM(zRotationMatrix, 0, anguloZ, 0, 0, 1);
float[] mMatrix = new float[16];
//aplica todas as rotações na matrix scratch
Matrix.multiplyMM(mMatrix, 0, xRotationMatrix, 0, mMatrix, 0);
Matrix.multiplyMM(mMatrix, 0, yRotationMatrix, 0, mMatrix, 0);
Matrix.multiplyMM(mMatrix, 0, zRotationMatrix, 0, mMatrix, 0);
// Calcula a view e depois a projeção
Matrix.multiplyMM(resultingMatrix, 0, mViewMatrix, 0, mMatrix, 0);
Matrix.multiplyMM(resultingMatrix, 0, mProjectionMatrix, 0, resultingMatrix, 0);
// Draw shape
triangulo.draw(resultingMatrix);
}
The Triangulo class must be right because I didn't changed it since the last time the app was working.
Well, i analysed your code thoroughly and there does not seem to be any problem in it.
But, i guess the problem is this :
When you call
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -5f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
You are setting the camera at Z = -5 and looking towards origin i.e towards the +ve Z direction.
(I guess initially the vertices of the triangle must be in XY plane and hence the triangle is visible.)
Then when you call
Matrix.setRotateM(zRotationMatrix, 0, anguloZ, 0, 0, 1);
It rotates the triangle about Z axis which is fine.
But then you call
Matrix.setRotateM(xRotationMatrix, 0, anguloX, 1, 0, 0);
Matrix.setRotateM(yRotationMatrix, 0, anguloY, 0, 1, 0);
Here you are rotating the triangle about X and Y axis and since triangles have no thickness,
It becomes invisible.
Possible fixes :
1) Remove the rotations about X and Y axis and check if it works.
OR
2) Put a cube instead of triangle and see if it works.
OR
3) If neither works, give me the full code.I will debug and run it.
Best of Luck
I figured out the convertion of x and y of my cursor to angle however the problem is my sprite is facing the oposite direction.
here is the code
#Override
public void create() {
bida = new Texture(Gdx.files.internal("data/alienblaster.png"));
tR = new TextureRegion(bida);
bucket = new Rectangle();
bucket.x = 800 / 2 - bida.getWidth() / 2; // center the bucket horizontally
bucket.y = 400/2;
/*bucket.x = Gdx.graphics.getWidth() - bida.getWidth();
bucket.y = Gdx.graphics.getHeight() - bida.getHeight();*/
bucket.width = bida.getWidth();
bucket.height = bida.getHeight();
bullets = new Array<Rectangle>();
spawnRaindrop();
camera = new OrthographicCamera();
camera.setToOrtho(true, 800, 480);
front = 270;
batch = new SpriteBatch();
Gdx.input.setInputProcessor(this);
}
#Override
public void render() {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
camera.update();
batch.setProjectionMatrix(camera.combined);
batch.begin();
{
//batch.draw(bida,bucket.x,bucket.y, 50,50);
batch.draw(tR, bucket.x, bucket.y, bucket.getWidth()/2 /*center x of image where it will rotate*/, bucket.getHeight()/2 /*center y of image where it will rotate*/, bucket.getWidth() , bida.getHeight(), 1, 1, front);
}
batch.end();
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
float dx = screenX - bucket.x; // cursor x and sprite x coordinates
float dy = screenY - bucket.y; // cursor y and sprite y coordinates
float secondSolution =MathUtils.radiansToDegrees*MathUtils.atan2(dx, dy);
double firstSolution = Math.toDegrees(Math.atan2(dx,dy));
front = secondSolution;
Gdx.app.log("","" + firstSolution+ " " + secondSolution);
return true;
}
and the jar file is here
what is the problem here?
In place of camera.setToOrtho(true, 800, 480); use
camera.setToOrtho(false, 800, 480);