How i make camera in my lwjgl 3D java application?
I try use glRotate and glTranslatef, but this move only objects, and i need move scene.
Same i try use
glLoadMatrixf(new float[]{
50, 50, 50, 50,
50, 50, 50, 50,
-75, 50, 50, 50,
100, 100, 100, 100
});
But I don’t quite understand how it works, and i see white screen
What solotion i can use for my task?
In OpenGL there is no camera. To "move the camera", you have to move the objects in the opposite direction instead. For example, instead of moving the camera forward, you would move the objects backward.
If you want to make your first view matrix, then start with gluLookAt.
With this handy Legacy OpenGL utility function, you can define a view matrix by a position (eye), a target point (target) and an up vector (up):
(See also Java Code Examples for org.lwjgl.util.glu.GLU.gluLookAt())
GLU.gluLookAt(eye.x, eye.y, eye.z, target.x, target.y, target.z, up.x, up.y, up.z);
The view space is the local system which is defined by the point of view onto the scene.
The position of the view, the line of sight and the upwards direction of the view, define a coordinate system relative to the world coordinate system. The objects of a scene have to be drawn in relation to the view coordinate system, to be "seen" from the viewing position. The inverse matrix of the view coordinate system is named the view matrix. This matrix transforms from world coordinates to view coordinates.
Additionally you well need either an Orthographic or Perspective projection matrix.
The former matrix can be defined by glOrtho
(See also Java Code Examples for org.lwjgl.opengl.GL11.glOrtho())
GL11.glOrtho(0, width, height, 0, 1, -1);
and the later by gluPerspective
(See also Java Code Examples for org.lwjgl.util.glu.GLU.gluPerspective())
GLU.gluPerspective(45.0f, wRatio, (float) near, (float) far);
The projection matrix describes the mapping from 3D points of a scene, to 2D points of the viewport. The projection matrix transforms from view space to the clip space. The coordinates in the clip space are transformed to the normalized device coordinates (NDC) in the range (-1, -1, -1) to (1, 1, 1) by dividing with the w component of the clip coordinates.
In legacy OpenGL there exist different current matrices. The projection matrix should be set to the current GL_PROJECTION matrix and the view matrix to the current GL_MODELVIEW matrix. See glMatrixMode.
e.g.:
float width = ...; // width of the window
float height = ...; // height of the window
Vector3f eye = ...; // camera position
Vector3f target = ...; // camera target
Vector3f up = ...; // camera up vector
float ratio = 1.0f * width / height;
GL11.glViewport(0, 0, (int) w, (int) h);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GLU.gluPerspective(45.0f, ratio , 0.1f, 100.0f);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glLoadIdentity();
GLU.gluLookAt(eye.x, eye.y, eye.z, target.x, target.y, target.z, up.x, up.y, up.z);
Instead of GLU.gluPerspective, a perspective projection matrix can be set as follows:
float width = ...; // width of the window
float height = ...; // height of the window
float fov_y = 45.0f; // filed of view in degrees (y axis)
float n = 0.1f; // near plane
float f = 100.0f; // far plane
float a = width / height;
float ta = Math.tan(Math.radians(fov_y) / 2.0f);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
glLoadMatrixf(new float[]{
1.0f/(ta*a), 0.0f, 0.0f, 0.0f,
0.0f, 1.0f/ta, 0.0f, 0.0f,
0.0f, 0.0f, -(f+n)/(f-n), -1.0f,
0.0f, 0.0f, -2.0f*f*n/(f-n), 0.0f
});
Instead of using a GLU.gluLookAt a view matrix can be set by glTranslate and glRoatate:
float distance = 10.0f; // distance to object
float pitch = 0.0f; // pitch in degrees
float yaw = 0.0f; // yaw in degrees
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glRotatef(yaw, 0.0f, 1.0f, 0.0f);
GL11.glRotatef(pitch, 1.0f, 0.0f, 0.0f);
GL11.glTranslatef(0.0f, 0.0f, -distance);
Related
The problem is that when rotating my 3D cube on more than one axes, it distorts weirdly roughly halfway through. I am using the JOML math library for matrices.
// This is the model matrix for the rotation of a textured cube
Matrix4f model = new Matrix4f();
model.identity();
model.rotate((float)(glfwGetTime() * Math.toRadians(50.0f)), new Vector3f(0.5f, 1.0f, 0.0f), model);
// Other matrices for coordinate system
Matrix4f view = new Matrix4f();
view.identity();
view.translate(new Vector3f(0.0f, 0.0f, -3.0f), view);
Matrix4f projection = new Matrix4f();
projection.identity();
projection.perspective((float)Math.toRadians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f); // FOV is 45
This is a gif of the distortion:
The main problem is that your rotation axis (0.5f, 1.0f, 0.0f) is not unit/normalized, (as is also required by its JavaDoc)
Parameters:
axis - the rotation axis (needs to be normalized)
To solve the problem and still use a matrix, you simply need to normalize the rotation axis.
Also (but this is irrelevant to the error):
JOML matrices are identity by default after instantiation - you do not need to call identity() on them)
you can omit supplying model as the argument to the dest parameter of rotate()
So:
// This is the model matrix for the rotation of a textured cube
Matrix4f model = new Matrix4f();
model.rotate((float)(glfwGetTime() * Math.toRadians(50.0f)),
new Vector3f(0.5f, 1.0f, 0.0f).normalize());
There are 2 mistakes in your code:
First: you try to update 2 axis at once.
Doing this will cause the model to scale as it rotates.
Second: you don't use 1.0f when defining what axis you want to rotate. This aswell causes the model to scale.
The way Matrix4f.rotate(float angleInRadiants, Vector3f(x, y, z)) works is it will rotate the axis specified in the the vector by the specified angleInRadians.
This is the correct way to rotate both axis:
model
.rotate((float)(glfwGetTime() * Math.toRadians(50.0f)), new Vector3f(0.0f, 1.0f, 0.0f), model)
.rotate(((float)(glfwGetTime() * Math.toRadians(50.0f)) / 2), new Vector3f(0.1f, 0.0f, 0.0f), model);
A better way to do rotation is quaternions.
You can create a new Quaternionf object, set it's angles and rotate the model matrix using it.
float someAngleInRads = (float) Math.toRadians(20f * glfwGetTime());
Quaternionf quaternionf = new Quaternionf()
.rotateAxis(someAngleInRads, new Vector3f(0, 1, 0))
.rotateAxis(someAngleInRads / 2, new Vector3f(1, 0, 0));
model.rotate(quaternionf);
You could also set the angles for the quaternion this way:
Quaternionf quaternionf = new Quaternionf().rotateXYZ(Math.toRadians(someAngleInRads / 2), Math.toRadians(someAngleInRads), Math.toRadians(0f));
I am attempting to have a 2D HUD which has icons that track the location on the screen of 3D objects behind the HUD in a 3D environment.
Reasoning: Sometimes you cannot see a 3D object (too far away or off screen) but you still want to know where it is.
Issue: 3D scene is using a perspective matrix to transform it, giving it depth (z-axis), the HUD is strictly 2D (xy-plane). Because of the depth, the 2D HUD cannot properly track objects when they are farther/closer away.
What I want: A way to get a 2D Vector [(x,y) pos] of where to put an icon so that it is centered where the 3D object in the background would be.
Example of all objects in an xy-plane (z=0):
You can see that as the objects get farther away from the center, the Icon (circle thing in white) is more off center.
Example of objects with increasing depths (farther from center == deeper):
You can see that the HUD thinks 3D objects are in the same plane still.
Pseudo-Code:
.getPos() gets the Vector (x,y,z)
lookAtObj = Object.getPos() - camera.getPos() // lookAt vector from camera to the object
icon.pos = Orthogonal Component of lookAtObj on camera.get_lookAt()
My Perspective Matrix:
// Function call in the OpenGL draw() method
FloatMatrix proj = FloatMatrix.getPerspectiveMatrix( this.fov, this.width, this.height, 0.1f, 200.0f );
// Function
public static FloatMatrix getPerspectiveMatrix( Double fov, float w, float h, float near, float far ){
float asp = w/h;
float fov_cos = (float) Math.cos( fov / 2.0d );
float fov_sin = (float) Math.sin( fov / 2.0d );
float fov_cot = fov_cos/fov_sin;
float a_0 = fov_cot/asp;
float a_3 = (far + near)/(near-far);
float a_43 = (2.0f * far * near)/(near-far);
float[] an = {
a_0, 0.0f, 0.0f, 0.0f,
0.0f, fov_cot, 0.0f, 0.0f,
0.0f, 0.0f, a_3, -1.0f,
0.0f, 0.0f, a_43, 0.0f,
};
return new FloatMatrix( an, 4, 4 );
}
This is pretty straightforward. You can use gluProject. It will take a given modelview, projection, and viewport transform, and a 3D point, and apply the inverse and spit out a 2D point in window coordinates for you (apologies for minor typos, just typing this here):
double myX = ..., myY = ..., myZ = ...; // your object's 3d coordinates
double[] my2DPoint = new double[2]; // will contain 2d window coords when done
double[] modelview = new double[16];
double[] projection = new double[16];
int[] viewport = new int[4];
gl.glGetDoublev(GL2.GL_MODELVIEW_MATRIX, modelview, 0);
gl.glGetDoublev(GL2.GL_PROJECTION_MATRIX, projection, 0);
gl.glGetIntegerv(GL2.GL_VIEWPORT, viewport, 0);
glu.gluProject(myX, myY, myZ, modelview, 0, projection, 0,
viewport, 0, my2DPoint, 0);
// now my2DPoint[0] is window x, and my2DPoint[1] is window y
After you do this, you'll have your 3D point in 2D window coordinates. Then simply switch your projection over to a 2D orthogonal projection, in window pixels, and draw your HUD in 2D space.
For performance, if you have multiple HUD items to draw per frame; just get the modelview/projection/viewport once per frame (or, even better, invalidate your cached ones if you change them and re-query only as needed) and reuse them in subsequent calls to gluProject.
I'm creating an app, which should draw objects in constant place on the scene, but when i move my phone around, camera should change view and i should see all object around (when i do full rotation with phone).
When i use gl.glMultMatrixf(rotationMatrix, 0) in my onDrawFrame method and then draw object its working perfect (rotation matrix is obtained from SensorManager)
#Override
public void onDrawFrame(GL10 gl) {
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
gl.glMultMatrixf(rotationMatrix, 0);
gl.glTranslatef(0f, 0f, -10f);
//draw object
pyramid.draw(gl);
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluPerspective(gl, 45.0f, (float) width / (float) height, 0.1f, 100.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
}
But when i try to use:
GLU.gluLookAt( gl, 0.0f, 0.0f, 0.0f, x, y, z, 0.0f, 1.0f, 0.0f );
gl.glPushMatrix();
//draw object
pyramid.draw(gl);
my object is all time in the same place on screen and follow camera movement. What I'm doing wrong in second example ?
I think you are unclear on what glulookat() actually does. You are asking for a matrix representing glulookat(currentrotationmatrix, mylocation.x, mylocation.y, mylocation.z, whereImlooking.x, whereImlooking.y, whereImlooking.z, upvector.x, upvector.y, upvector.z)
So with that code you are telling opengl to rotate everything, (assuming that code is still present) and then you are saying "I am at origin (0.0, 0.0, 0.0) and looking at xyz" (not sure what xyz is in your case. or what effect you are trying to achieve.)
I want it to be at 0 on the y-axis, that is what I mean by flat to the ground.
I am making the floor of my game in android, I am using opengl es 1. I have a square I am using as the floor, so obviously I want it to be flat to the ground. I want the y-axis to be 0, but whenever I set it to this the square isn't on the screen. But if I set all of the y-axis to 0.1 then the square is hovering from the center of the screen to the top right corner, not flat to the ground.
This is the vertices array:
float w = 10;
float h = 10;
float vertices[] ={
0f, 0.1f, 0f,
w, 0.1f, 0f,
0f, 0.1f, -h,
w, 0.1f, -h
};
I am then storing it in the normal float buffer:
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
mFVertexBuffer = vbb.asFloatBuffer();
mFVertexBuffer.put(vertices);
mFVertexBuffer.position(0);
And then when it comes to drawing it:
gl.glDrawElements( GL10.GL_TRIANGLES,2*3, GL10.GL_UNSIGNED_BYTE, mIndexBuffer);
And this is setting up the frustum, which I don't think should make a difference but...
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
float aspectRatio;
float zNear =.1f;
float zFar = 1000f;
float fieldOfView = 1f;
float size;
gl.glEnable(GL10.GL_NORMALIZE);
aspectRatio=(float)width/(float)height;
gl.glMatrixMode(GL10.GL_PROJECTION);
size = zNear * (float)(Math.tan((double)(fieldOfView/2.0f)));
gl.glFrustumf(-size, size, -size /aspectRatio,
size /aspectRatio, zNear, zFar);
gl.glMatrixMode(GL10.GL_MODELVIEW);
}
Why is it not flat? and why when the y-axis is 0, does it disappear?
I am tring to achieve this:
Where the white section is the floor.
Your object is "disappearing", because your object has no height.
It's like if you were holding an infinitely thin piece of paper flat in front of your eyes. If the paper is above or below your field of vision, then you can see it, but if you put it exactly parallel to your eyes, you wouldn't be able to see it.
It's not really clear to me what you expect it to look like. How do you want this floor to look, will you be looking at it from above, or from an angle? Do you want it to fill from the center of the screen to the bottom? Maybe a mockup image could really help explain what you're trying to achieve.
The following code produces the image that follows. The image I am using for the background is 640 x 480, as is the displayMode. The texture background is a .bmp and is loaded with the Slick texture loader. I am confuse to why it is not filling the Quad and why it is reflected.
EDIT: The background of my OpenGL scene is pink, the black you see is from the Quad created. The background image is the green block with a 2px light blue border with "test" plastered on it.
private void renderBackground(){
float w = displayMode.getHeight()/2;
float h = displayMode.getWidth()/2;
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glPushMatrix();
GL11.glLoadIdentity();
GLU.gluOrtho2D(-w, w, -h, h);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glPushMatrix();
GL11.glLoadIdentity();
GL11.glDisable(GL11.GL_DEPTH_TEST);
if(useTextures)background.bind();
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(0.0f, 0.0f);
GL11.glVertex2f(-w,-h);
GL11.glTexCoord2f(1.0f, 0.0f);
GL11.glVertex2f(w,-h);
GL11.glTexCoord2f(1.0f, 1.0f);
GL11.glVertex2f(w, h);
GL11.glTexCoord2f(0.0f, 1.0f);
GL11.glVertex2f(-w, h);
GL11.glEnd();
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glPopMatrix();
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glPopMatrix();
}
Now when I add GL11.glTranslatef(20.0f, 20.0f, 0.0f); you will notice that the pink appears, which is the colour created int my "initGL" method:
GL11.glClearColor(1.0f, 0.75f, 0.796f, 0.0f);
My GL_PROJECTION contains the following before pushing it, my GL_MODELVIEW is unmodified when renderBackground() is called.
GL11.glMatrixMode(GL11.GL_PROJECTION); // Select The Projection Matrix
GL11.glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
GLU.gluPerspective(45.0f, (float) displayMode.getWidth() / (float) displayMode.getHeight(), 0.1f, 25.0f);
//position camera
GLU.gluLookAt(5.0f, 3.0f, -5.0f, 0.0f, 0.0f, -10.0f, 0.0f, 1.0f, 0.0f);
GL11.glMatrixMode(GL11.GL_MODELVIEW); // Select The Modelview Matrix
I need more information to determine the problem, but here is a list with some possibilities.
1) You are using an older video card, which does not support texture non-power of 2, since you are using a library to load the texture, maybe it is detecting it, creating a power of two image, and filling it with black.
2) You (or some library you are using) changed the matrix of the texture matrix stack, and it is changing the texture coordinates.
3) You are doing something wrong when you load the texture (or call the library to do so).
The first thing I would check is if your video card supports texture non-power of 2 extension. You can check it at runtime, see how to detect if openGL/card supports non power of 2?
What I see first, is that you compute
float w = displayMode.getHeight()/2;
float h = displayMode.getWidth()/2;
switched?
Second, the texture could be flipped because the loader flipped it (when I remember right this happened to me, too especially with BMPs).