How to translate camera after rotating the scene? - opengl-es

I'm currently trying to visualize a building in OpenGL ES 2 in Android.
When I swipe to the left, the whole scene should move to the left (same with right, bottom and top). Now when I rotate the model by 90° the axis are swapped. When I swipe to the right, the model is moved to the top instead of the right (same with the other axis).
How can I translate the camera without having the problem with the current rotation of the scene? As I'm working with a phone, I always want to move the object to the direction I'm swiping to. When I call translate first, the translation works fine, but the rotation has some errors.
Update: I created most of the camera-class (suggested in answers):
private Vector3D c = new Vector3D(eye); // copy of eye
private Vector3D l = Vector3D.getNormalized
(Vector3D.subtract(center, eye)); // normalized center-eye
private Vector3D u = new Vector3D(up); // up (normalized)
public void rotateX(float angle) {
// Now you can rotate L vector left and
// right by rotating it around U by any angle. ??
}
public void rotateY(float angle) {
// If you also need to look up and down
// (rotate) you need to rotate both L and U around S ??
}
public void rotateZ(float angle) {
// to tilt left and right you need to rotate U around L. ??
}
// move left and right
// C = C+S * inputfactor
public void translateX(float inputFactor) {
Vector3D s = Vector3D.cross(l, u);
Vector3D sTimesInput = mul(s, inputFactor);
c = new Vector3D(c).add(sTimesInput);
}
// move forward and backward
// C = C+L*inputfactor
public void translateY(float inputFactor) {
Vector3D lTimesInput = mul(l, inputFactor);
c = new Vector3D(c).add(lTimesInput);
}
// move up and down
// C = C+U * inputfactor
public void translateZ(float inputFactor) {
Vector3D uTimesInput = mul(u, inputFactor);
c = new Vector3D(c).add(uTimesInput);
}
// reconstruct lookAt - eye,center,up
public Vector3D getEye() {
return new Vector3D(c);
}
public Vector3D getCenter() {
return new Vector3D(c).add(new Vector3D(l));
}
public Vector3D getUp() {
return new Vector3D(u);
}
public float[] createLookAt() {
Vector3D eye = getEye();
Vector3D center = getCenter();
Vector3D up = getUp();
return new float[] { eye.getX(), eye.getY(), eye.getZ(), center.getX(),
center.getY(), center.getZ(), up.getX(), up.getY(), up.getZ() };
}
// helper-function
public Vector3D mul(Vector3D vec, float factor) {
return new Vector3D(vec.getX() * factor, vec.getY() * factor,
vec.getZ() * factor);
}
How can I rotate a vector around another vector by an angle?

If you define camera base vectors C-center, L-look at, U-up such that C is the camera center, L is the normalized vector from center towards the point you are looking at and U is up normalized. Now you can rotate the L vector left and right by rotating it around U by any angle.
As for moving left and right you will have to reconstruct side vector S: a cross product between L and U (S=LxU). Now all you have to do is move the center: C = C+S*inputFactor.
To reconstruct the lookAt vectors:
eye = C
center = C+L
up = U
Just as a note: If you also need to look up and down (rotate) you need to rotate both L and U around S, to tilt left and right you need to rotate U around L. To move forward or backwards C = C+L*inputFactor and to move up and down C = C+U*inputFactor.
This should solve all logical camera movement and rotations.

