I've already checked the other questions on this topic and their solutions haven't worked for me. I'm at a bit of a loss. I have the following functions in my GLEventListener implementation.
public void init(GLAutoDrawable gl) {
GL2 gl2 = gl.getGL().getGL2();
gl2.glMatrixMode(GL2.GL_PROJECTION);
gl2.glLoadIdentity();
GLU glu = GLU.createGLU(gl2);
glu.gluPerspective(45.0f, 1, 0.1f,100.0f);
gl2.glMatrixMode(GL2.GL_MODELVIEW);
gl2.glLoadIdentity();
gl2.glViewport(0, 0, width, height);
gl2.glEnable(GL.GL_DEPTH_TEST);
}
private void render(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
GLU glu = GLU.createGLU(gl);
gl.glClear(GL.GL_COLOR_BUFFER_BIT);
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glLoadIdentity();
glu.gluLookAt(5, 0, 20,
0, 30, 0,
0, 1, 0);
gl2.glPushMatrix();
gl2.glClear( GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT );
gl2.glLoadIdentity();
gl2.glTranslatef(x, y, z);
gl2.glBegin( GL2.GL_QUADS );
gl2.glColor3f( 1, 0, 0 );
//24 glVertex3f calls & some colour changes go here.
gl2.glVertex3f(...)
gl2.glEnd();
gl2.glPopMatrix();
gl.glFlush();
}
It doesn't matter what values I put into the gluLookAt() matrix, the view doesn't change. I still end up looking at the same face of a cube.
Any ideas?
Thanks
EDIT: Responding to the edit in the original question. Leaving the original text below because people seem to find it to be useful.
I think your problem is in your cube drawing code. Check the commentary below: the glLoadIdentity call is doing exactly what you would expect - forcing the cube to be there in front of you:
gl2.glPushMatrix();
gl2.glClear( GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT );
/** Try removing the following glLoadIdentity call below.
* That call was blowing out the MODELVIEW matrix - it's removing your
* gluLookAt call and returning to the identity.
* As a result, the cube will always be right there in front of you.
*/
// gl2.glLoadIdentity();
gl2.glTranslatef(x, y, z);
gl2.glBegin( GL2.GL_QUADS );
gl2.glColor3f( 1, 0, 0 ); //24 glVertex3f calls & some colour changes go here.
gl2.glVertex3f(...)
gl2.glEnd();
gl2.glPopMatrix();
Here's a very quick explanation about what the related calls will do. See the documentation for more information:
gl2.glPushMatrix(); // This preserves current MODEL_VIEW matrix so you can get back here.
// Think of it as a checkpoint save in a game.
// Most of your objects will be wrapped in push and pop.
gl2.glLoadIdentity(); // This erases the MODEL_VIEW and replaces it with an identity.
// This un-does your previous gluLookAt call. You will rarely use
// this inside an object (but it's not impossible).
// Does not apply here so don't use.
gl2.glTranslatef(x, y, z); // This is what puts your object out in space for you to find
// as opposed to putting it at the origin. Most objects will
// have a translate (and likely a rotate as well).
// Note that the order of operations matters:
// translate and then rotate != rotate and then translate.
// QUAD strip code with vertices and colors - you're okay with these.
gl2.glPopMatrix(); // This brings back the MODEL_VIEW that you originally saved by pushing
// it.
The great thing about the matrix code in OpenGL is that once you get a portfolio of example code that you understand, you'll always have it as a reference. When I switched from IrisGL to OpenGL back in the day, it took me a little while to port my utilities over and then I never looked back.
ORIGINAL: You need to add your cube drawing code - if you are putting the cube in the vicinity of (0, 30, 0), it's highly likely that the code is doing what you asked it to.
Checking the OpenGL FAQ, there's a specific question and answer that is likely relevant to what you're doing: 8.080 Why doesn't gluLookAt work? I'm going to quote the whole answer as there really isn't a good break but please visit the OpenGL FAQ, the answer is likely there:
This is usually caused by incorrect
transformations.
Assuming you are using
gluPerspective() on the Projection
matrix stack with zNear and zFar as
the third and fourth parameters, you
need to set gluLookAt on the ModelView
matrix stack, and pass parameters so
your geometry falls between zNear and
zFar.
It's usually best to experiment with a
simple piece of code when you're
trying to understand viewing
transformations. Let's say you are
trying to look at a unit sphere
centered on the origin. You'll want to
set up your transformations as
follows:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(50.0, 1.0, 3.0, 7.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 0.0, 5.0,
0.0, 0.0, 0.0,
0.0, 1.0, 0.0);
It's important to note how the Projection
and ModelView transforms work
together.
In this example, the Projection
transform sets up a 50.0-degree field
of view, with an aspect ratio of 1.0.
The zNear clipping plane is 3.0 units
in front of the eye, and the zFar
clipping plane is 7.0 units in front
of the eye. This leaves a Z volume
distance of 4.0 units, ample room for
a unit sphere.
The ModelView transform sets the eye
position at (0.0, 0.0, 5.0), and the
look-at point is the origin in the
center of our unit sphere. Note that
the eye position is 5.0 units away
from the look at point. This is
important, because a distance of 5.0
units in front of the eye is in the
middle of the Z volume that the
Projection transform defines. If the
gluLookAt() call had placed the eye at
(0.0, 0.0, 1.0), it would produce a
distance of 1.0 to the origin. This
isn't long enough to include the
sphere in the view volume, and it
would be clipped by the zNear clipping
plane.
Similarly, if you place the eye at
(0.0, 0.0, 10.0), the distance of 10.0
to the look at point will result in
the unit sphere being 10.0 units away
from the eye and far behind the zFar
clipping plane placed at 7.0 units.
If this has confused you, read up on
transformations in the OpenGL red book
or OpenGL Specification. After you
understand object coordinate space,
eye coordinate space, and clip
coordinate space, the above should
become clear. Also, experiment with
small test programs. If you're having
trouble getting the correct transforms
in your main application project, it
can be educational to write a small
piece of code that tries to reproduce
the problem with simpler geometry.
Related
I'm making a top-down game where the camera centers the player in the middle of the screen. The code I have works, but I don't understand the eyeXYZ parameters. If I put a number less than 1000000000 like 100 the game will be very glitchy and the angle will no longer be perpendicular (top down).
Is there a better way to make a camera that follow the player from a top-down perspective in Processing? Here's what I have:
camera(0.0, 0.0, 1000000000, player.x+300, player.y, 0.0, 0.0, 1.0, 0.0);
ortho(-width, width, -height, height);
The first three parameters specify the position of your camera (the eye). Hence, if you want your camera to be over your player, then you should use:
camera(player.x, player.y, player.z + cameraHeight ...
cameraHeight is the distance of the camera over the player. Since you are using an orthographic view, this value doesn't really matter. It is only important for proper depth values (and that depends on the values for znear and zfar, which the Processing documentation isn't very helpful about).
The next three parameters are the position of the focus point. If you want to focus on the player, you should use:
... player.x, player.y, player.z ...
(I'm not sure what this +300 is supposed to do).
The last three parameters are the direction that points upwards in the image. The y-axis should be fine.
... 0.0, 1.0, 0.0);
And that's it.
The reason why your super-large z-coordinate of the eye worked is because this basically degenerated the +300 offset. In comparison to 1000000000, 300 is practically zero, which is why it looked perpendicular. When you decreased the z-coordinate, the influence of the 300 become stronger and the non-perpendicularity became more obvious.
I am working on an OpenGL game in Java with LWJGL (ThinMatrix's tutorials at the moment) and I just added my skybox. As you can see from the picture, however, it is clipping through the trees and covering everything behind a certain point.
Here is my rendering code for the skybox:
public void render(Camera camera, float r, float g, float b) {
shader.start();
shader.loadViewMatrix(camera);
shader.loadFogColor(r, g, b);
GL30.glBindVertexArray(cube.getVaoID());
GL20.glEnableVertexAttribArray(0);
bindTextures();
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, cube.getVertexCount());
GL30.glBindVertexArray(0);
shader.stop();
}
private void bindTextures() {
GL13.glActiveTexture(GL13.GL_TEXTURE0);
GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, texture);
GL13.glActiveTexture(GL13.GL_TEXTURE1);
GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, nightTexture);
shader.loadBlendFactor(getBlendFactor());
}
also if it is needed, here is my code for my master renderer:
public void render(List<Light> lights, Camera camera){
prepare();
shader.start();
shader.loadSkyColor(RED, GREEN, BLUE);
shader.loadLights(lights);
shader.loadViewMatrix(camera);
renderer.render(entities);
shader.stop();
terrainShader.start();
terrainShader.loadSkyColor(RED, GREEN, BLUE);
terrainShader.loadLight(lights);
terrainShader.loadViewMatrix(camera);
terrainRenderer.render(terrains);
terrainShader.stop();
skyboxRenderer.render(camera, RED, GREEN, BLUE);
terrains.clear();
entities.clear();
}
There are two things you can do
If you draw your skybox first, you can disable your depth test glDisable(GL_DEPTH_TEST) or your depth write glDepthMask(false). This will prevent that your skybox draws depth values, and the skybox will never be in front of anything that will be drawn later.
If you draw your skybox last, you can make it literally infinitely big by using vertex coordinates with a w-coordinate as 0. A vertex (x y z 0) means it is a vertex infinitely far in the direction of the vector (x y z). To prevent clipping, you have to enable depth clamping glEnable(GL_DEPTH_CLAMP) this will prevent OpenGl to clip away your skybox faces, and you are sure that the skybox is always at the maximum distance and will never hide anything you have drawn earlier.
the advantage of the second method is within the depth test. Because you already have a depth values written for your scene, the OpenGL pipeline can skip the calculation of the skybox pixels that are already covered by your scene. But the fragment shader for skyboxes is usually very trivial, so it shouldn't make that much of a difference.
I am not familiar with LWJGL, are you alllowed to write shader? In plain opengl, you don't have to worry about the size of skybox cube, it can be {1.0, 1.0, 1.0} if you like. What you need is first place your camera at {0.0, 0.0, 0.0} and make skybox fail depth test against everything in your scene, you can achieve that by making the skybox's z value in normalized device coordinate be 1.0.
Do this in your vertex shader
gl_Position = (mvp_mat * vec4(xyz, 1.0)).xyww;
after the perspective divide by w, z will be w / w or 1.0.
You might want to check out How can I increase distance (zfar/gluPerspective) where openGL stops drawing objects?
The problem in that instance is that the skybox itself was too small and intersecting with the geometry.
I also see that you're rendering your terrain first, and then your skybox. I would try flipping the order there; draw the skybox first then the terrain.
First, you should remove the skybox and render the scene again to check if it is skybox that clip the tree.
If it is skybox, simply scale the skybox to make it contain all the object in the terrain.
If not, it is likely to be the problem of camera (like Hanston said). You need to set the far clipping plane at least behind the skybox. That is, it should be larger the diameter of your skybox.
If you want to scale the skybox or any other object, use the transformationMatrix. the game engine use a 4x4 matrix to control the size, location and rotation of the model. you can see example in source TerrainRenderer.java, at function loadModelMatrix. It create a transform matrix and uploads it into the shader. You should do the same thing, but change the scale parameter into what you want.
I am writing a voxel engine and at the moment
I am working on the Chunk-Rendering-System but I have a problem.
It seems that the textures were repeated on the quads.
There is this green line at the bottom of the grass blocks and I don't know why.
This is the OpenGL-Render-Code:
Texture texture = TextureManager.getTexture(block.getTextureNameForSide(Direction.UP));
texture.bind();
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2d(0, 0); GL11.glVertex3f(0, 1, 0);
GL11.glTexCoord2d(1, 0); GL11.glVertex3f(0, 1, 1);
GL11.glTexCoord2d(1, 1); GL11.glVertex3f(1, 1, 1);
GL11.glTexCoord2d(0, 1); GL11.glVertex3f(1, 1, 0);
GL11.glEnd();
And here is the OpenGL-Setup:
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glShadeModel(GL11.GL_SMOOTH);
GL11.glClearColor(0.1F, 0.4F, 0.6F, 0F);
GL11.glClearDepth(1F);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glDepthFunc(GL11.GL_LEQUAL);
GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST);
GL11.glCullFace(GL11.GL_BACK);
GL11.glEnable(GL11.GL_CULL_FACE);
Make sure GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T are set to GL_CLAMP_TO_EDGE.
genpfault's answer should do the trick for you, I just wanted to give you some insight into why you need this particular wrap state.
To be clear, the green line in your screenshot corresponds to the edges of one of your voxels?
It looks like you are using GL_LINEAR filtering (default) together with an inappropriate texture wrap state (e.g. GL_REPEAT or GL_CLAMP). I will explain why GL_CLAMP is a bad idea later.
You may think that the texture coordinate 0.0 and 1.0 are perfectly within the normalized texture coordinate range and therefore not subject to wrapping, but you would be wrong.
This particular combination of states will pickup texels from the other side of your texture at either extreme of the [0,1] texture coordinate range. The texture coordinate 1.0 is actually slightly beyond the center of the last texel in your texture, so when GL fetches the 4 nearest texels for linear filtering, it wraps around to the other side of the texture for at least 2 of them.
GL_CLAMP_TO_EDGE modifies this behavior, it clamps the texture coordinates to a range that is actually more restrictive than [0,1] so that no coordinate goes beyond the center of any edge texels in your texture. Linear filtering will not pickup texels from the other side of your texture with this set. You could also (mostly) fix this by using GL_NEAREST filtering, but that will result in a lot of texture aliasing.
It is also possible that you are using GL_CLAMP, which, by the way was removed in OpenGL 3.1. In older versions of GL it was designed to clamp the coordinates into the range [0,1] and then if linear filtering tried to fetch a texel beyond the edge it would use a special set of border texels rather than wrapping around. Border texels are no longer supported, and thus that wrap mode is gone.
The bottom line is do not use GL_CLAMP, it does not do what most people think. GL_CLAMP_TO_EDGE is almost always what you really want when you think of clamping textures.
EDIT:
genpfault brings up a good point; this would be a lot easier to understand with a diagram...
The following diagram illustrates the problem in 1 dimension:
http://i.msdn.microsoft.com/dynimg/IC83860.gif
I have a more thorough explanation of this diagram in an answer I wrote to a similar issue.
How can I correctly figure out what values I must use for gl.glTranslatef(x,y,z), and similar methods. Example: I've got an square, and want to display it in the upper left corner, at about 1/4th of the screen. I figured it would be glTranslate() with values -0.5 and 0.5, but this doens't display where I expected it.
So basically I wan't to know how to find the right coordinates for objects in OpenGL-ES.
Unfortunately haven't developed opengl-es content for android yet, but AFAIK you need to convert screen coordinates (e.g. upper left corner on your screen) to world coordinates(coordinates in your 3D world in OpenGL).
For 3D you could do this would be through ray projection. You will find plenty of examples through google search and maybe a OpenGL implementation too.
For 2D you can get away bit using an orthogonal projection matrix(with no perspective distortion basically) and rotating it as needed (e.g. for lanscape mode):
// Initialize your projection matrix - current number are half the dimensions for the G1 I borrowed(320x480)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(-240.0f, 240.0f, -160.0f, 160.0f, -1.0f, 1.0f);
// Rotate everything by 90 degrees
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(-90.0f, 0.0f, 1.0f, 0.0f);
HTH
I've written several Android apps, but this is my first experience with 3D programming.
I've created a room (4 walls, ceiling and floor) with a couple objects inside and am able to move the camera around it as if walking. I've textured all surfaces with various images and everything was working as expected.
For context, the room is 14 units wide and 16 units deep (centered at origin), 3 units high (1 above origin and 2 below). There are 2 objects in the middle of the room, a cube and an inverted pyramid on top of it.
Then I went to add a light source to shade the cube and pyramid. I had read through and followed a couple of NeHe's ports, so I took what I had working in the lesson on lighting and applied it to my new code.
gl.glEnable(GL10.GL_LIGHTING);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, new float[] { 0.1f, 0.1f, 0.1f, 1f }, 0);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, new float[] { 1f, 1f, 1f, 1f }, 0);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, new float[] { -4f, 0.9f, 6f, 1f }, 0);
gl.glEnable(GL10.GL_LIGHT0);
The result is that the cube and pyramid are not shaded. They look the same on sides opposing the light as they do on the sides facing it. When the camera is pointed directly away from the light source the room looks as it did before I added the lighting code. As I rotate the camera to face the light source the entire room (including objects) becomes darker until completely black when the camera is directly facing the source.
What is going on here? I read many articles on lighting and how it works, but I have seen nothing to indicate why this wouldn't light up all sides of the room, with the cube and pyramid shaded based on the light position. Is there some expected behavior of the light because it is "inside" the room? Am I just missing something easy because I'm new?
Every object in your 3D world has a normal, where it helps OpenGL to determine how much light an object need to reflect. You've probably forgot to specify the normals for your surfaces. Without specifying them, OpenGL will light all objects in your world in the same way.
In order to get a surface's normal in 3D you need at least three vertices, which means it at least is a triangle.
Sample stuff:
In order to calculate a surface's normal you need two vectors. Since you have three vertices in 3D space that means that these sample points could contain a triangle:
// Top triangle, three points in 3D space.
vertices = new float[] {
-1.0f, 1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
0.0f, 1.0f, -1.0f,
}
Given these three points, you can now define two vectors by the following:
// Simple vector class, created by you.
Vector3f vector1 = new Vector3f();
Vector3f vector2 = new Vector3f();
vector1.x = vertices[0] - vertices[3];
vector1.y = vertices[1] - vertices[4];
vector1.z = vertices[2] - vertices[5];
vector2.x = vertices[3] - vertices[6];
vector2.y = vertices[4] - vertices[7];
vector2.z = vertices[5] - vertices[8];
Now when you have two vectors, you can finally get the surface's normal by using the Cross Product. Shortly, the cross product is an operation which results in a new vector containing an angle that is perpendicular to the input vectors. This is the normal that we need.
To get the cross product in your code you have to write your own method that calculates it. In theory you calculate the cross product given this formula:
A X B = (A.y * B.z - A.z * B.y, A.z * B.x - A.x * B.z, A.x * B.y - A.y * B.x)
In code (by using the vectors above):
public Vector3f crossProduct(Vector3f vector1, Vector3f vector2) {
Vector3f normalVector = new Vector3f();
// Cross product. The normalVector contains the normal for the
// surface, which is perpendicular both to vector1 and vector2.
normalVector.x = vector1.y * vector2.z - vector1.z * vector2.y;
normalVector.y = vector1.z * vector2.x - vector1.x * vector2.z;
normalVector.z = vector1.x * vector2.y - vector1.y * vector2.x;
return normalVector;
}
Before any further comments; you can specify your normals in an array and just put them into OpenGL when needed, but your understanding of this topic will be much better if you dig into it and your code will be much more flexible.
So now we have a normal which you can loop through, assign the vector values to your normal array (like NeHe's ports, but dynamically) and set up OpenGL to use GL_NORMAL_ARRAY in order to get OpenGL to reflect the light on the object correctly:
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
// I'm assuming you know how to put it into a FloatBuffer.
gl.glNormalPointer(GL10.GL_FLOAT, 0, mNormalsBuffer);
// Draw your surface...
Another last comment; if you're using other vertices values (like 5.0f, 10.0f or bigger) you might wanna normalize the vector that returns from the crossProduct() method in order to gain some performance. Otherwise OpenGL must calculate the new vector to get the unit vector and that might be a performance issue.
Also, your new float[] {-4f, 0.9f, 6f, 1f} for GL_POSITION is not quite correct. When the fourth value is set to 1.0f it means that the light position is 0, 0, 0, no matter what the first three values are. In order to specify a vector for your light position, change the fourth value to 0.0f.
You need to reload the light position each frame, otherwise the light source will move with the camera which is probably not what you want. Also the shading you are describing is totally consistent with vertex interpolated lighting. If you want something better you will have to do it per-pixel (which means implementing your own shader), or else subdivide your geometry.