LibGdx: calculating view matrix from projection - android

I'm currently working on Google VR Sdk integration with LibGDX. As a starting point, I used this one: https://github.com/yangweigbh/Libgdx-CardBoard-Extension
However I was not really satisfied with it as it does not follow the the general project structure of LibGDX projects, so I started to refactor and move things around. So far so good, I have a demo running showing a rotating cube.
Now I wanted to add a Skybox, starting from here: LibGDX 0.9.9 - Apply cubemap in environment
The image is drawn, but does not move with head rotation like the other objects, so I looked deeper into the CardboardCamera class, especially the part about setting the projection matrix.
The Skybox class from above gets a quaternion from the camera's view matrix. However this matrix is not set within the CardboardCamera class; instead it sets the projection matrix directly leaving the view matrix unchanged.
So my question now is. If I have the projection matrix, how can I either get the correct quaterion for it to be used for the Skybox or how can I calculate the view matrix so that its getRotation() method returns the correct values ? If both does not make sense, where could I get the correct getRotation() data from ?
Relevant code of the CardboardCamera class:
public void setEyeProjection(Matrix4 projection) {
this.projection.set(projection);
}
final Matrix4 tmpMatrix = new Matrix4();
final Vector3 tmpVec = new Vector3();
#Override
public void update(boolean updateFrustum) {
// below line does not make much sense as position, direction and up are never set...
view.setToLookAt(position, tmpVec.set(position).add(direction), up);
tmpMatrix.set(eyeViewAdjustMatrix);
Matrix4.mul(tmpMatrix.val, view.val);
combined.set(projection);
Matrix4.mul(combined.val, tmpMatrix.val);
if (updateFrustum) {
invProjectionView.set(combined);
Matrix4.inv(invProjectionView.val);
frustum.update(invProjectionView);
}
}

Related

Integrating jPCT-AE and ARToolKit in Android

I'm using the ARToolKit for Android to build an AR app. I can apply the Projection Matrix and the Marker Transformation Matrix in OpenGL without problem, as explained in the ARSimple example. However, I did not find a way to apply correctly these to the jPCT-AE camera. Here is what I did for the camera:
Camera cam = world.getCamera();
Matrix projMatrix = new Matrix();
projMatrix.transformToGL();
projMatrix.setDump(ARToolKit.getInstance().getProjectionMatrix());
cam.setPosition(projMatrix.getTranslation());
cam.setBack(projMatrix);
and for the object:
Matrix objMat = new Matrix();
objMat.transformToGL();
objMat.setDump(ARToolKit.getInstance().queryMarkerTransformation(markerID));
cube.setTranslationMatrix(objMat);
cube.setRotationMatrix(objMat);
It almost works: I can see the 3D object if the marker is placed at the center of the screen. However when I move the marker it quickly disappears off screen. Also, the cube (and other models I tried to load) seems to render in some sort of "inverted" way.
For what I read on the web the ARToolKit matrices are relative to OpenGL world coordinates (while jPCT-AE has its own coordinates), and also that the projection matrix of jPCT-AE is built internally based on the fov, near and far clipping plane, position and rotation, and then I cannot set it directly.
How do I translate the projection matrix and marker matrix to the jPCT-AE engine?
Reviewing my code, it seems JPCT-AE does not get the position and back vector correctly from the matrix (although I see no reason why it does not), but it does when you split them in separate vectors. This are just my findings from trial and error.
This is how I did it for the camera, using the direction and up vectors.
float[] projection = ARToolKit.getInstance().getProjectionMatrix();
Matrix projMatrix = new Matrix();
projMatrix.setDump(projection);
projMatrix.transformToGL();
SimpleVector translation = projMatrix.getTranslation();
SimpleVector dir = projMatrix.getZAxis();
SimpleVector up = projMatrix.getYAxis();
mCamera.setPosition(translation);
mCamera.setOrientation(dir, up);
And then for the model I extract translation and rotation. It is important to clear the translation, since it is not an absolute position, but a modification to the current position. I think this may be your main problem why the objects move out of the screen.
float[] transformation = ARToolKit.getInstance().queryMarkerTransformation(markerID);
Matrix dump = new Matrix();
dump.setDump(transformation);
dump.transformToGL();
mModel.clearTranslation();
mModel.translate(dump.getTranslation());
mModel.setRotationMatrix(dump);
Also, you should do the transformToGl after calling setDump, I think that is the reason why you see them inverted.
Finally, you should reuse the matrix between executions instead of creating a new object every frame, for optimization.