I think you mix the concept of moving the camera and rotating your object. First you need to separate the action of rotating your object from any interaction with the camera. You should be able to do anything with the object without changing the camera at all. To do this just use the model matrix to describe the translation/rotation/scaling of your object. Then you handle your camera separatly by using Matrix.setLookAtM with an eyeX, eyeY, eyeZ that is independent of your model position. And a point to look at that in your case is dependent of the eyeX, eyeY, eyeZ, as you want to be looking at the same direction all the time.
For example, if you want to rotate your object 90 degrees around the Y axis, use:
Matrix.rotateM(mModelMatrix, 0, 90, 0.0f, 1.0f, 0.0f);
Also remember that all matrix operations after Matrix.setIdentityM will be done in a backwards order, ie if you rotate first and then translate as you do the first thing in your code, you will first translate your object away from its origin position, then rotate around the origin, making your object do a kind of rotation around of the first origin, instead of the center of your object.
Then lets say you have translated your camera 100 units to the left and looking at -Z direction, use:
Matrix.setLookAtM(mViewMatrix, offset, -100.0f+camX, camY, camZ, -100.0f+camX, camY, -1.0f+camZ, upX, upY, upZ);

Related

How are should openGL matrices be created? Is there something wrong with my multiplication or order of translation/rotation?

