Question

Code flow is as follows:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
renderScene();
renderTexturedQuadForBackground();
presentRenderbuffer();

Is there any way for me to get that textured quad rendering code to show behind the scene in spite of the fact that the scene renders first? Assume that I cannot change that the rendering of the background textured quad will happen directly before I present the render buffer.

Rephrased: I can't change the rendering order. Essentially what I want is that every pixel that would've been colored only by glClearColor to instead be colored by this textured quad.

Was it helpful?

Solution

The easiest solution is to define the quad in normalized device coordinates directly and set the z-value to 1. You then don't need to project the quad and it will be screen-filling and behind anything else - except stuff that's also at z=1 after projection and perspective divide.

That's pretty much the standard procedure for screen-aligned quads, except there is usually no need to put the quad at z=1, not that it would matter. Usually, full screen quads are simply used to be able to process at least once fragment per pixel, normally a 1:1 mapping of fragments an pixels. Deferred shading, post-processing fx or image processing in general are the usual suspects. Since you only render the quad in most cases (and nothing else) the depth value is irrelevant, as long as it's inside the unit cube and not dropped by the depth test, for instance when you put it at z=1 and your depth functions is LESS.

EDIT: I made a little mistake. NDCs are defined in a left-handed coordinate system, meaning that the near plane is mapped to -1 and the far plane is mapped to 1. So, you need to define your quad in NDCs with a z value of 1 and set the DepthFunc to LEQUAL. Alternatively, you can leave the depth function untouched and simply subtract a very small value from 1.f:

float maxZ = 1.f - std::numeric_limits<float>::epsilon();

EDIT2: Let's assume you want to render a screen-aligned quad which is drawn behind everything else and with appropriate texture coordinates. Please note: I'm on a desktop here, so I'm writing core GL code which doesn't map to GLES 2.0 directly. However, there is nothing in my examnple you can't do with GLES and GLSL ES 2.0.

You may define the vertex attribs of the quad like this (without messing with the depth func):

GLfloat maxZ = 1.f - std::numeric_limits<GLfloat>::epsilon ();

// interleaved positions an tex coords
GLfloat quad[] = {-1.f, -1.f, maxZ, 1.f, // v0
                   0.f,  0.f, 0.f,  0.f, // t0
                   1.f, -1.f, maxZ, 1.f, // ...
                   1.f,  0.f, 0.f,  0.f,
                   1.f,  1.f, maxZ, 1.f,
                   1.f,  1.f, 0.f,  0.f,
                  -1.f,  1.f, maxZ, 1.f,
                   0.f,  1.f, 0.f,  0.f};

GLubyte indices[] = {0, 1, 2, 0, 2, 3};

The VAO and buffers are setup accordingly:

// generate and bind a VAO
gl::GenVertexArrays (1, &vao);
gl::BindVertexArray (vao);

// setup our VBO
gl::GenBuffers (1, &vbo);
gl::BindBuffer (gl::ARRAY_BUFFER, vbo);
gl::BufferData (gl::ARRAY_BUFFER, sizeof(quad), quad, gl::STATIC_DRAW);

// setup out index buffer
gl::GenBuffers (1, &ibo);
gl::BindBuffer (gl::ELEMENT_ARRAY_BUFFER, ibo);
gl::BufferData (gl::ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, gl::STATIC_DRAW);

// setup our vertex arrays
gl::VertexAttribPointer (0, 4, gl::FLOAT, gl::FALSE_, 8 * sizeof(GLfloat), 0);
gl::VertexAttribPointer (1, 4, gl::FLOAT, gl::FALSE_, 8 * sizeof(GLfloat), (GLvoid*)(4 * sizeof(GLfloat)));
gl::EnableVertexAttribArray (0);
gl::EnableVertexAttribArray (1);

The shader code comes to a very, very simple pass-through vertex shader and, for simplicty a fragment shader which in my example simply exports the interpolated tex coords:

// Vertex Shader
#version 430 core

layout (location = 0) in vec4 Position;
layout (location = 1) in vec4 TexCoord;

out vec2 vTexCoord;

void main()
{
  vTexCoord = TexCoord.xy;

  // you don't need to project, you're already in NDCs!
  gl_Position = Position;
}

//Fragment Shader
#version 430 core

in  vec2 vTexCoord;
out vec4 FragColor;

void main()
{
  FragColor = vec4(vTexCoord, 0.0, 1.0);
}

As you can see, the values written to gl_Position are simply the vertex positions passed to the shader invocation. No projection takes place because the result of projection and perspective divide is nothing else than normalized device coordinates. Since we already are in NDCs, we don't need projection and perspective divide and so simply pass through the positions unaltered.

The final depth is very close to the maximum of the depth range and so the quad will appear to be behind anthing else in your scene.

You can use the texcoords as usual.

I hope you get the idea. Except for the explicit attrib locations which aren't supported by GLES 2.0 (i.e. replace the stuff with BindAttribLocation() calls instead) you shouldn't have to do anything.

OTHER TIPS

There is a way, but you have to put the quad behind the scene. If your quad is constructed correctly you can enable DEPTH_TEST by using

glEnable(DEPTH_TEST);

and then by using

glDepthFunc(GL_GREATER);

before rendering your background. Your quad will be rendered behind the scene. But as I said, this only works, when your geometry is literally located behind the scene.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top