Panning the view of a gameObject instead of the camera in Unity3d?

I'm having a hard time to pan a view of a gameObject in Unity3d. I'm new to scripting and I'm trying to develop an AR (Augmented Reality) application for Android.
I need to have a gameObject (e.g. a model of a floor), from the normal top down view, rendered to a "pseudo" iso view, inclined to 45 degrees. As the gameObject is inclined, I need to have a panning function on its view, utilizing four (4) buttons (for left, right, forward(or up), backward(or down)).
The problem is that, I cannot use any of the known panning script snippets around the forum, as the AR camera has to be static in the scene.
Need to mention that, I need the panning function to be active only at the isometric view, (which I already compute with another script), not on top down view. So there must be no problem with the inclination of the axes of the gameObject, right?
Following, are two mockup images of the states, the gameObject (model floor) is rendered and the script code (from Unity reference), that I'm currently using, which is not very much functional for my needs.
Here is the code snippet, for left movement of the gameObject. I use the same with a change in -, +speed values, for the other movements, but I get it only move up, down, not forth, backwards:
#pragma strict
// The target gameObject.
var target: Transform;
// Speed in units per sec.
var speedLeft: float = -10;
private static var isPanLeft = false;
function FixedUpdate()
{
if(isPanLeft == true)
{
// The step size is equal to speed times frame time.
var step = speedLeft * Time.deltaTime;
// Move model position a step closer to the target.
transform.position = Vector3.MoveTowards(transform.position, target.position, step);
}
}
static function doPanLeft()
{
isPanLeft = !isPanLeft;
}
It would be great, if someone be kind enough to take a look at this post, and make a suggestion on how this functionality can be coded the easiest way, as I'm a newbie?
Furthermore, if a sample code or a tutorial can be provided, it will be appreciated, as I can learn from this, a lot. Thank you all in advance for your time and answers.
If i understand correctly you have a camera with some fixed rotation and position and you have a object you want to move up/down/left/right from the cameras perspective
To rotated an object to a set of angles you simply do
transform.rotation = Quaternion.Euler(45, 45, 45);
Then to move it you use the cameras up/right/forward in worldspace like this to move it up and left
transform.position += camera.transform.up;
transform.position -= camera.transform.right;
If you only have one camera in your scene you can access its transform by Camera.main.transform
An example of how to move it when someone presses the left arrow
if(Input.GetKeyDown(KeyCode.LeftArrow))
{
transform.position -= camera.transform.right;
}

android - set starting point to top left on libgdx