So basically I'm trying to make a simple open gl 3D graphics engine using my own linear algebra to make projection and transformation matrices. OpenGL has a class called glUniformMatrix4fv() which I use to pass the matrices as a float[].
Here is my "Matrix" class to construct a float[] for that openGl method:
private float[] m= {
1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1
};
public Matrix() {}
public Matrix(float[] m) {
this.m=m;
}
//gets value at x,y coords of matrix
public float getValue(int x,int y) {
return m[y*4 + x];
}
//sets value of x,y coord to n
public void setValue(int x,int y,float n) {
m[y*4 + x]=n;
}
To construct a transformation for object translation and rotation I first create translation Matrix (s is for scale). Also a vertex is basically just a size 4 float array I have my Vector/vertex info in:
public Matrix createTranslationMatrix(Vertex pos,float s) {
Matrix m=new Matrix();
m.setValue(0,0,s);
m.setValue(1,1,s);
m.setValue(2,2,s);
m.setValue(3,0,pos.getValue(0));
m.setValue(3,1,pos.getValue(1));
m.setValue(3,2,pos.getValue(2));
return m;
}
Then I create a rotation matrix which is a combo of x, y, and z rotation of object around origin
public Matrix createRotationMatrix(Vertex rot) {
//if rotation is screwed up maybe mess around with order of these :)
Matrix rotX=createRotationMatrixX(rot.getValue(0));
Matrix rotY=createRotationMatrixY(rot.getValue(1));
Matrix rotZ=createRotationMatrixZ(rot.getValue(2));
Matrix returnValue=multiply(rotX,rotY);
returnValue=multiply(returnValue,rotZ);
return returnValue;
}
private Matrix createRotationMatrixX(float num) {
float n=num;
n=(float)Math.toRadians(n);
Matrix rot=new Matrix();
rot.setValue(1, 1, (float)Math.cos(n));
rot.setValue(1, 2, (float)Math.sin(n));
rot.setValue(2, 1, (float)-Math.sin(n));
rot.setValue(2, 2, (float)Math.cos(n));
return rot;
}
//rotation mat Y
private Matrix createRotationMatrixY(float num) {
float n=num;
n=(float)Math.toRadians(n);
Matrix rot=new Matrix();
rot.setValue(0, 0, (float)Math.cos(n));
rot.setValue(0, 2, (float)-Math.sin(n));
rot.setValue(2, 0, (float)Math.sin(n));
rot.setValue(2, 2, (float)Math.cos(n));
return rot;
}
//rotation mat Z
private Matrix createRotationMatrixZ(float num) {
float n=num;
n=(float)Math.toRadians(n);
Matrix rot=new Matrix();
rot.setValue(0, 0, (float)Math.cos(n));
rot.setValue(0, 1, (float)Math.sin(n));
rot.setValue(1, 0, (float)-Math.sin(n));
rot.setValue(1, 1, (float)Math.cos(n));
return rot;
}
I combine the translation and create my objectTransform float[] using a matrix with multiply(rotationMat,translationMat):
public Matrix multiply(Matrix a, Matrix b){
Matrix m=new Matrix();
for(int y=0;y<4;y++) {
for(int x=0;x<4;x++) {
//if this doesn't work maybe try switching x and y around?
m.setValue(x,y,a.getValue(x,0)*b.getValue(0,y) + a.getValue(x,1)*b.getValue(1,y) + a.getValue(x,2)*b.getValue(2,y) + a.getValue(x,3)*b.getValue(3, y));
}
}
return m;
}
And my code for my worldTransorm is defined from by combining a transformation with negative values for position and rotation (so it moves vertex and rotates opposite from camera position and rotation), then combinging rotation and transformation like so multiply(translationMat,rotationMat) , so it theoretically moves opposite camera pos, THEN rotates opposite camera rotation.
then I create my projection using this function:
public Matrix createProjectionMatrix(float fov, float aspectRatio, float near, float far) {
float fovRad=1/(float)Math.tan(Math.toRadians(fov*.5));
Matrix projection=new Matrix(base);
projection.setValue(0,0,aspectRatio*fovRad);
projection.setValue(1,1,fovRad);
projection.setValue(2,2,far/(far-near));
projection.setValue(2,3,(-far*near)/(far-near));
projection.setValue(3,2,1);
projection.setValue(3,3,0);
return projection;
}
I combine my projection , worldTransform, and objectTransform with my Vec3 position (vector with mesh coordinates I import). These are all multiplied together in my openGL shader class like so:
gl_Position=projection * worldTransform * objectTransform * vec4(position,1);
Write now if I back my camera up by 3, rotate it around with hopes of finding the "triangle" mesh I made
float[] verts= {
//top left tri
-.5f,-.5f,0,
0,.5f,0,
.5f,-.5f,0,
};
Then I get a really small pixel moving really fast accross my screen from top to bottom. I also have the object spinning, but that (if my code worked properly) shouldn't be an issue, but if I don't have the object spinning, then I don't see any pixel at all. So my thinking is the object transformation is applying like the world transormation should be working, moving the vertex by "translation" then rotating it, or the triangle is really small and not scaled properly (do I have to offset it somehow?), but then it shouldn't be flying off the screen repeatedly as if its rotating around the camera. I've tried switching multiplication of translation and rotation for both types of transforms, but either the triangle doesn't appear at all or I just see a teensy tiny little pixel, almost orbitting the camera at high speeds (when I should see just the triangle and camera rotating seperately)
I know its a lot to ask but what am I doing wrong? Do I need to transpose something? Is my projection matrix out of wack? I feel like everything should be right :(

Unity2D: How do I move the player to the touch position

I can't figure it out, how do I move the Player slowly, scaleable with a speed value to the point, where the touch happens?
My Camera is attached to the player.
You should use Vector2.Lerp, Input.GetTouch, and Touch.Position. Here is a code example that prints the current touch position:
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
{
Debug.Log(Input.GetTouch(0).position);
}
Now, we should add this to a certain position in the world. We can use Camera.ScreenPointToRay for this part:
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
{
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
RaycastHit2D hit;
Physics2D.Raycast(ray, out hit);
Debug.Log(hit.point);
}
Here, we actually get the position in the world that you have pressed. We can then use this along with Lerp to move an object to the position:
public float scaleFactor = 0.2f; //how fast to move object.
public GameObject moving // drag the object you want to move in this slot.
public Vector2 Lerped;//Vector3 if you’re working in 3D.
public float time = 0f;
public bool lerping = false;
private Vector2 newPos = new Vector2();
//Vector3 if you’re working in 3D.
RaycastHit2D hit;//remove the 2D after RaycastHit if you are in 3D. If you are in 2D, leave it.
float dist;
...
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
{
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
Physics2D.Raycast(ray, out hit);//same with this one. Remove the 2D if you are in 3D.
Debug.Log(hit.point);
dist = Vector2.Distance(moving.transform.position, hit.point);
//Vector3 if you’re in 3D.
lerping = true;
}
if (lerping)
{
time += Time.deltaTime * dist * scaleFactor;
lerp(hit.point.x, hit.point.y, hit.point.z);
//remove hit.point.z if you are in 2D.
}
else
{
time = 0f;
}
if (moving.transform.position == new Vector3(hit.point.x, hit.point.y, hit.point.z);
//remove hit.point.z if in 2D, and switch Vector3 to Vector2 if in 2D.
{
lerping = false;
}
moving.transform.position = newPos;
And then in another part of the script:
public void lerp(float x, float y, float z)
//remove the float z and the comma before it if you are in unity 2d.
{
Vector3 pos = new Vector3(x, y, z);
//Vector2 and no z if you’re in 2D.
newPos = Vector2.Lerp(moveObj, pos, time);
//Vector3 if in 3D.
}
This is a pretty large script, and it’s pretty hard to explain, so I will say this: do what the comments tell you, and tell me if you get any errors. I haven’t actually tested the script, so if anyone notices them, please tell me.
Now, what the script does: basically, it gets the point of where you touched, and makes the player slowly go towards it (the speed changes by the distance and scaleFactor variable of which you can change.)

Having a point from 3 static cameras prespectives how to restore its position in 3d space?

We have same rectangle position relative to 3 same type of staticly installed web cameras that are not on the same line. Say on a flat basketball field. Thus we have tham all inside one 3d space and (x, y, z); (ax, ay, az); positionas and orientations set for all of them.
We have a ball color and we found its position on all 3 images im1, im2, im3. Now having its position on 2d frames (p1x, p1y);(p2x, p2y);(p3x, p3y), and cameras pos\orientations how to get ball position in 3d space?
You need to unproject 2D screen coordinates into 3D coordinates in space.
You need to solve system of equation to find real point in 3D from 3 rays you got on the first step.
You can find source code for gluUnProject here. I also provide here my code for it:
public Vector4 Unproject(float x, float y, Matrix4 View)
{
var ndcX = x / Viewport.Width * 2 - 1.0f;
var ndcY = y / Viewport.Height * 2 - 1.0f;
var invVP = Matrix4.Invert(View * ProjectionMatrix);
// We don't z-coordinate of the point, so we choose 0.0f for it.
// We are going to find out it later.
var screenPos = new Vector4(ndcX, -ndcY, 0.0f, 1.0f);
var res = Vector4.Transform(screenPos, invVP);
return res / res.W;
}
Vector3 ComputeRay(Camera camera, Vector2 p)
{
var worldPos = Unproject(p.X, p.Y, camera.View);
var dir = new Vector3(worldPos) - camera.Eye;
return new Ray(camera.Eye, Vector3.Normalize(dir));
}
Now you need to find intersection of three such rays. Theoretically that would be enough to use only two rays. It depends on positions of your cameras.
If we had infinite precision floating point arithmetic and input was without noise that would be trivial. But in reality you might need to exploit some simple numerical scheme to find the point with an appropriate precision.

How to rotate the ball in the direction its moving?I try to use the rotate function but that throws everything off?

//declaringglobalvaribales
float dia1=50;
//diameteroftheface
float x=400;
float y=400;
float speedX=4;
float speedY=0;
//setup
void setup() {
size(810, 810);
} //draw
void draw() {
background(225);
fill(225, 0, 0);
stroke(0);
ellipse(x, y, dia1, dia1);
fill(0, 225, 0);
//a nose
triangle(x, y, x+10, y+10, x-10, y+10);
//movingtheballXway
x=x+speedX;
//movingtheballYway
y=y+speedY;
//if it hits the left or right corners it will turn around
if (x>width-dia1/2 || x<2+dia1/2) {
speedX=speedX*-1;
}
// it its hits the top or bottom it will turn around
if (y>height-dia1/2 || y<2+dia1/2) {
speedY=speedY*-1;
}
// this code to move it according to the keys W S D A
void keyPressed() {
if (keyCode=='W') {
speedX=0;
speedY=-4;
}
if (keyCode=='S') {
speedX=0;
speedY=4;
}
if (keyCode=='A') {
speedX=-4;
speedY=0;
}
if (keyCode=='D') {
speedX=4;
speedY=0;
}
}
I made this ball with a nose, which moves around the screen with the keys W S D A. If it hits the edges it will bounce back.
I'm trying to change the direction the ball is facing to make it face the same way as it's moving. I wanted to use rotate for this, but once I use rotate it throws all the coordinates off. Rotating it back doesn't help either.
I have commented out the stuff I have tried to do. For example, I tried to translate it to 250,250 and then rotate it afterwards, but then the X and Y coordinates are switched. Also, the ball won't go all the way to the corners and it moves out (since it's translated down).
What kind of rotation/translation logic do I need to change?
It is likely that using the rotate function on your triangle is wreaking havoc as you are performing the rotate on several variables in your draw loop because you're not telling processing exactly which object you want to transform. One way to do this is to look up the pushMatrix and popMatrix functions (google "processing pushMatrix" to see helpful info for how to use the type and associated functions). It would be cumbersome to implement this into your code as the triangle is created in your draw loop every frame. An easy way to make transformations to a specific shape you have (in your instance, a triangle) is to store it as a PShape and then make transformations as you need to. Since PShape's can easily be transformed using PShape functions you don't need to worry about your transformations effecting other variables (so no need to use push/popmatrix. Here is a commented version of your code that implements your Triangle as a PShape.
//declaringglobalvaribales
float dia1=50;
//diameteroftheface
float x=400;
float y=400;
float speedX=4;
float speedY=0;
//Initialize PShape which we can later store a triangle in
PShape tri;
void setup() {
size(810, 810);
//Initialize triangle - this triangle faces right
tri = createShape(TRIANGLE, 0, 10, 0, -10, 10, 0);
}
void draw() {
background(225);
fill(225, 0, 0);
stroke(0);
ellipse(x, y, dia1, dia1);
fill(0, 225, 0);
//Draw the stored PShape at x and y coordinate
shape(tri,x,y);
//movingtheballXway
x=x+speedX;
//movingtheballYway
y=y+speedY;
//if it hits the left or right corners it will turn around
if (x>width-dia1/2 || x<2+dia1/2) {
speedX=speedX*-1;
//Flip PShape rotation
tri.rotate(PI);
} // it its hits the top or bottom it will turn around
if (y>height-dia1/2 || y<2+dia1/2) {
speedY=speedY*-1;
//Flip PShape rotation
tri.rotate(PI);
}
}
// this code to move it according to the keys W S D A
void keyPressed() {
if (keyCode=='W') {
speedX=0;
speedY=-4;
//reset triangle orientation (transformation matrix) to original then rotate to face UP
tri.resetMatrix();
tri.rotate(-PI/2);
}
if (keyCode=='S') {
//reset triangle orientation (transformation matrix) to original then rotate to face DOWN
speedX=0;
speedY=4;
tri.resetMatrix();
tri.rotate(PI/2);
}
if (keyCode=='A') {
//reset triangle orientation (transformation matrix) to original then rotate to face LEFT
tri.resetMatrix();
tri.rotate(PI);
speedX=-4;
speedY=0;
}
if (keyCode=='D') {
//reset triangle orientation (transformation matrix) to original - it is already pointing right
tri.resetMatrix();
speedX=4;
speedY=0;
}
}
I suspect your next step, or a more efficient way to write this piece of code might be to begin to implement PVectors (google processing PVectors to see helpful info for how to use the type and associated functions) for position and direction of your 'ball'. Here is some commented code that begins to show you how you might implement this in your current code. Although there are many improvements that can be made on this. For more information on how vectors work in processing follow this tutorial - http://natureofcode.com/book/chapter-1-vectors/
//declaringglobalvaribales
//diameteroftheface
float dia1=50;
//initialize position PVector and tell it where you want it to be - in this case 400,400
PVector position = new PVector(400, 400);
//how many steps you want your position to move per frame
float speed=4;
//initialize direction vector as 0,0 - the ellipse will not move until you give it a
//direction as it is initialized with no direction
PVector direction = new PVector(0, 0);
void setup() {
size(810, 810);
}
void draw() {
background(225);
fill(225, 0, 0);
stroke(0);
//draw ellipse at your position PVector using the PVectors x and y values
ellipse(position.x, position.y, dia1, dia1);
fill(0, 225, 0);
//drawing a line to indicate what direction the ellipse is heading in using the position coordinates and the position plus direction
line(position.x, position.y, position.x+direction.x*4, position.y+direction.y*4);
// add the direction to the position to make it move
position =position.add(direction);
//if the position PVector is close to sketch edges invert its direction by multiplying direction PVector by -1
if (position.x>width-dia1/2 || position.x<2+dia1/2) {
direction.mult(-1);
}
if (position.y>height-dia1/2 || position.y<2+dia1/2) {
direction.mult(-1);
}
}
// this code to move it according to the keys W S D A
void keyPressed() {
//set the direction coordinates based on keypresses
//also multiply the direction by speed variable so it moves at a speed set at top of script
if (keyCode=='W') {
direction.y = -1*speed;
direction.x = 0;
}
if (keyCode=='S') {
direction.y = 1*speed;
direction.x = 0;
}
if (keyCode=='A') {
direction.x = -1*speed;
direction.y = 0;
}
if (keyCode=='D') {
direction.x = 1*speed;
direction.y = 0;
}
}
If you have a center point, an angle you want to face, and a distance from that center, you can use cos() and sin() to calculate the end point. Here's a simple example:
float angle = 0;
float distance = 25;
void draw(){
angle += .01;
float startX = width/2;
float startY = height/2;
float endX = startX + cos(angle)*distance;
float endY = startY + sin(angle)*distance;
background(255);
line(startX, startY, endX, endY);
}
In the future, please try to narrow your question down to an MCVE like this before posting.

Changing the origin of a rotation matrix in XNA

I am trying to get 4 Vector2 objects representing the 4 corners of a sprite to rotate around the sprite itself rotates around its center. With my following code, however, the Vector2 objects rotate around 0,0 in Client Space instead of rotating around the center of the object. Using matrix transformations, is there any way to rotate the Vector2 objects around the center of the object instead of the global coordinate (0,0)?
Here is the function for the rotation so far:
public Vector2[] CheckCollision()
{
//Get the 4 corners of the sprite locally
//We can get all 4 corners from only 2 vectors
Vector2 topLeft = new Vector2(position.X - spriteSize.X, position.Y - spriteSize.Y);
//Not sure why position is representing the
//bottom right instead of the center here....
Vector2 bottomRight = position;
Vector2 bottomLeft = new Vector2(topLeft.X, bottomRight.Y);
Vector2 topRight = new Vector2(bottomRight.X, topLeft.Y);
//Create transformation matrix
Matrix transform = Matrix.CreateRotationZ(MathHelper.ToRadians(this.direction)) *
Matrix.CreateScale(this.scale);
//Transform the vectors
topLeft = Vector2.Transform(topLeft, transform);
bottomRight = Vector2.Transform(bottomRight, transform);
bottomLeft = Vector2.Transform(bottomLeft, transform);
topRight = Vector2.Transform(topRight, transform);
Vector2[] vectorArray = new Vector2[4];
vectorArray[0] = topLeft;
vectorArray[1] = bottomRight;
vectorArray[2] = bottomLeft;
vectorArray[3] = topRight;
return vectorArray;
}
It would probably be a lot easier to just rotate the four corners first before adding the spritePosition and add the spriteposition after the rotation and scaling has been performed.
Just make your four corners into the corresponding combinations of spriteSize and do the Vector2.Transform once that is done add the spritePosition to the four vectors in vectorArray

Resources