Related
In LWJGL 3.2.1 I'm drawing a triangle using vertices and viewing it with a perspective (frustum) projection. I'm trying to use the triangle to orientate myself in 3D space to figure out where I am and how to direct myself. When I rotate the triangle, it gets smaller instead of rotating around the set point.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(0, windowWidth, windowHeight, 0, 0, 100);
glMatrixMode(GL_MODELVIEW);
while (!glfwWindowShouldClose(window))
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glMatrixMode(GL_PROJECTION);
glRotatef(5f, 0f, 0f, 0f);
glMatrixMode(GL_MODELVIEW);
glBegin(GL_POLYGON);
glVertex3f(-0f, -0f, 0f);
glVertex3f(0f, 1f, 0f);
glVertex3f(1f, 1f, 0f);
glEnd();
glPopMatrix();
glfwSwapBuffers(window);
glfwPollEvents();
}
Am I rotating it incorrectly or something?
I have been trying to render a VBO that is 1/3 of the size of the screen resolution of the screen to a Quad that is the size of the screen. What am I doing wrong?
public void initGL() {
frameBufferID = glGenFramebuffersEXT();
colorBufferID = glGenTextures();
depthBufferID = glGenRenderbuffersEXT();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBufferID);
glBindTexture(GL_TEXTURE_2D, colorBufferID);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, WIDTH / SCALE, HEIGHT / SCALE, 0, GL_RGBA, GL_INT, (java.nio.ByteBuffer)null);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, colorBufferID, 0);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthBufferID);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL14.GL_DEPTH_COMPONENT24, WIDTH / SCALE, HEIGHT / SCALE);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthBufferID);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
public void render() {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
GLU.gluPerspective(90.0f, WIDTH/(float)HEIGHT, 0.001f, 1000.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0, 0, WIDTH / SCALE, HEIGHT / SCALE);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBufferID);
glClearColor(1.0f, 0.0f, 0.0f, 0.5f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1, 1, 1);
// Render game code here
glBegin(GL_LINES);
{
glVertex2f(0, 0);
glVertex2f(1, 1);
}
glEnd();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, WIDTH, 0, HEIGHT, 0.001f, 1000.0f);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glBindTexture(GL_TEXTURE_2D, colorBufferID);
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, WIDTH, HEIGHT);
glTranslatef(0, 0, -1);
//Draw Quad
glBegin(GL_QUADS);
{
glTexCoord2f(0, 0);
glVertex2f(0, 0);
glTexCoord2f(1, 0);
glVertex2f(WIDTH, 0);
glTexCoord2f(1, 1);
glVertex2f(WIDTH, HEIGHT);
glTexCoord2f(0, 1);
glVertex2f(0, HEIGHT);
}
glEnd();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
I'm trying to render the things in the VBO in Perspective, and then draw the fullscreen Quad in Orthographic. But everything I've tried doesn't work... Like at all. Is there anything I've screwed up?
You are rendering a quad with a completely red texture in front of a red background, so there is not much to see.
The lines you are trying to render into the texture are actually outside of the frustum, as you draw in the z=0 plane, while your frustum is in the range z=[-0.001,-1000].
For debugging purposes, I recommend to change the clear color between your two draw passes, so that you can better see which of the two passes fails.
I am making a 3D game that has a player with the follow cam. Before I started using real models I used the cube and I rendered it using displaylist and it everything moved fine. However, now that I am importing full 3D models with many more vertices, I looked into VBOs. I have a full structure setup for my VBOs and I can see the model drawn initially but it is drawn at the center of the game world. When I move the player, the model doesn't translate as it should. The model doesn't move its position.
Here is the code that I used initially to draw the player as a rectangle (which works):
public static void drawRectPrism(float centerx, float centery, float centerz, float length, float height, float width, float rx, float ry, float rz)
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
{
glTranslatef(centerx, centery, centerz);
glRotatef(rx, 1, 0, 0);
glRotatef(ry, 0, 1, 0);
glRotatef(rz, 0, 0, 1);
glTranslatef(-centerx, -centery, -centerz);
glTranslatef(-length/2f, -height/2f, -width/2f);
glBegin(GL_QUADS);
{
glColor3f(1.0f, 0, 0);
glVertex3f(centerx, centery, centerz);
glVertex3f(centerx + length, centery, centerz);
glVertex3f(centerx + length, centery + height, centerz);
glVertex3f(centerx, centery + height, centerz);
glColor3f(0, 1.0f, 0);
glVertex3f(centerx, centery, centerz + width);
glVertex3f(centerx + length, centery, centerz + width);
glVertex3f(centerx + length, centery + height, centerz + width);
glVertex3f(centerx, centery + height, centerz + width);
glColor3f(0, 0, 1.0f);
glVertex3f(centerx, centery, centerz);
glVertex3f(centerx, centery + height, centerz);
glVertex3f(centerx, centery + height, centerz + width);
glVertex3f(centerx, centery, centerz + width);
glColor3f(0, 1.0f, 1.0f);
glVertex3f(centerx + length, centery, centerz);
glVertex3f(centerx + length, centery + height, centerz);
glVertex3f(centerx + length, centery + height, centerz + width);
glVertex3f(centerx + length, centery, centerz + width);
glColor3f(1.0f, 1.0f, 0);
glVertex3f(centerx, centery, centerz);
glVertex3f(centerx + length, centery, centerz);
glVertex3f(centerx + length, centery, centerz + width);
glVertex3f(centerx, centery, centerz + width);
glColor3f(1.0f, 0, 1.0f);
glVertex3f(centerx, centery + height, centerz);
glVertex3f(centerx + length, centery + height, centerz);
glVertex3f(centerx + length, centery + height, centerz + width);
glVertex3f(centerx, centery + height, centerz + width);
}
glEnd();
}
glPopMatrix();
}
I tried a couple of different ways somewhere better than others and probably implemented terrible programming structure, but I figured it should still work.
First attempt: to adapt the rectangle code to load my vertices and models instead of specific rectangle verticies:
public void translate(float x, float y, float z, float rx, float ry, float rz)
{
File f = new File("graveDigga.obj");
try{
m = OBJLoader.loadModel(f);
}
catch(FileNotFoundException e)
{
e.printStackTrace();
Display.destroy();
System.exit(1);
}
catch(IOException e)
{
e.printStackTrace();
Display.destroy();
System.exit(1);
}
displayListChar = glGenLists(1);
glNewList(displayListChar, GL_COMPILE);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
{
glTranslatef(x, y, z);
glRotatef(rx, 1, 0, 0);
glRotatef(ry, 0, 1, 0);
glRotatef(rz, 0, 0, 1);
//glTranslatef(-x, -y, -z);
//glTranslatef(-length/2f, -height/2f, -width/2f);
glBegin(GL_TRIANGLES);
for(Face face : m.faces)
{
Vector2f t1 = m.textures.get((int) face.textures.x - 1);
glTexCoord2f(t1.x +x ,1-(t1.y +y ));
Vector3f n1 = m.normals.get((int) face.normal.x-1);
glNormal3f(n1.x +x ,n1.y+y,n1.z +z);
Vector3f v1 = m.vertices.get((int) face.vertex.x-1);
glVertex3f(v1.x +x,v1.y+y,v1.z+z);
Vector2f t2 = m.textures.get((int) face.textures.y - 1);
glTexCoord2f(t2.x +x, 1 - (t2.y+y ));
Vector3f n2 = m.normals.get((int) face.normal.y-1);
glNormal3f(n2.x+x,n2.y+y ,n2.z+z);
Vector3f v2 = m.vertices.get((int) face.vertex.y-1);
glVertex3f(v2.x+x,v2.y+y ,v2.z+z);
Vector2f t3 = m.textures.get((int) face.textures.z - 1);
glTexCoord2f(t3.x +x, 1 - (t3.y +y));
Vector3f n3 = m.normals.get((int) face.normal.z-1);
glNormal3f(n3.x+x,n3.y+y,n3.z +z);
Vector3f v3 = m.vertices.get((int) face.vertex.z-1);
glVertex3f(v3.x+x,v3.y+y,v3.z +z);
}
glEnd();
}
glPopMatrix();
//}
//glPopMatrix();
build();
}
I next tried to display model by creating a VBO from this data and call a rander method in my game loop. Before calling render I would run through the code to attempt to translate the position of VBO but nothing was happening.
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
{
//glLoadIdentity();
glTranslatef(x,y,z);
glRotatef(rx, 1, 0, 0);
glRotatef(ry, 0, 1, 0);
glRotatef(rz, 0, 0, 1);
glTranslatef(-x,-y,-z);
glDrawArrays(GL_TRIANGLES, 0, m.faces.size() * 3);
}
I am not sure if I should be using shaders for this or not, but part of me is questioning why it is hard to move a 3D model in world space? Is there a messy way that is easier to implement for a temporary basis?
Considering you're a new person with 1 rep, have an upvote. Nicely written question :).
I am not sure if I should be using shaders for this or not, but part of me is questioning why it is hard to move a 3D model in world space? Is there a messy way that is easier to implement for a temporary basis?
A simple glTranslatef() call should suffice to move an object, and simple glRotatef() call will rotate the object.
For example, using glRotatef(90, 1, 0, 0) returns this result:
Wheras without the line, the grass is not rotated at all:
Same with the ship. Using glRotatef(40, -1, 0, 0) returns this result:
Wheras without the line it just returns flat:
Obviously that is just the pitch. glRotatef(AmountToRotate, PITCH, YAW, ROLL) can roll the ship onto its side, or rotate the ship around.
Enough about rotation.
For rendering the grass, I just use this:
public void render(){
Main.TerrainDemo.shader.start();
glPushMatrix();
glDisable(GL_LIGHTING);
glTranslatef(location.x * TerrainDemo.scale, location.y, location.z * TerrainDemo.scale);
TexturedModel texturedModel = TerrainDemo.texModel;
RawModel model = texturedModel.getRawModel();
GL30.glBindVertexArray(model.getVaoID());
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(1);
GL13.glActiveTexture(GL13.GL_TEXTURE0);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texturedModel.getTexture().getID());
glScalef(10f, 10f, 10f);
glColor4f(0, 0, 0, 0.5f);
glDrawElements(GL_TRIANGLES, model.getVertexCount(), GL11.GL_UNSIGNED_INT, 0);
GL20.glDisableVertexAttribArray(0);
GL20.glDisableVertexAttribArray(1);
GL30.glBindVertexArray(0);
glEnable(GL_LIGHTING);
glPopMatrix();
Main.TerrainDemo.shader.stop();
}
To cut through code which you will probably not recognize/understand, I am basically just saying that glTranslatef(location.x * TerrainDemo.scale, location.y, location.z * TerrainDemo.scale) is the only thing that is setting the location. After translating, I simple set the scale (the size), and then draw it.
Wheras if I remove the glTranslatef() line, all the grass will just render in the same location:
So to answer your question:
use something like this (Psuedocode)
PUSH MATRIX HERE (glPushMatrix) SO TO NOT SAVE THE CURRENT TRANSLATION
USE GLTRANSLATEF ON LOCATION OF CURRENT OBJECT
RENDER/DRAW OBJECT
POP THE MATRIX
Unfortunately, looking through your code I could'nt find the specific issue that is actually causing it not to draw, meaning I cannot just say "Have xxx code and it will work", but I hope that it helped on how to move/rotate an object.
I am using VBOs just like you are for rendering the grass, ship, and trees (though I use a display list for terrain because I am lazy).
My skype is joehot200 if you wish to discuss anything further.
First, I'll start with my code because I've identified which block is causing the issue.
// init
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, 800, 0, 600, 1, -1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glEnable(GL11.GL_TEXTURE_2D);
// BEGINNING OF OFFENDING CODE
BufferedImage image = ImageIO.read(new File("res/button.png"));
int[] pixels = new int[image.getWidth() * image.getHeight()];
image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
IntBuffer buffer = BufferUtils.createIntBuffer(pixels.length);
for (int pixel : pixels)
buffer.put(pixel);
buffer.flip();
int button = GL11.glGenTextures();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, button);
//Setup wrap mode
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, image.getWidth(), image.getHeight(), 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);
// END OF OFFENDING CODE
This is what things are supposed to look like without the textured quad.
This is what happens when I render with the offending code (with the textured quad).
This is what happens when I render with the offending code (without the textured quad).
For reference, this is the texture
I can't seem to figure out which GL11 call is affecting the rest of the Display and why it would be affecting the rest of the display. From what I understand, all of the calls that follow GL11.glBindTexture are limited to the bound texture, aren't they?
Edit: Additional Rendering Code
private static void renderQuad(int x, int y, int width, int height) {
GL11.glPushMatrix();
GL11.glBegin(GL11.GL_QUADS);
GL11.glVertex2f(x, y);
GL11.glVertex2f(x + width, y);
GL11.glVertex2f(x + width, y + height);
GL11.glVertex2f(x, y + height);
GL11.glEnd();
GL11.glPopMatrix();
}
The method used for the red quads.
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
GL11.glColor3f(0.5f,0.5f,1.0f);
renderQuad(0, 0, 800, 600);
// render action bar
GL11.glColor3f(0.2f,0.2f,1.0f);
renderQuad(0, 0, 800, 200);
GL11.glColor3f(1.0f,0.0f,0.0f);
renderQuad(50, 50, 100, 60);
renderQuad(200, 50, 100, 60);
// render textured quad
GL11.glPushMatrix();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, button);
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2d(0.0,1.0);
GL11.glVertex2f(x, y);
GL11.glTexCoord2d(1.0,1.0);
GL11.glVertex2f(x + width, y);
GL11.glTexCoord2d(1.0,0.0);
GL11.glVertex2f(x + width, y + height);
GL11.glTexCoord2d(0.0,0.0);
GL11.glVertex2f(x, y + height);
GL11.glEnd();
GL11.glPopMatrix();
First of all, I think there's a problem with your texture loading. I believe the order of the bytes is reversed or something similar, which is why you get the red on black. Here's a working load-texture-from-BufferedImage example taken from my own code:
BufferedImage image = ImageIO.read(new File("<file path>.png"));
int[] pixels = new int[image.getWidth() * image.getHeight()];
image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
ByteBuffer buffer = BufferUtils.createByteBuffer(image.getWidth() * image.getHeight() * 4);
for(int y = 0; y < image.getHeight(); y++){
for(int x = 0; x < image.getWidth(); x++){
int pixel = pixels[y * image.getWidth() + x];
buffer.put((byte) ((pixel >> 16) & 0xFF)); // Red component
buffer.put((byte) ((pixel >> 8) & 0xFF)); // Green component
buffer.put((byte) (pixel & 0xFF)); // Blue component
buffer.put((byte) ((pixel >> 24) & 0xFF)); // Alpha component. Only for RGBA
}
}
buffer.flip(); //FOR THE LOVE OF GOD DO NOT FORGET THIS
// You now have a ByteBuffer filled with the color data of each pixel.
// Now just create a texture ID and bind it. Then you can load it using
// whatever OpenGL method you want, for example:
int textureID = GL11.glGenTextures(); //Generate texture ID
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID); //Bind texture ID
//Setup wrap mode
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
//Setup texture scaling filtering
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
//Send texel data to OpenGL
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, image.getWidth(), image.getHeight(), 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);
Now, to the actual rendering problem:
For OpenGL, GL_TEXTURE_2D must be enabled or disabled depending on whether or not the polygon you are drawing is textured. If you do not supply texture coordinates for each vertex, then the last texture coords call still holds and is used for each vertex. So, you'll get a quad using one pixel's worth of texture. This is what's causing the black quads - it's taking from one pixel from a corner of your improperly loaded texture. So, your fixed rendering code:
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glColor3f(0.5f,0.5f,1.0f);
renderQuad(0, 0, 800, 600);
// render action bar
GL11.glColor3f(0.2f,0.2f,1.0f);
renderQuad(0, 0, 800, 200);
GL11.glColor3f(1.0f,0.0f,0.0f);
renderQuad(50, 50, 100, 60);
renderQuad(200, 50, 100, 60);
GL11.glEnable(GL11.GL_TEXTURE_2D);
// render textured quad
GL11.glColor3f(1.0f, 1.0f, 1.0f);
GL11.glPushMatrix();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, button);
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2d(0.0,1.0);
GL11.glVertex2f(x, y);
GL11.glTexCoord2d(1.0,1.0);
GL11.glVertex2f(x + width, y);
GL11.glTexCoord2d(1.0,0.0);
GL11.glVertex2f(x + width, y + height);
GL11.glTexCoord2d(0.0,0.0);
GL11.glVertex2f(x, y + height);
GL11.glEnd();
GL11.glPopMatrix();
On a side note, you can use simply glEnable() instead of GL11.glEnable() if you do:
import static org.lwjgl.opengl.GL11.*;
instead of simply
import org.lwjgl.opengl.GL11;
So I'm using gluProject to take the 3d coordinates and tell me where on the screen they rendered. The problem is I don't get the same coordinates with gluProject and where they actually ended up rendering. The weird part is that if the difference between the x, y, and z of the camera and the point i'm testing are equal (e.g. camera at 5,3,4 and point at 2,0,1) it gives the correct values. I'm using gluLookAt() for camera transforms. I have confirmed that the same matrices that I use for rendering are being passed in to gluProject. Below is my rendering code, camera.look(), and my part with gluProject:
Rendering:
glEnable(GL_LIGHTING);
glEnable(GL_NORMAL_ARRAY);
glViewport(0, 0, Display.getHeight(), Display.getHeight());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90.0f, 1, .1f, 1000f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
cam.look();
for (Cube cube : cubes) {
cube.draw();
}
grid.draw();
Camera.look():
void look() {
calcPoints(xAng, yAng);
gluLookAt(x, y, z, x + dx, y + dy, z + dz, 0, 1, 0);
}
part with gluProject:
glViewport(0, 0, Display.getHeight(), Display.getHeight());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90.0f, 1, .1f, 1000f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
cam.look();
modelview = BufferUtils.createFloatBuffer(16); //floatbuffers, defined earlier
projection = BufferUtils.createFloatBuffer(16);
viewport = BufferUtils.createIntBuffer(16);
FloatBuffer result = BufferUtils.createFloatBuffer(3);
glGetFloat(GL_MODELVIEW_MATRIX, modelview);
glGetFloat(GL_PROJECTION_MATRIX, projection);
glGetInteger(GL_VIEWPORT, viewport);
gluProject(1f, 0f, 0f, modelview, projection, viewport, result);
//Utils.printFloatBuffer(projection);
//Utils.printFloatBuffer(modelview);
System.out.println(result.get(0) + " " + result.get(1) + " " + result.get(2));
Maybe try having the up vector at a right angle to the camera direction and position instead of (0, 1, 0) constantly.