i want to use libgdx as a solution to scaling of apps based on screens aspect ratio.
i've found this link , and i find it really useful:
http://blog.acamara.es/2012/02/05/keep-screen-aspect-ratio-with-different-resolutions-using-libgdx/
i'm quite rusty with opengl (haven't written for it in years) and i wish to use the example on this link so that it would be easy to put images and shapes .
sadly , the starting point is in the middle . i want to use it like on many other platforms - top left corner should be (0,0) , and bottom right corner should be (targetWidth-1,targetHeight-1) ,
from what i remember, i need to move(translate) and rotate the camera in order to achieve it , but i'm not sure .
here's my modified code of the link's example for the onCreate method:
#Override
public void create()
{
camera=new OrthographicCamera(VIRTUAL_WIDTH,VIRTUAL_HEIGHT);
// camera.translate(VIRTUAL_WIDTH/2,VIRTUAL_HEIGHT/2,0);
// camera.rotate(90,0,0,1);
camera.update();
//
font=new BitmapFont(Gdx.files.internal("data/fonts.fnt"),false);
font.setColor(Color.RED);
//
screenQuad=new Mesh(true,4,4,new VertexAttribute(Usage.Position,3,"attr_position"),new VertexAttribute(Usage.ColorPacked,4,"attr_color"));
Point bottomLeft=new Point(0,0);
Point topRight=new Point(VIRTUAL_WIDTH,VIRTUAL_HEIGHT);
screenQuad.setVertices(new float[] {//
bottomLeft.x,bottomLeft.y,0f,Color.toFloatBits(255,0,0,255),//
topRight.x,bottomLeft.y,0f,Color.toFloatBits(255,255,0,255),//
bottomLeft.x,topRight.y,0f,Color.toFloatBits(0,255,0,255),//
topRight.x,topRight.y,0f,Color.toFloatBits(0,0,255,255)});
screenQuad.setIndices(new short[] {0,1,2,3});
//
bottomLeft=new Point(VIRTUAL_WIDTH/2-50,VIRTUAL_HEIGHT/2-50);
topRight=new Point(VIRTUAL_WIDTH/2+50,VIRTUAL_HEIGHT/2+50);
quad=new Mesh(true,4,4,new VertexAttribute(Usage.Position,3,"attr_position"),new VertexAttribute(Usage.ColorPacked,4,"attr_color"));
quad.setVertices(new float[] {//
bottomLeft.x,bottomLeft.y,0f,Color.toFloatBits(255,0,0,255),//
topRight.x,bottomLeft.y,0f,Color.toFloatBits(255,255,0,255),//
bottomLeft.x,topRight.y,0f,Color.toFloatBits(0,255,0,255),//
topRight.x,topRight.y,0f,Color.toFloatBits(0,0,255,255)});
quad.setIndices(new short[] {0,1,2,3});
//
texture=new Texture(Gdx.files.internal(IMAGE_FILE));
spriteBatch=new SpriteBatch();
spriteBatch.getProjectionMatrix().setToOrtho2D(0,0,VIRTUAL_WIDTH,VIRTUAL_HEIGHT);
}
so far , i've succeeded to use this code in order to use scaled coordinates , and still keep aspect ratio (which is great) , but i didn't succeed in moving the starting point (0,0) to the top left corner .
please help me .
EDIT: ok , after some testing , i've found out that the reason for it not working is that i use the spriteBatch . i think it ignores the camera . this code occurs in the render part. no matter what i do to the camera , it will still show the same results.
#Override
public void render()
{
if(Gdx.input.isKeyPressed(Keys.ESCAPE)||Gdx.input.justTouched())
Gdx.app.exit();
// update camera
// camera.update();
// camera.apply(Gdx.gl10);
// set viewport
Gdx.gl.glViewport((int)viewport.x,(int)viewport.y,(int)viewport.width,(int)viewport.height);
// clear previous frame
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
//
final String msg="test";
final TextBounds textBounds=font.getBounds(msg);
spriteBatch.begin();
screenQuad.render(GL10.GL_TRIANGLE_STRIP,0,4);
quad.render(GL10.GL_TRIANGLE_STRIP,0,4);
Gdx.graphics.getGL10().glEnable(GL10.GL_TEXTURE_2D);
spriteBatch.draw(texture,0,0,texture.getWidth(),texture.getHeight(),0,0,texture.getWidth(),texture.getHeight(),false,false);
spriteBatch.draw(texture,0,VIRTUAL_HEIGHT-texture.getHeight(),texture.getWidth(),texture.getHeight(),0,0,texture.getWidth(),texture.getHeight(),false,false);
font.draw(spriteBatch,msg,VIRTUAL_WIDTH-textBounds.width,VIRTUAL_HEIGHT);
spriteBatch.end();
}
These lines:
camera.translate(VIRTUAL_WIDTH/2,VIRTUAL_HEIGHT/2,0);
camera.rotate(90,0,0,1);
should move the camera such that it does what you want. However, my code has an additional:
camera.update()
call after it calls translate, and it looks like you're missing that. The doc for Camera.update says:
update
public abstract void update()
Recalculates the projection and view matrix of this camera and the Frustum planes. Use this after you've manipulated any of the attributes of the camera.

How to find the current translate position in Canvas?

