I am wondering how to render surfaces using depth test correctly. In my case it is not working although it has been enabled. I tried many combinations but can not figure out what is being done wrong, it might been some ordering of OpenGL commands, or it might be something I am missing completely.
I have this code that uses opengl to render a 2d game I am working on. I want to enable z buffering and depth test to simplify things in the code. I read a number of tutorials online and made changes as instructed but can not figure out why it is not working.
the code of the main function is shown below, I am changing the values of z for the two squares to be -10 and -25 and swapping them later on, but I always get the first square rendered over the second one no matter what values I use:
void MainGame::RenderTestUI()
{
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LESS);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLSLProgram *ActiveShader = nullptr;
ActiveShader = &ColorShader;
ActiveShader->Use();
GLint Location1 = ActiveShader->GetUniformLocation("cam");
glm::mat4 tmp = Camera.GetCameraMatrix();
glUniformMatrix4fv(Location1, 1, GL_FALSE, &tmp[0][0]);
glActiveTexture(GL_TEXTURE0);
GLint Location2 = ActiveShader->GetUniformLocation("basic");
glUniform1f(Location2, 0);
glBindTexture(GL_TEXTURE_2D, GameTextures.ID);
CurrentBoundTexture = GameTextures.ID;
RenderingBatch.StartAddingVerticies();
this->GameMap.TileList[1].FillSixVerticies(RenderingBatch.VertexListPtr, 0, 0);
RenderingBatch.VertexCount += 6;
for (int i = 0; i < 6; i++)
RenderingBatch.VertexListPtr[i].z = -10; // first face
this->GameMap.TileList[2].FillSixVerticies(&RenderingBatch.VertexListPtr[RenderingBatch.VertexCount], 8, 8);
RenderingBatch.VertexCount += 6;
for (int i = 0; i < 6; i++)
RenderingBatch.VertexListPtr[i+6].z = -25; // second face
RenderingBatch.EndAddingVerticies();
RenderingBatch.CreateVBO();
RenderingBatch.Render();
ActiveShader->Unuse();
// swap buffers
SDL_GL_SwapWindow(GameWindow);
}
The end result is always the same regardless of the value of z i am assigning to the two faces, the result could be seen here:
any advice is highly appreciated.
When setting up the SDL surface to draw on, did you ask for a depth buffer prior to calling SDL_CreateWindow?
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
Related
I want to understand how to create loads of similar 2-D objects and then animate each one separately, using OpenGL.
I have a feeling that it will be done using this and glfwGetTime().
Can anyone here help point me in the right direction?
Ok, so here is what is the general thing that have tried so far:
We have this vector that handles translations created the following code, which I have modified slightly to make a shift in location based on time.
glm::vec2 translations[100];
int index = 0;
float offset = 0.1f;
float time = glfwGetTime(); // newcode
for (int y = -10; y < 10; y += 2)
{
for (int x = -10; x < 10; x += 2)
{
glm::vec2 translation;
translation.x = (float)x / 10.0f + offset + time; // new adjustment
translation.y = (float)y / 10.0f + offset + time*time; // new adjustmet
translations[index++] = translation;
}
}
Later, in the render loop,
while (!glfwWindowShouldClose(window))
{
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shader.use();
glBindVertexArray(quadVAO);
glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 100); // 100 triangles of 6 vertices each
glBindVertexArray(0);
time = glfwGetTime(); // new adjustment
glfwSwapBuffers(window);
glfwPollEvents();
}
is what I have tried. I suppose I am misunderstanding the way the graphics pipeline works. As I mentioned earlier, my guess is that I need to use some glm matrices to make this work as I imagined it, but am not sure ...
The general direction would be, during initialization:
Allocate a buffer to hold the positions of your instances (glNamedBufferStorage).
Set up an instanced vertex attribute for your VAO that sources the data from that buffer (glVertexArrayBindingDivisor and others).
Update your vertex shader to apply the position of your instance (coming from the instanced attribute) to the total transformation calculated within the shader.
Then, once per frame (or when the position changes):
Calculate the positions of of all your instances (the code you posted).
Submit those to the previously allocated buffer with glNamedBufferSubData.
So far you showed the code calculating the position. From here try to implement the rest, and ask a specific question if you have difficulties with any particular part of it.
I posted an example of using instancing with multidraw that you can use for reference. Note that in your case you don't need the multidraw, however, just the instancing part.
I am trying to pick objects on mouse click. For this I have followed this tutorial, and tried to use the stencil buffer for this purpose.
Inside "game" loop I am trying to draw 10 (5 pairs) 'pick'able triangles as follows:
...
glClearColor(red, green, blue, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glClearStencil(0); // this is the default value
/* Enable stencil operations */
glEnable(GL_STENCIL_TEST);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
/*Some other drawing not involving stencil buffer*/
GLuint index = 1;
for (GLshort i = 0; i < 5; i++)
{
//this returns 2 model matrices
auto modelMatrices = trianglePairs[i].getModelMatrices();
for (GLshort j = 0; j < 2; j++)
{
glStencilFunc(GL_ALWAYS, index, -1);
glUniformMatrix4fv(glGetUniformLocation(ourShader.Program, "model"), 1, GL_FALSE, glm::value_ptr(modelMatrices[j]));
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, BUFFER_OFFSET(2));
index++;
}
/*Some other drawing not involving stencil buffer*/
}
/*Some other drawing not involving stencil buffer*/
...
However, when I am trying to read back the stencil values, I am getting wrong values. I am reading back the values as (this is also a part of the above-mentioned tutorial):
GLuint index;
glReadPixels(xpos, Height - ypos - 1, 1, 1, GL_STENCIL_INDEX, GL_UNSIGNED_INT, &index);
Whenever, I click the first triangle of the pair I am getting values as i+1, whereas the correct value should have been i, and for the second triangle of the pair, I am getting 0 as index.
Please let me know what am I missing here?
Update
I have found that stencil values can be applied on quads. When I tried to apply the stencil value on unit square it worked correctly. However, when the quad is not unit square, it returns 0. What is the reason for this?
I'm on Linux host and using a Windows guest.
I'm creating the OpenGL context with SDL, and I just draw 1000 objects in different positions, each object is just 6 vertices and 3 lines, just a 3D cross.
I'm using vertex and index buffers and GLSL shaders. It doesn't do anything special: it binds the buffers and sets the vertex attrib pointers, set the matrix and draws the elements.
It renders the scene in 2 seconds, if I hoist the buffer binding and attribute setting outside the loop it renders in 200ms, if I remove glUniformMatrix4fv that sets the matrix due to the updated positions it'll render about 10ms, though I only see 1 object and thousand other is just overdrawn on it.
On Linux and Windows host the same thing renders on stable 60FPS.
OpenGL games like OpenArena run on 60FPS in VirtualBox...
Is buffer binding and uniform setting a slow operation in OpenGL in general?
Does anyone has experience testing 3D programs on VirtualBox?
Update: added some code, error checking removed for clarity:
void drawStuff()
{
GLfloat projectView[16];
int ms;
RenderingContext rc; /*< Nothing special contains the currently bound render object.*/
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
createViewMatrix(
viewMatrix,
&viewedObject->attitude.k,
&viewedObject->attitude.j,
&viewedObject->pos
);
multiplyMatrix(projectView, viewMatrix, projMatrix); /*< Combine projection and view matrices. */
/* Draw 10×10×10 grid of 3D crosses. One cross is 6 vertices and 3 lines. */
bindRenderObject(&rc, &cross); /*< This binds buffers and sets up vertex attrib arrays. It's very slow if I put it into the loop*/
{
int i, j, k;
for (i = -5; i < 5; i++)
{
for (j = -5; j < 5; j++)
{
for (k = -5; k < 5; k++)
{
createTranslationMatrix(modelMatrix, i * 10, j * 10, k * 10);
multiplyMatrix(combinedMatrix, modelMatrix, projectView);
glUniformMatrix4fv(renderingMatrixId, 1, GL_FALSE, combinedMatrix); /*< This is slow for some reason.*/
drawRenderObject(&rc); /*< This is just a call to glDrawElements. No performance bottleneck here at all. */
}
}
}
}
/* Draw some UI. */
glDisable(GL_DEPTH_TEST);
/* ... */
glEnable(GL_DEPTH_TEST);
SDL_GL_SwapBuffers();
}
I recently switched from intermediate mode and have a new rendering process. There must be something I am not understanding. I think it has something to do with the indices.
Here is my diagram: Region->Mesh->Polygon Array->3 vertex indices which references the master list of vertices.
Here my render code:
// Render the mesh
void WLD::render(GLuint* textures, long curRegion, CFrustum cfrustum)
{
int num = 0;
// Set up rendering states
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// Set up my indices
GLuint indices[3];
// Cycle through the PVS
while(num < regions[curRegion].visibility.size())
{
int i = regions[curRegion].visibility[num];
// Make sure the region is not "dead"
if(!regions[i].dead && regions[i].meshptr != NULL)
{
// Check to see if the mesh is in the frustum
if(cfrustum.BoxInFrustum(regions[i].meshptr->min[0], regions[i].meshptr->min[2], regions[i].meshptr->min[1], regions[i].meshptr->max[0], regions[i].meshptr->max[2], regions[i].meshptr->max[1]))
{
// Cycle through every polygon in the mesh and render it
for(int j = 0; j < regions[i].meshptr->polygonCount; j++)
{
// Assign the index for the polygon to the index in the huge vertex array
// This I think, is redundant
indices[0] = regions[i].meshptr->poly[j].vertIndex[0];
indices[1] = regions[i].meshptr->poly[j].vertIndex[1];
indices[2] = regions[i].meshptr->poly[j].vertIndex[2];
// Enable texturing and bind the appropriate texture
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textures[regions[i].meshptr->poly[j].tex]);
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &vertices[0].x);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &vertices[0].u);
// Draw
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, indices);
}
}
}
num++;
}
// End of rendering - disable states
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
Sorry if I left anything out. And I really appreciate feedback and help with this. I would even consider paying someone who is good with OpenGL and optimization to help me with this.
There is no point in using array rendering if you're only rendering 3 vertices at a time. The idea is to send thousands through with a single call. That is, you render a single "Polygon Array" or "Mesh" with one call.
I'm really not sure what to do anymore. I'v made my application use VBO's and my cpu usage still goes into the 70's and 80's. My render proceedure works like this:
Set the camera transformation
if the shape has not been tesselated, tesselate it.
create it's VBO
if it has a VBO, use it.
You will notice I have display lists too, I might use these if VBO is not supported. I went and found an OpenGL demo that renders a 32000 poly mesh at 60fps on my PC and uses 4% cpu. I'm rendering about 10,000 polys # 60fps using vbos and its using 70-80%.
Here is my render proc:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
POINT hh = controls.MainGlFrame.GetMousePos();
POINTFLOAT S;
S.x = static_cast<float>(hh.x);
S.y = static_cast<float>(hh.y);
POINTFLOAT t;
t.x = 256;
t.y = 256;
POINT dimensions;
dimensions.x = 512;
dimensions.y = 512;
glDeleteTextures(1,&texName);
texName = functions.CreateGradient(col,t,S,512,512,true);
itt = true;
}
HDC hdc;
PAINTSTRUCT ps;
glEnable(GL_MULTISAMPLE_ARB);
glEnable(GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
hdc = BeginPaint(controls.MainGlContext.mhWnd,&ps);
//start OGL code
glClearColor( 1.0f, 1.0f, 1.0f, 0.0f );
if(!current.isdrawing)
glClear( GL_COLOR_BUFFER_BIT );
glPushMatrix();
glTranslatef(controls.MainGlFrame.GetCameraX(),
controls.MainGlFrame.GetCameraY(),0);
//glTranslatef(current.ScalePoint.x,current.ScalePoint.y,0);
glScalef(current.ScaleFactor,current.ScaleFactor,current.ScaleFactor);
//glTranslatef(-current.ScalePoint.x,-current.ScalePoint.y,0);
if(!current.isdrawing)
{
for(unsigned int currentlayer = 0; currentlayer < layer.size(); ++currentlayer)
{
PolygonTesselator.Init();
for(unsigned int i = 0; i < layer[currentlayer].Shapes.size(); i++)
{
if(layer[currentlayer].Shapes[i].DisplayListInt == -999)
{
gluTessNormal(PolygonTesselator.tobj, 0, 0, 1);
PolygonTesselator.Set_Winding_Rule(layer[currentlayer].Shapes[i].WindingRule);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texName);
layer[currentlayer].Shapes[i].DisplayListInt = glGenLists(1);
glNewList(layer[currentlayer].Shapes[i].DisplayListInt,GL_COMPILE);
PolygonTesselator.SetDimensions(layer[currentlayer].Shapes[i].Dimensions,layer[currentlayer].Shapes[i].minima);
PolygonTesselator.Begin_Polygon();
for(unsigned int c = 0; c < layer[currentlayer].Shapes[i].Contour.size(); ++c)
{
if(layer[currentlayer].Shapes[i].Color.a != 0)
{
PolygonTesselator.Begin_Contour();
for(unsigned int j = 0; j < layer[currentlayer].Shapes[i].Contour[c].DrawingPoints.size(); ++j)
{
gluTessVertex(PolygonTesselator.tobj,&layer[currentlayer].Shapes[i].Contour[c].DrawingPoints[j][0],
&layer[currentlayer].Shapes[i].Contour[c].DrawingPoints[j][0]);
}
PolygonTesselator.End_Contour();
}
}
PolygonTesselator.End_Polygon();
glEndList();
PolygonTesselator.TransferVerticies(layer[currentlayer].Shapes[i].OutPoints);
glGenBuffersARB(1,&layer[currentlayer].Shapes[i].VBOInt);
glBindBufferARB(GL_ARRAY_BUFFER_ARB,layer[currentlayer].Shapes[i].VBOInt);
glBufferDataARB(GL_ARRAY_BUFFER_ARB,sizeof(GLfloat) * layer[currentlayer].Shapes[i].OutPoints.size(),
&layer[currentlayer].Shapes[i].OutPoints[0], GL_STATIC_DRAW_ARB);
InvalidateRect(controls.MainGlFrame.framehWnd,NULL,false);
}
else //run vbo
{
//glEnable(GL_TEXTURE_2D);
//glDisable(GL_TEXTURE_2D);
//glBindTexture(GL_TEXTURE_2D, texName);
glColor4f(layer[currentlayer].Shapes[i].Color.r,
layer[currentlayer].Shapes[i].Color.g,
layer[currentlayer].Shapes[i].Color.b,
layer[currentlayer].Shapes[i].Color.a);
//glColor4f(1,1,1,1);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, layer[currentlayer].Shapes[i].VBOInt);
//glCallList(layer[currentlayer].Shapes[i].DisplayListInt);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, layer[currentlayer].Shapes[i].OutPoints.size() / 2);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
glDisable(GL_TEXTURE_2D);
//Draw outlines
if(layer[currentlayer].Shapes[i].Outline.OutlinePoints.size() > 4)
{
glColor4f(layer[currentlayer].Shapes[i].Outline.OutlineColor.r
,layer[currentlayer].Shapes[i].Outline.OutlineColor.g
,layer[currentlayer].Shapes[i].Outline.OutlineColor.b
,layer[currentlayer].Shapes[i].Outline.OutlineColor.a);
}
}
PolygonTesselator.End();
}
}
glPopMatrix();
//end OGL code
glFlush();
SwapBuffers(hdc);
glDisable(GL_MULTISAMPLE_ARB);
EndPaint(controls.MainGlContext.mhWnd,&ps);
}
Why could I be getting such high cpu usage?
Under what conditions is that first bit of code run? There's a couple of suspicious-looking lines in there:
glDeleteTextures(1,&texName);
texName = functions.CreateGradient(col,t,S,512,512,true);
If you're deleting and recreating a texture every time you paint, that could get expensive. I couldn't say how expensive the OpenGL parts would be -- I'd expect uploading texture data to be reasonably efficient, even if deleting and creating texture names might be less so -- but perhaps CreateGradient is inherently slow. Or maybe you're accidentally hitting some kind of slow path for your graphics card. Or the function is creating all the mipmap levels. And so on.
Aside from that, some random ideas:
What is the present interval? If the buffer swap is set to sync with the monitor, you may incur a delay because of that. (You can use the WGL_EXT_swap_control extension to tweak this value.)
If all of this is being run in response to a WM_PAINT, check that you aren't getting unexpected extra WM_PAINTs for some reason.
Check that the polygon tesselator Init and End functions aren't doing anything, since they're being called every time, even if there's no tesselating to be done.
Based on the code snippet you have provided, you have (at one point) loops nested four layers deep. You may be seeing high CPU load due to running each of these loops an extremely large number of times. Can you give us any idea how many iterations these loops are having to run through?
Try grabbing a timestamp inside each loop iteration and compare it against the previous to see how long it is taking to run one iteration of each particular loop. This should help you determine what part of the function is taking up the bulk of your CPU time.