I'm fighting with the code, to make it rotate camera around the object. The code that I'm using is:
eyeX = (float) (obj.x + 500*Math.cos(Math.toRadians(angle))*Math.sin(Math.toRadians(angle)));
eyeY = (float) (obj.y + 500*Math.sin(Math.toRadians(angle))*Math.sin(Math.toRadians(angle)));
eyeZ = (float) (obj.z + 500*Math.cos(Math.toRadians(angle)));
Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, obj.x, obj.y, obj.z, 0, 1, 0);
Where obj is the model I want to rotate the camera around, and angle is incremented by 1 with every draw. Can somebody shed a light to this problem, what I'm doing wrong?
What exact camera motion are you trying to achieve?
If you want to turn around obj on the XZ plane while remaining at a constant height, you should do:
eyeX = (float)(obj.x + 500*Math.cos(Math.toRadians(angle));
eyeY = (float)(y0); //constant height
eyeZ = (float)(obj.z + 500*Math.sin(Math.toRadians(angle));
Also, if y0 != 0, then (0, 1, 0) is not a proper "up" vector and will distort you view.
Related
The pitch and the heading work perfectly :
fun onDrawFrame(pitch: Float, roll: Float, heading: Float) {
val lookAtX = cos(pitch) * cos(heading)
val lookAtY = -sin(pitch)
val lookAtZ = cos(pitch) * sin(heading)
val upX = 0.0F
val upY = 1.0F
val upZ = 0.0F
Matrix.setLookAtM(cameraPositionMatrix, 0, 0.0F, 0.0F, 0.0F, lookAtX.toFloat(), lookAtY.toFloat(), lookAtZ.toFloat(), upX.toFloat(), upY.toFloat(), upZ.toFloat())
...
}
But how can I rotate (roll) the camera? I guess I need to rotate the UP vector based on the roll angle around the "line of sight", but it's more complex than I thought.
Does anyone know the formula to calculate the cartesian coordinates of a point A(Xa, Ya, Za) after a rotation of an angle δ (in radians) around an axis B(Xb, Yb, Zb)C(Xc, Yc, Zc)?
This question concerns both setLookAtM (OpenGL ES) and gluLookAt (OpenGL)
What you want can easily be achieved with Rx * Ry * Rz * T where Rx/y/z are the respective rotation matrices to rotate around the x, y or z axis, respectively, followed by the (negative) camera translation, which in your case is just (0, 0, 0).
You could compute it manually by doing the trigonometry by hand and computing the direction and up vectors for lookat by hand, but there's also the route via rotateM, effectively achieving the same:
fun onDrawFrame(pitch: Float, roll: Float, heading: Float) {
Matrix.setIdentityM(cameraPositionMatrix, 0)
Matrix.rotateM(cameraPositionMatrix, 0, pitch, 1, 0, 0);
Matrix.rotateM(cameraPositionMatrix, 0, heading, 0, 1, 0);
Matrix.rotateM(cameraPositionMatrix, 0, roll, 0, 0, 1);
}
I have a problem for now quite a long time...
In my OpenGL game, you can see in the picture, is a car with a height-terrain.
So to calculate the angle for the car, I created 4 Boxes, which are following around the car, so they always have the same position in relation of the car's rotation. So my algorithm for that works quite well, but when I streer the car, it gets useless, because I'm only rotating around the static X and Z axis of the cartesian-coordinate system.
Do someone know how the "move" the solid axis, so I could rotate around like custom axis? Or my second Idea was something about interpulation between Xrotation and zrotation...
Pls help :(
Here my code:
Vector3f x1 = new Vector3f(26, cubex1.getPosition().y, 0);
Vector3f x2 = new Vector3f(0, cubex2.getPosition().y, 0);
Vector3f xdif = new Vector3f(x1.x - x2.x, x1.y - x2.y, x1.z - x2.z);
float anglex = -(float) Math.toDegrees(cubex1.getPosition().angle(xdif, new Vector3f(1, 0, 0)));
if(cubex1.getPosition().y < cubex2.getPosition().y){
super.setRotX(-anglex);
}else{
super.setRotX(anglex);
}
Vector3f z1 = new Vector3f(0, cubez1.getPosition().y, 14);
Vector3f z2 = new Vector3f(0, cubez2.getPosition().y, 0);
Vector3f zdif = new Vector3f(z1.x - z2.x, z1.y - z2.y, z1.z - z2.z);
float anglez = -(float) Math.toDegrees(cubez1.getPosition().angle(zdif, new Vector3f(0, 0, 1)));
super.setRotZ(anglearoundplayer / anglez);
if(cubez1.getPosition().y < cubez2.getPosition().y){
super.setRotZ(-anglez);
}else{
super.setRotZ(anglez);
}
I am using the Vectors of different boxes the get the angle in relation of a flat surface...
I try to transform the window mouse coordinates (0/0 is the upper left corner) into world space coordinates. I just tried to solve it by this description. Here is my code:
public void showMousePosition(float mx, float my){
Matrix4f projectionMatrix = camera.getProjectionMatrix();
Matrix4f viewMatrix = camera.getViewMatrix();
Matrix4f projMulView = projectionMatrix.mul(viewMatrix);
projMulView.invert();
float px = ((2*mx)/650)-1;
float py = ((2*my)/650)-1;
Vector4f vec4 = new Vector4f(px, py*(-1), 0.0f, 1.0f);
vec4.mul(projMulView);
vec4.w = 1.0f / vec4.w;
vec4.x *= vec4.w;
vec4.y *= vec4.w;
vec4.z *= vec4.w;
System.out.println(vec4.x + ", " + vec4.y);
}
But thats not 100% correct. I have an Object on 0/-11 on world space and when I move my mouse to this point, my function say 0/9,8. And when I go to the left side of my window the x value is 5,6 but it should be something like 28.
Someone know what is wrong on my code?
First of all, your code says that your windows size is always width=650, height=650.
Then you are getting the position when z=0. But this z is in screen space and therefore it changes as you change the camera position and orientation. Normally, you get this information from the depth buffer, using glReadPixel. You should do it in this case.
However, there is another way to do this also. In the code I will share, I am looking for the intersection between a ray (generated from the mouse position) and the plane (0,0,0) with normal (0,1,0), I hope this helps.
/*Given the inverse PV (projection*view) matrix, the position of the mouse on screen and the size of the screen, transforms the screen coordinates to world coordinates*/
glm::vec3 Picking::OnWorld(glm::mat4 const& m_inv, glm::vec2 const & spos,size_t width, size_t height) {
float x = spos.x;
float y = spos.y;
y = height - y;
//InputOrigin, start of the ray for intersection with plane
glm::vec4 inputO = glm::vec4(x / width*2.0f - 1.0f, y / height*2.0f - 1.0f, -1.0f, 1.0f); //transforms screen position to the unit cube range
glm::vec4 resO = m_inv*inputO; //transforms to world space
if (resO.w == 0.0f)
return glm::vec3(-1); //return an invalid value to show a problem during a calculation, normally this means that the m_inv matrix was incorrect
resO /= resO.w; //homogeneous division
glm::vec4 inputE = inputO; //inputEnd, the end of the ray
inputE.z = 1.0;
//End of ray to world space
glm::vec4 resE = m_inv*inputE;
//checks that the coordinates are correct
if (resE.w == 0.0f)
return glm::vec3(-1); //return an invalid value to show a problem during a calculation, normally this means that the m_inv matrix was incorrect
resE /= resE.w;
//ray for intersection
glm::vec3 ray = glm::vec3(resE - resO); //vector between z=-1 and z=1
glm::vec3 normalRay = glm::normalize(ray);
glm::vec3 normalPlane = glm::vec3(0, 1, 0); //detects collision with plane 0, normal 1
float denominator = glm::dot(normalRay, normalPlane);
if (denominator == 0)
return glm::vec3(-1); //return an invalid value to show a problem during a calculation, normally this means that the m_inv matrix was incorrect
float numerator = glm::dot(glm::vec3(resO), normalPlane);
//intersection between ray and plane
glm::vec3 result = glm::vec3(resO) - normalRay*(numerator / denominator);
return result;
}
The math for the intersection can be read from this link:
https://www.cs.princeton.edu/courses/archive/fall00/cs426/lectures/raycast/sld017.htm
Follow-up for: Calculating world coordinates from camera coordinates
I'm multiplying a 2D vector with a transformation matrix (OpenGL's model-view matrix) to get world coordinates from my camera coordinates.
I do this calculation like this:
private Vector2f toWorldCoordinates(Vector2f position) {
glPushMatrix();
glScalef(this.zoom, this.zoom, 1);
glTranslatef(this.position.x, this.position.y, 0);
glRotatef(ROTATION, 0, 0, 1);
ByteBuffer m = ByteBuffer.allocateDirect(64);
m.order(ByteOrder.nativeOrder());
glGetFloatv(GL_MODELVIEW_MATRIX, m);
float x = (position.x * m.getFloat(0)) + (position.y * m.getFloat(4)) + m.getFloat(12);
float y = (position.x * m.getFloat(16)) + (position.y * m.getFloat(20)) + m.getFloat(28);
glPopMatrix();
return new Vector2f(x, y);
}
Now I also want to do this vice-versa: calculate the camera coordinates for a position in the world. How can I reverse this calculation?
To create a matrix representing the inverse transform to the one above, apply the transforms in reverse, with negative quantities for the rotation and translation and an inverse quantity for the zoom:
glRotatef(-ROTATION, 0, 0, 1);
glTranslatef(-this.position.x, -this.position.y, 0);
glScalef(1.0f / this.zoom, 1.0f / this.zoom, 1);
Then multiply by the position vector as before.
The alternative is to compute the inverse matrix, but this way is much simpler.
Good evening.
I'm trying to rotate a line on a canvas using setRotation -method and it works perfectly, unless you want to draw another shape on the same canvas. After using Canvas's concat -method, the entire canvas will be rotated, let's say, by 30 degrees counterclockwise/clockwise. And this is the problem. I would like to rotate only the line and I don't want to rotate any other shapes on this canvas or the entire canvas. I found out that the bitmap could be drawn with matrices, but it looks cumbersome and clumsy. Also, there was a suggestion to setup a new matrix for the Canvas, in fact, this proposition works neither.
So, the question sounds simple enough, how could the only one shape on the canvas be rotated without using OpenGl and affecting on other shapes on the canvas?
Thank you for your answers in advance!
Here is the code with comments and other stuff:
#Override
public void onDraw(Canvas canvas)
{
int startX, startY, stopX, stopY;
startY = stopY = 100;
startX = 100;
stopX = 200;
this.paint = new Paint();
//this.path = new Path();
this.matrix = canvas.getMatrix();
this.paint.setColor(Color.BLUE);
this.paint.setStrokeWidth(4);
this.matrix.setRotate(180, startX, startY);
canvas.concat(this.matrix);
/*this.matrix.setTranslate(startX, 0);
canvas.concat(this.matrix);*/
canvas.drawLine(startX, startY, stopX, stopY, this.paint);
canvas.setMatrix(new Matrix());
//canvas.drawCircle(200, 200, 50, paint);
}
You could try Canvas.save() and Canvas.restore() for this. They supposedly put current matrix into stack and you can return back to previous one once done with the modified matrix.
this.matrix.setRotate(180, startX, startY);
canvas.save();
canvas.concat(this.matrix);
canvas.drawLine(startX, startY, stopX, stopY, this.paint);
canvas.restore();
Mozoboy proposed the idea of using the linear algebra. Here is a new code of the onDraw(Canvas canvas) method with using linear algebra and staying in the scopes of the Android APIs:
Matrix m = new Matrix(); //Declaring a new matrix
float[] vecs = {7, 3}; //Declaring an end-point of the line
/*Declaring the initial values of the matrix
according to the theory of the 3
dimensional chicken in 2D space
There is also 4D chicken in 3D space*/
float[] initial = {1, 0, 0, 0, 1, 0, 0, 0, 1};
m.setValues(initial);
float[] tmp = new float[9]; //Debug array of floats
m.setRotate(90, 4.0f, 3.0f); //Rotating by 90 degrees around the (4, 3) point
/*Mapping our vector to the matrix.
Similar to the multiplication of two
matrices 3x3 by 1x3.
In our case they are (matrix m after rotating) multiplied by
(7)
(3)
(1) according to the theory*/
m.mapPoints(vecs);
for(float n : vecs)
{
Log.d("VECS", "" + n); //Some debug info
}
m.getValues(tmp);
for(float n : tmp)
{
Log.d("TMP", "" + n); //also debug info
}
As a result of this algorithm, we have a new coordinates of the line's end point (4, 6).