How do I get the current translate position from a Canvas? I am trying to draw stuff where my coordinates are a mix of relative (to each other) and absolute (to canvas).
Lets say I want to do
canvas.translate(x1, y1);
canvas.drawSomething(0, 0); // will show up at (x1, y1), all good
// now i want to draw a point at x2,y2
canvas.translate(x2, y2);
canvas.drawSomething(0, 0); // will show up at (x1+x2, y1+y2)
// i could do
canvas.drawSomething(-x1, -y1);
// but i don't always know those coords
This works but is dirty:
private static Point getCurrentTranslate(Canvas canvas) {
float [] pos = new float [2];
canvas.getMatrix().mapPoints(pos);
return new Point((int)pos[0], (int)pos[1]);
}
...
Point p = getCurrentTranslate(canvas);
canvas.drawSomething(-p.x, -p.y);
The canvas has a getMatrix method, it has a setTranslate but no getTranslate. I don't want to use canvas.save() and canvas.restore() because the way I'm drawing things it's a little tricky (and probably messy ...)
Is there a cleaner way to get these current coordinates?
You need to reset the transformation matrix first. I'm not an android developer, looking at the android canvas docs, there is no reset matrix, but there is a setMatrix(android.graphics.Matrix). It says if the given matrix is null it will set the current matrix to the identity matrix, which is what you want. So I think you can reset your position (and scale and skew) with:
canvas.setMatrix(null);
It would also be possible to get the current translation through getMatrix. There is a mapVectors() method you could use for matrices to see where the point [0,0] would be mapped to, this would be your translation. But in your case I think resetting the matrix is best.

First Person Camera rotation in 3D

I have written a first person camera class for android.
The class is really simple , the camera object has its three axes
X,y and Z
and there are functions to create the ModelView matrix ( i.e. calculateModelViewMatrix() ),
rotate the camera along its X and Y axis
and Translate the camera along its Z-axis.
I think that my ModelViewMatrix calulation is correct and i can also translate the camera along the Z-axis.
Rotation along x-axis seems to work but along Y-axis it gives strange results.
Also another problem with the rotation seems to be that instead of the camera being rotated, my 3d model starts to rotate instead along its axis.
I have written another implementation based on the look at point and using the openGL ES's GLU.gluLookAt( ) function to obtain the ModelView matrix but that too seems to suffer from the exactly the same problems.
EDIT
First of all thanks for your reply.
I have actually made a second implementation of the Camera class, this time using the rotation functions provided in android.opengl.Matrix class as you said.
I have provided the code below, which is much simpler.
To my surprise, the results are "Exactly" the same.
This means that my rotation functions and Android's rotation functions are producing the same results.
I did a simple test and looked at my data.
I just rotated the LookAt point 1-dgree at a time around Y-axis and looked at the coordinates. It seems that my LookAt point is lagging behind the exact rotation angle e.g. at 20-deg it has only roatated 10 to 12 degree.
And after 45-degrees it starts reversing back
There is a class android.opengl.Matrix which is a collection of static methods which do everything you need on a float[16] you pass in. I highly recommend you use those functions instead of rolling your own. You'd probably want either setLookAtM with the lookat point calculated from your camera angles (using sin, cos as you are doing in your code - I assume you know how to do this.)
-- edit in response to new answer --
(you should probably have edited your original question, by the way - your answer as another question confused me for a bit)
Ok, so here's one way of doing it. This is uncompiled and untested. I decided to build the matrix manually instead; perhaps that'll give a bit more information about what's going on...
class TomCamera {
// These are our inputs - eye position, and the orientation of the camera.
public float mEyeX, mEyeY, mEyeZ; // position
public float mYaw, mPitch, mRoll; // euler angles.
// this is the outputted matrix to pass to OpenGL.
public float mCameraMatrix[] = new float [16];
// convert inputs to outputs.
public void createMatrix() {
// create a camera matrix (YXZ order is pretty standard)
// you may want to negate some of these constant 1s to match expectations.
Matrix.setRotateM(mCameraMatrix, 0, mYaw, 0, 1, 0);
Matrix.rotateM(mCameraMatrix, 0, mPitch, 1, 0, 0);
Matrix.rotateM(mCameraMatrix, 0, mRoll, 0, 0, 1);
Matrix.translateM(mCameraMatrix, 0, -mEyeX, -mEyeY, -mEyeZ);
}
}

Categories

Resources