Trying to draw wavefront obj files using OpenGL but it seems there is a depth-buffer problem.
Source:
// Default constructor
Engine::Engine()
{
initialize();
loadModel();
start();
}
// Initialize OpenGL
void Engine::initialize()
{
// Enable depth test
glEnable(GL_DEPTH_TEST);
// Enable depth write
glDepthMask(GL_TRUE);
}
void Engine::start()
{
// Main loop
while(isOpen())
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Draw 3D model to screen
draw();
}
}
Things to check:
Make sure depth test is enabled glEnable(GL_DEPTH_TEST)
Make sure depth write is enabled glDepthMask(true)
Make sure your context has a depth buffer Assert(glGetIntegerv(GL_DEPTH_BITS) != 0))
Did you activated the depth test?
glEnable(GL_DEPTH_TEST);
Request a GL context with a depth buffer and glEnable(GL_DEPTH_TEST).
Try this:
mainWindow.create
(
sf::VideoMode
(
settings.getWidth(),
settings.getHeight()
),
"",
sf::Style::Resize,
sf::ContextSettings( 16, 0, 0, 2, 0 )
);
Are you using vertex shaders? This thing would happen if at the exit of vertex shader gl_Position.z is accidentally set to 0. Or to any value between -1 and 1 I believe.
It would also happen if all vertices had equal z value before the input stage, albeit there must be something wrong with your transformation matrices in this case. Or simply you may be doing something very exotic with your transformation matrices, and the model is fine. Have you set up both MODELVIEW and PROJECTION, and multiplied them accordingly? Either in the vertex shader or in the FFP?
Related
So I'm trying to render a basic overlay onto my 3D scene, and currently I can either have the 3D scene or the 2D overlay, I cant work out how to get both
In my main method, where render is called, I moved specific render functions to manager classes, so in the main render I call :
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-aspect, aspect, -1, 1, -10, 10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
material.setColour(new Vector3f(1,1,1));
sLight.getPointLight().setPosition(camera.getPosition());
sLight.setDirection(camera.getForward());
DayCycle.getInstance().update(Time.getDelta());
shader.updateUniforms(transform.getTransformation(), transform.getProjectedTransformation(), material);
//material is a wrapper class for textures and specular value etc
//transform is a matrix wrapper for getting projected transformations, taking the camera position when its created
WorldManager.renderAll(true); //true denotes yes to wireframe mode
InterfaceManager.renderAll();
glfwSwapBuffers(window);
glfwPollEvents();
If i comment out WorldManager.renderAll(), I get the little 2d square in the right part of the screen, If i dont comment it, I get the world render but no little square
WorldManager.renderAll()
public static void renderAll(boolean wireframeMode)
{
RendererUtils.setWireframeMode(wireframeMode);
for (String s : chunks.keySet())
{
Chunk actingChunk = chunks.get(s);
Transform transform = new Transform();
Shader shader = PhongShader.getInstance();
transform.setTranslation(new Vector3f(actingChunk.getLocation().getX() * (Chunk.ChunkSize),0.0f, actingChunk.getLocation().getY() * (Chunk.ChunkSize)));
transform.setScale(1.0f, 50f, 1.0f);
shader.updateUniforms(transform.getTransformation(), transform.getProjectedTransformation(), actingChunk.getMaterial());
shader.bind();
actingChunk.getMesh().draw();
//transform.setRotation(new Vector3f(0,0,0));
}
}
InterfaceManager.renderAll()
public static void renderAll()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, 0, height, -10, 10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
RendererUtils.setWireframeMode(false);
for (Interface i : interfaces)
{
Transform transform = new Transform();
transform.setTranslation(new Vector3f(0,0,0));
InterfaceShader.getInstance().updateUniforms(transform.getProjectedTransformation());
InterfaceShader.getInstance().bind();
i.getMesh().draw();
}
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
}
When I have WorldManager.renderAll() uncommented, i get a nice sea of triangles (as its meant to look) but no 2D square
With it commented, I get a nice little square where its meant to be and nothing else
Shaders are here : https://pastebin.com/xWaWhQHy because I felt this post was getting too long to have them inlined
What's my problem? I cant figure out where it is
Edit : If i've missed any pertinent code, tell me and i'll upload it to a pastebin
Edit 2 : updated my code here to reflect that i'd removed a shader in interfaceManager to actually get a square to draw at all : https://pastebin.com/pHHDsCvF for the shader code
Edit 3 : Ive determined it's something to do with my interface shaders, If i use PhongShader instead of InterfaceShader then it works exactly how I wanted it to
I can suggest you to modify the code this way:
WorldManager.renderAll(true); //true denotes yes to wireframe mode
glClear(GL_DEPTH_BUFFER_BIT);
InterfaceManager.renderAll();
This way you will clear depth buffer before rendering 2d interface.
The problem was that I was still applying transformations to the vertices after passing them to the shader.
By editing out the transformation (and later scrapping the entire vertex shader) in the InterfaceShader instance, the little squares were appearing in the right place
I take multiple images of the same mesh using OpenGL, GLEW and GLFW. The mesh (triangles) doesn't change in each shot, only the ModelViewMatrix does.
Here's the important code of my mainloop:
for (int i = 0; i < number_of_images; i++) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
/* set GL_MODELVIEW matrix depending on i */
glBegin(GL_TRIANGLES);
for (Triangle &t : mesh) {
for (Point &p : t) {
glVertex3f(p.x, p.y, p.z);
}
}
glReadPixels(/*...*/) // get picture and store it somewhere
glfwSwapBuffers();
}
As you can see, I set/transfer the triangle vertices for each shot I want to take. Is there a solution in which I only need to transfer them once? My mesh is quite large, so this transfer takes quite some time.
In the year 2016 you must not use glBegin/glEnd. No way. Use Vertex Array Obejcts instead; and use custom vertex and/or geometry shaders to reposition and modify your vertex data. Using these techniques, you will upload your data to the GPU once, and then you'll be able to draw the same mesh with various transformations.
Here is an outline of how your code may look like:
// 1. Initialization.
// Object handles:
GLuint vao;
GLuint verticesVbo;
// Generate and bind vertex array object.
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// Generate a buffer object.
glGenBuffers(1, &verticesVbo);
// Enable vertex attribute number 0, which
// corresponds to vertex coordinates in older OpenGL versions.
const GLuint ATTRIBINDEX_VERTEX = 0;
glEnableVertexAttribArray(ATTRIBINDEX_VERTEX);
// Bind buffer object.
glBindBuffer(GL_ARRAY_BUFFER, verticesVbo);
// Mesh geometry. In your actual code you probably will generate
// or load these data instead of hard-coding.
// This is an example of a single triangle.
GLfloat vertices[] = {
0.0f, 0.0f, -9.0f,
0.0f, 0.1f, -9.0f,
1.0f, 1.0f, -9.0f
};
// Determine vertex data format.
glVertexAttribPointer(ATTRIBINDEX_VERTEX, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Pass actual data to the GPU.
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*3*3, vertices, GL_STATIC_DRAW);
// Initialization complete - unbinding objects.
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
// 2. Draw calls.
while(/* draw calls are needed */) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(vao);
// Set transformation matrix and/or other
// transformation parameters here using glUniform* calls.
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0); // Unbinding just as an example in case if some other code will bind something else later.
}
And a vertex shader may look like this:
layout(location=0) in vec3 vertex_pos;
uniform mat4 viewProjectionMatrix; // Assuming you set this before glDrawArrays.
void main(void) {
gl_Position = viewProjectionMatrix * vec4(vertex_pos, 1.0f);
}
Also take a look at this page for a good modern accelerated graphics book.
#BDL already commented that you should abandon the immediate mode drawing calls (glBegin … glEnd) and switch to Vertex Array drawing (glDrawElements, glDrawArrays) that fetch their data from Vertex Buffer Objects (VBOs). #Sergey mentioned Vertex Array Objects in his answer, but those are actually state containers for VBOs.
A very important thing you have to understand – and the way you asked your question it's apparently something you're not aware of, yet – is, that OpenGL does not deal with "meshes", "scenes" or the like. OpenGL is just a drawing API. It draws points… lines… and triangles… one at a time… with no connection between them whatsoever. That's it. So when you show multiple views of the "same" thing, you must draw it several times. There's no way around this.
Most recent versions of OpenGL support multiple viewport rendering, but it still takes a geometry shader to multiply the geometry into several pieces to be drawn.
I've just implemented deferred rendering and am having trouble getting my skybox working. I try rendering my skybox at the very end of my rendering loop and all I get is a black screen. Here's the rendering loop:
//binds the fbo
gBuffer.Bind();
//the shader that writes info to gbuffer
geometryPass.Bind();
glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
//draw geometry
geometryPass.SetUniform("model", transform.GetModel());
geometryPass.SetUniform("mvp", camera.GetViewProjection() * transform.GetModel());
mesh3.Draw();
geometryPass.SetUniform("model", transform2.GetModel());
geometryPass.SetUniform("mvp", camera.GetViewProjection() * transform2.GetModel());
sphere.Draw();
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT);
//shader that calculates lighting
pointLightPass.Bind();
pointLightPass.SetUniform("cameraPos", camera.GetTransform().GetPosition());
for (int i = 0; i < 2; i++)
{
pointLightPass.SetUniformPointLight("light", pointLights[i]);
pointLightPass.SetUniform("mvp", glm::mat4(1.0f));
//skybox.GetCubeMap()->Bind(9);
quad.Draw();
}
//draw skybox
glEnable(GL_DEPTH_TEST);
skybox.Render(camera);
window.Update();
window.SwapBuffers();
The following is the skybox's render function
glCullFace(GL_FRONT);
glDepthFunc(GL_LEQUAL);
m_transform.SetPosition(camera.GetTransform().GetPosition());
m_shader->Bind();
m_shader->SetUniform("mvp", camera.GetViewProjection() * m_transform.GetModel());
m_shader->SetUniform("cubeMap", 0);
m_cubeMap->Bind(0);
m_cubeMesh->Draw();
glDepthFunc(GL_LESS);
glCullFace(GL_BACK);
And here is the skybox's vertex shader:
layout (location = 0) in vec3 position;
out vec3 TexCoord;
uniform mat4 mvp;
void main()
{
vec4 pos = mvp * vec4(position, 1.0);
gl_Position = pos.xyww;
TexCoord = position;
}
The skybox's fragment shader just sets the output color to texture(cubeMap, TexCoord).
As you can see from the vertex shader, I'm setting the position's z component to be w so that it will always have a depth of 1. I am also setting the depth function to be GL_LEQUAL so that it will fail the depth test. Should this not only draw the skybox in places where other objects weren't already drawn? Why does it result in a black screen?
I know I have set up the skybox correctly because if I just draw the skybox by itself it shows up just fine.
I can briefly see for a split second the geometry that should be drawn before the skybox is drawn on top of everything.
Since you're using double buffering, seeing different things must be due to a different frame being drawn. The depth buffer in the default framebuffer isn't being cleared, which I believe is the cause of the temporal instability at least.
In your case, you want the default depth buffer to be the same as the GBuffer when you draw the skybox. A quick way to achieve this is with glBlitFramebuffer, also avoiding the need to clear it:
glBindFramebuffer(GL_READ_FRAMEBUFFER, gbuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(..., GL_DEPTH_BUFFER_BIT, ...);
Now to explain the black screen when the skybox fills the screen. Without the depth test, of course the skybox just draws. With the depth test, the skybox still draws on the first frame, but shortly after the second frame clears only the colour buffer. The depth buffer still contains stale skybox values so it does not get re-draw for this frame and you're left with black...
However your geometry pass draws without depth testing enabled, so this should still be visible even if the skybox isn't. Also this would only happen with GL_LESS and you have GL_LEQUAL. And you have glDepthMask false, which means nothing should write to the default depth buffer in your code. This points to the depth buffer containing other values, perhaps uninitialized, but in my experience it's initially zero. Also this still happens when the skybox doesn't fill the screen, drawn as a cube away from the camera, which blows away that argument. Now, perhaps if the geometry failed to draw in the second frame that would explain it. For that matter blatant driver bugs would too, but I'm not seeing any problems in the given code.
TLDR: Many unexplained things, so **I tried it myself and can't reproduce your problem...
Here's a quick example based on your code and it works fine for me...
(green sphere is the geometry, red cube is the skybox)
gl_Position = pos:
Note the yellow from additive blending even if the skybox is drawn over the top. I would have thought you'd be seeing this too.
gl_Position = pos.xyww:
Now for the code...
//I haven't enabled back face culling, but that shouldn't affect anything
//binds the fbo
fbo.bind();
//the shader that writes info to gbuffer
//geometryPass.Bind(); //fixed pipeline for now
glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glColor3f(0,1,0);
fly.uploadCamera(); //glLoadMatrixf
sphere.draw();
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
fbo.unbind(); //glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT);
//shader that calculates lighting
drawtex.use();
//pointLightPass.SetUniform("cameraPos", camera.GetTransform().GetPosition());
drawtex.set("tex", *(Texture2D*)fbo.colour[0]);
for (int i = 0; i < 2; i++)
{
//pointLightPass.SetUniformPointLight("light", pointLights[i]);
//pointLightPass.SetUniform("mvp", glm::mat4(1.0f));
//skybox.GetCubeMap()->Bind(9);
drawtex.set("modelviewMat", mat44::identity());
quad.draw();
}
drawtex.unuse();
//draw skybox
glEnable(GL_DEPTH_TEST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, fbo.size.x, fbo.size.y, 0, 0, fbo.size.x, fbo.size.y, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
//glCullFace(GL_FRONT);
glDepthFunc(GL_LEQUAL);
//m_transform.SetPosition(camera.GetTransform().GetPosition());
skybox.use();
skybox.set("mvp", fly.camera.getProjection() * fly.camera.getInverse() * mat44::translate(1,0,0));
//m_shader->SetUniform("mvp", camera.GetViewProjection() * m_transform.GetModel());
//m_shader->SetUniform("cubeMap", 0);
//m_cubeMap->Bind(0);
cube.draw();
skybox.unuse();
glDepthFunc(GL_LESS);
//glCullFace(GL_BACK);
//window.Update();
//window.SwapBuffers();
Hi guys and girls the problem I have is I have sucessfully loaded 3 BMP textures (or at least I hope I have using char* textureFilenames[textureCount] = {"cement.bmp","hedge.bmp","sky.bmp"};
and I'm applying it currently using
glTexCoord2f(0.0,0.0);
glVertex3f(-150.0, 0.0, -150.0);
glTexCoord2f(1.0,0.0);
glVertex3f(-150.0, 0.0, 150.0);
glTexCoord2f(1.0,1.0);
glVertex3f(150.0, 0.0, 150.0);
glTexCoord2f(0.0,1.0);
glVertex3f(150.0, 0.0, -150.0);
however it currently only picks up the sky.bmp is there anyway i can select one of the others?
OpenGL is a state machine. The current texture is part of the OpenGL state. The last texture you bind with glBindTexture() will be used until you bind another.
glBindTexture(GL_TEXTURE_2D, cement_texture_id);
// ... following geometry will use the cement texture
glBindTexture(GL_TEXTURE_2D, hedge_texture_id);
// ... hedge texture
glBindTexture(GL_TEXTURE_2D, sky_texture_id);
// ... sky texture
The "OpenGL RedBook" has a chapter on texture mapping that covers the basics.
You mistake lies in your lack of understanding of OpenGL. OpenGL is not a scene graph! It's best to think OpenGL to be a set of drawing tools to paint on a canvas called the frame buffer.
So in using OpenGL you must put your mind in a state similar to if you's draw a picture with pencils, eraser, brush and paint. First you prepare your tools: Textures are like "sheets of colour", meshes of vertices are like some delicate "brush".
Like an artist the very fist step is to prepare your tools. You prepare your geometry (i.e. the meshes), if you use Vertex Buffer Objects you load them into fast memory with glBufferData, and your paint and dye, the textures. This is what you do in the "init" phase (I prefer to do this on demand, so that users don't see a "loading" screen).
First you load all your objects (geometry in VBOs, textures etc.); you do this exactly once for each required object, i.e. once an object is prepared (i.e. complete) you don't have to re-upload it.
Then in every drawing iteration for each object you want to draw you bind the needed OpenGL objects to their targets, then perform the drawing calls, which will then be performed using the currently bound objects.
i.e. something like this, please use common sense to fill in the lacking functions in your mind:
struct texture; // some structure holding texture information, details don't matter here
struct geometry; // structure holding object geometry and cross references
texture *textures;
geometry *geometries;
texture * load_texture(char const *texture_name)
{
texture *tex;
if( texture_already_loaded(textures, texture_name) )
tex = get_texture(texture_name);
else
tex = load_texture_data(textures, texture_name);
return tex;
}
geometry * load_geometry(char const *geometry_name)
{
geometry * geom;
if( geometry_already_loaded(geometries, geometry_name) )
geom = get_geometry(geometry_name);
else
geom = load_geometry_data(geometries, geometry_name)
if( geom->texture_name )
geom->texture = load_texture(geom->texture_name);
return geom;
}
void onetime_initialization()
{
for(geometry_list_entry * geom = geometry_name_list; geom ; geom = geom->next)
geom->geometry = geometry_load(geom->name);
}
void drawGL()
{
glViewport(...);
glClearColor(...);
glClear(...);
glMatrixMode(GL_PROJECTION);
// ...
glMatrixMode(GL_MODELVIEW);
// ...
for(geometry_list_entry * geom = geometry_name_list; geom ; geom = geom->next)
{
glMatrixMode(GL_MODELVIEW); // this is not redundant!
glPushMatrix();
apply_geometry_transformation(geom->transformation); // calls the proper glTranslate, glRotate, glLoadMatrix, glMultMatrix, etc.
glBindTexture(GL_TEXTURE_2D, geom->texture->ID);
draw_geometry(geom);
glMatrixMode(GL_MODELVIEW); // this is not redundant!
glPopMatrix();
}
// ...
swapBuffers();
}
How exactly can I do a Z buffer prepass with openGL.
I'v tried this:
glcolormask(0,0,0,0); //disable color buffer
//draw scene
glcolormask(1,1,1,1); //reenable color buffer
//draw scene
//flip buffers
But it doesn't work. after doing this I do not see anything. What is the better way to do this?
Thanks
// clear everything
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// z-prepass
glEnable(GL_DEPTH_TEST); // We want depth test !
glDepthFunc(GL_LESS); // We want to get the nearest pixels
glcolormask(0,0,0,0); // Disable color, it's useless, we only want depth.
glDepthMask(GL_TRUE); // Ask z writing
draw()
// real render
glEnable(GL_DEPTH_TEST); // We still want depth test
glDepthFunc(GL_LEQUAL); // EQUAL should work, too. (Only draw pixels if they are the closest ones)
glcolormask(1,1,1,1); // We want color this time
glDepthMask(GL_FALSE); // Writing the z component is useless now, we already have it
draw();
You're doing the right thing with glColorMask.
However, if you're not seeing anything, it's likely because you're using the wrong depth test function.
You need GL_LEQUAL, not GL_LESS (which happens to be the default).
glDepthFunc(GL_LEQUAL);
If i get you right, you are trying to disable the depth-test performed by OpenGL to determine culling. You are using color functions here, which does not make sense to me. I think you are trying to do the following:
glDisable(GL_DEPTH_TEST); // disable z-buffer
// draw scene
glEnable(GL_DEPTH_TEST); // enable z-buffer
// draw scene
// flip buffers
Do not forget to clear the depth buffer at the beginning of each pass.