The easiest way to draw strings in QGLWidget - c++

I'm creating a QGLWidget subclass with initializeGL. resizeGL and paintGL. Everything is fine, i can draw 2D graphivcs with gluOrtho2D and 3D too. Everything is fine.
Now I need to draw some text, no text rotation, no text deformations, no particular fonts. The first trial was with glut engine but the program kept on crashing so I thought with QGLWidget glut does not work in that context.
I've tried with QPainter, remember to use end() method and swapBuffers too, but.. nothing, the text is rendered but the opengl stuff no..
What is the easiest way to draw some text on a QGLWidget?

I usually do this by first rendering the text into a QImage which contents I then copy into a texture using glTexSubImage2D. Then I draw a textured quad.
Code from actual project
void displayText(QString const &text, bool render_text)
{
if(!text_texture) {
glGenTextures(1, &text_texture);
}
glActiveTexture(GL_TEXTURE0); gltPrintMultiError("glActiveTexture");
glBindTexture(GL_TEXTURE_2D, text_texture); gltPrintMultiError("glBindTexture");
int tex_width, tex_height;
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &tex_width); gltPrintMultiError("glGetTexLevelParameteriv GL_TEXTURE_WIDTH");
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &tex_height); gltPrintMultiError("glGetTexLevelParameter GL_TEXTURE_HEIGHT");
if(tex_width != text_width || tex_height != text_height ) {
render_text = true;
tex_width = text_width;
tex_height = text_height;
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGB8,
tex_width, tex_height, 0,
GL_RGB, GL_UNSIGNED_BYTE, NULL);
gltPrintMultiError("glTexImage2D");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
if(render_text) {
QImage textimg(tex_width, tex_height, QImage::Format_RGB888);
{
QPainter painter(&textimg);
painter.fillRect(0, 0, tex_width, tex_height, QColor(0,0,0));
painter.setBrush(QColor(255, 255, 255));
painter.setPen(QColor(255, 255, 255));
painter.setFont(QFont("Sans", 15));
painter.drawText(5, 20, text);
}
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glTexSubImage2D(
GL_TEXTURE_2D, 0,
0, 0,
tex_width, tex_height,
GL_RGB, GL_UNSIGNED_BYTE, textimg.constBits() );
}
static GLfloat const pos[] = {
0, 1,
1, 1,
1, 0,
0, 0
};
static GLfloat const tex[] = {
0, 0,
1, 0,
1, 1,
0, 1
};
glUseProgram(frame2d.program);
/* frame2d is a program consisting of the
following vertex and fragment shaders:
// Vertex Shader
#version 330
in vec2 position;
in vec2 texcoord;
out vec2 vert_tex;
void main()
{
vert_tex = texcoord;
gl_Position = vec4(position*2 - 1., 0, 1);
}
// Fragment Shader
#version 330
uniform sampler2D frame;
in vec2 vert_tex;
void main()
{
gl_FragColor = texture(frame, vert_tex);
}
*/
glEnableVertexAttribArray(frame2d.attrib_position);
glEnableVertexAttribArray(frame2d.attrib_texcoord);
glVertexAttribPointer(frame2d.attrib_position, 2, GL_FLOAT, GL_FALSE, 0, pos);
gltPrintMultiError("glVertexAttribPointer(attrib_position, ...)");
glVertexAttribPointer(frame2d.attrib_texcoord, 2, GL_FLOAT, GL_FALSE, 0, tex);
gltPrintMultiError("glVertexAttribPointer(attrib_texcoord, ...)");
glUniform1i(frame2d.uniform_sampler_frame, 0);
gltPrintMultiError("glUniform1i(frame2d.uniform_sampler_frame)");
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR);
glViewport(0, 0, tex_width, tex_height);
glDisable(GL_DEPTH_TEST);
glDepthMask(0);
glColorMask(1,1,1,1);
glDrawArrays(GL_QUADS, 0, 4);
glDisableVertexAttribArray(frame2d.attrib_position);
glDisableVertexAttribArray(frame2d.attrib_texcoord);
glUseProgram(0);
glBindTexture(GL_TEXTURE_2D, 0);
}

I didn't know but there is also renderText method builtin in QGLWidget class.

Related

Framebuffer Texture rendered to screen is stretched at certain points

I'm currently trying to test out rendering to a framebuffer for various uses, but whenever I have an object(say a square) at a certain y-value, it appears "stretched", and then past a certain y-value or a certain x-value it seems to "thin out" and disappears. I have determined the x and y-values that it disappears at, but the coordinates seem to not have any rhyme or reason.
When I remove the framebuffer binding and render directly to the screen it draws the square perfectly fine, no matter the x or y-value.
Drawing a basic square(using immediate mode to remove possible errors) with a wide x-value looks like this:
Code here:
Window window("Framebuffer Testing", 1600, 900); //1600x900 right now
int fbowidth = 800, fboheight = 600;
mat4 ortho = mat4::orthographic(0, width, 0, height, -1.0f, 1.0f);
//trimmed out some code from shader creation that is bugless and unneccessary to include
Shader shader("basic"); shader.setUniform("pr_matrix", ortho);
Shader drawFromFBO("fbotest"); shader.setUniform("pr_matrix", ortho);
GLfloat screenVertices[] = {
0, 0, 0, 0, height, 0,
width, height, 0, width, 0, 0};
GLushort indices[] = {
0, 1, 2,
2, 3, 0 };
GLfloat texcoords[] = { //texcoords sent to the drawFromFBO shader
0, 0, 0, 1, 1, 1,
1, 1, 1, 0, 0, 0 };
IndexBuffer ibo(indices, 6);
VertexArray vao;
vao.addBuffer(new Buffer(screenVertices, 4 * 3, 3), 0);
vao.addBuffer(new Buffer(texcoords, 2 * 6, 2), 1);
GLuint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fbowidth, fboheight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "false" << std::endl;
glEnable(GL_TEXTURE_2D);
//the x-values mess up at ~783 thru 800 and the y-values at 0 thru ~313
while(!window.closed()) {
glClearColor(0.2f, 0.2f, 0.2f, 1.0f); //grey
window.clear(); //calls glclear for depth and color buffer
//bind framebuffer and shader
shader.enable(); //literally just calls glUseProgram(id) with the compiled shader id
glViewport(0, 0, fbowidth, fboheight);
glBindFramebuffer(GL_FRAMEBUFFER, fbo); //bind the fbo
glClearColor(1.0f, 0.0f, 1.0f, 1.0f); //set clear color to pink
glClear(GL_COLOR_BUFFER_BIT);
//render a red square to the framebuffer texture
glBegin(GL_QUADS); {
glColor3f(1.0f, 0.0f, 0.0f); //set the color to red
glVertex3f(700, 400, 0);
glVertex3f(700, 450, 0);
glVertex3f(750, 450, 0);
glVertex3f(750, 400, 0);
} glEnd();
shader.disable();
glBindFramebuffer(GL_FRAMEBUFFER, 0); //set framebuffer to the default
//render from framebuffer to screen
glViewport(0, 0, width, height);
drawFromFBO.enable();
glActiveTexture(GL_TEXTURE0);
drawFromFBO.setUniform1i("texfbo0", 0);
glBindTexture(GL_TEXTURE_2D, texture);
vao.bind();
ibo.bind();
glDrawElements(GL_TRIANGLES, ibo.getCount(), GL_UNSIGNED_SHORT, NULL);
ibo.unbind();
vao.unbind();
drawFromFBO.disable();
window.update();
}
If you want to see any thing extra, the file is located at my Github: here

Framebuffer depth-artifacts

There's some Artifacts on my FrameBuffer Depth Texture I can't get rid off:
The Code used to init the FrameBuffer:
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glGenTextures(1, &color);
glBindTexture(GL_TEXTURE_2D, color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glGenTextures(1, &depth);
glBindTexture(GL_TEXTURE_2D, depth);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, color, 0);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, depth, 0);
GLuint attachments[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
glDrawBuffers(2, attachments);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
std::cout << "FBO FEHLER" << std::endl;
}
Code used to draw the FrameBuffer:
shader->bind();
// Bind Textures
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, color);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, depth);
glUniform1i(shader->getUniform("tex"), 0);
glUniform1i(shader->getUniform("depth"), 1);
glUniformMatrix4fv(shader->getUniform("matrix"), 1, GL_FALSE, glm::value_ptr(ortho));
// Draw Call
glBindBuffer(GL_ARRAY_BUFFER,fbovbo);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 20, (void*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 20, (void*)12);
glDrawArrays(GL_TRIANGLE_STRIP,0,4);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Unbind
shader->unbind();//*/
FragmentShader of the actual rendering:
#version 330 core
layout(location = 0) out vec4 out_color;
layout(location = 1) out vec4 out_depth;
in float temp;
void main(void){
out_color = vec4(1,0.0,0.0,1.0);
out_depth = vec4(gl_FragCoord.z);
}
FragmentShader of the FrameBuffer rendering:
#version 330 core
in vec2 fuv;
out vec4 color;
uniform sampler2D tex;
uniform sampler2D depth;
void main(){
vec4 d = texture2D(depth, fuv);
gl_FragDepth = d.a;
vec4 c = texture2D(tex,fuv);
if(c.a<0.1){
discard;
}
color = c;
//color = vec4(texture2D(depth, fuv).zzz,1.0);
//color.a = 0.8;
//color = vec4(1,0,0,0.5);
}
The red "Mesh" is behind the brown surface, but its borders still appear. thats the problem
The problem might come from the limited precision of the depth buffer. Basically, the range between near and farplane has to be represented by the depth-buffer. In your case, the depth-buffer has 8 bit, thus there are only 256 different depth values that can be represented. When two objects are closer together than this, they will be mapped to the same value in the depth buffer.
To overcome this, you can try to increase the precision of the depth buffer, for example, by using
glGenTextures(1, &depth);
glBindTexture(GL_TEXTURE_2D, depth);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_SHORT, NULL);
Side-note: I'm not sure why the depth texture has four channels. If you don't need them, I would change this to a one channel format.

Deferred shader textures from FBO display as black

I am trying to use deferred shading to implement SSAO and I have problems to access my textures in the deferred fragment shader. The code is in C++/Qt5 and makes use of Coin3D to generate the rest of the UI (but this shouldn't really matter here).
The fragment shader of the deferred pass is:
#version 150 compatibility
uniform sampler2D color;
uniform sampler2D position;
uniform sampler2D normal;
uniform vec3 dim;
uniform vec3 camPos;
uniform vec3 camDir;
void main()
{
// screen position
vec2 t = gl_TexCoord[0].st;
// the color
vec4 c = texture2D(color, t);
gl_FragColor = c + vec4(1.0, t.x, t.y, 1.0);
}
The code for running the deferred pass is
_geometryBuffer.Unbind();
// push state
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glPushAttrib(GL_DEPTH_BUFFER_BIT |
GL_COLOR_BUFFER_BIT |
GL_LIGHTING_BIT |
GL_SCISSOR_BIT |
GL_POLYGON_BIT |
GL_CURRENT_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_ALPHA_TEST);
glDisable(GL_LIGHTING);
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_CULL_FACE);
}
// bind shader
// /!\ IMPORTANT to do before specifying locations
_deferredShader->bind();
_CheckGLErrors("deferred");
// specify positions
_deferredShader->setUniformValue("camPos", ...);
_deferredShader->setUniformValue("camDir", ...);
_geometryBuffer.Bind(GBuffer::TEXTURE_TYPE_NORMAL, 2);
_deferredShader->setUniformValue("normal", GLint(2));
_geometryBuffer.Bind(GBuffer::TEXTURE_TYPE_POSITION, 1);
_deferredShader->setUniformValue("position", GLint(1));
_geometryBuffer.Bind(GBuffer::TEXTURE_TYPE_DIFFUSE, 0);
_deferredShader->setUniformValue("color", GLint(0));
_CheckGLErrors("bind");
// draw screen quad
{
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glColor3f(0, 0, 0);
glVertex2f(-1, -1);
glTexCoord2f(1, 0);
glColor3f(0, 0, 0);
glVertex2f( 1, -1);
glTexCoord2f(1, 1);
glColor3f(0, 0, 0);
glVertex2f( 1, 1);
glTexCoord2f(0, 1);
glColor3f(0, 0, 0);
glVertex2f(-1, 1);
glEnd();
}
_deferredShader->release();
// for debug
_geometryBuffer.Unbind(2);
_geometryBuffer.Unbind(1);
_geometryBuffer.Unbind(0);
_geometryBuffer.DeferredPassBegin();
_geometryBuffer.DeferredPassDebug();
// pop state
{
glPopAttrib();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
I know that the textures have been correctly processed in the geometry buffer creation because I can dump them into files and get the expected result.
The deferred pass doesn't work. The shader compiled correctly and I get the following result on screen:
And the last part of my code (DeferredPassBegin/Debug) is to draw the FBO to the screen (as shown in screenshot) as a proof that the GBuffer is correct.
The current result seems to mean that the textures are not correctly bound to their respective uniform, but I know that the content is valid as I dumped the textures to files and got the same results as shown above.
My binding functions in GBuffer are:
void GBuffer::Unbind()
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
}
void GBuffer::Bind(TextureType type, uint32_t idx)
{
glActiveTexture(GL_TEXTURE0 + idx);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, _textures[static_cast<uint32_t>(type)]);
}
void GBuffer::Unbind(uint32_t idx)
{
glActiveTexture(GL_TEXTURE0 + idx);
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
}
Finally, the textures are 512/512, and I created them in my GBuffer with:
WindowWidth = WindowHeight = 512;
// Create the FBO
glGenFramebuffers(1, &_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
const uint32_t NUM = static_cast<uint32_t>(NUM_TEXTURES);
// Create the gbuffer textures
glGenTextures(NUM, _textures);
glGenTextures(1, &_depthTexture);
for (unsigned int i = 0 ; i < NUM; i++) {
glBindTexture(GL_TEXTURE_2D, _textures[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, WindowWidth, WindowHeight, 0, GL_RGBA, GL_FLOAT, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i + _firstIndex, GL_TEXTURE_2D, _textures[i], 0);
}
// depth
glBindTexture(GL_TEXTURE_2D, _depthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, WindowWidth, WindowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _depthTexture, 0);
GLenum buffers[NUM];
for(uint32_t i = 0; i < NUM; ++i){
buffers[i] = GLenum(GL_COLOR_ATTACHMENT0 + i + _firstIndex);
}
glDrawBuffers(NUM, buffers);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
printf("FB error, status: 0x%x\n", status);
return _valid = false;
}
// unbind textures
glBindTexture(GL_TEXTURE_2D, 0);
// restore default FBO
glBindFramebuffer(GL_FRAMEBUFFER, 0);
How can I debug farther at this stage?
I know that the texture data is valid, but I can't seem to bind it to the shader correctly (but I have other shaders that use textures loaded from files and which work fine).
--- Edit 1 ---
As asked, the code for DeferredPassBegin/Debug (mostly coming from this tutorial )
void GBuffer::DeferredPassBegin() {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, _fbo);
}
void GBuffer::DeferredPassDebug() {
GLsizei HalfWidth = GLsizei(_texWidth / 2.0f);
GLsizei HalfHeight = GLsizei(_texHeight / 2.0f);
SetReadBuffer(TEXTURE_TYPE_POSITION);
glBlitFramebuffer(0, 0, _texWidth, _texHeight,
0, 0, HalfWidth, HalfHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
SetReadBuffer(TEXTURE_TYPE_DIFFUSE);
glBlitFramebuffer(0, 0, _texWidth, _texHeight,
0, HalfHeight, HalfWidth, _texHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
SetReadBuffer(TEXTURE_TYPE_NORMAL);
glBlitFramebuffer(0, 0, _texWidth, _texHeight,
HalfWidth, HalfHeight, _texWidth, _texHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
}
Arghk!!!
So I expected that texture parameters were not mandatory, but as I looked at some code, I just tried to specify my texture parameters. When generating the FBO textures, I use now
for (unsigned int i = 0 ; i < NUM; i++) {
glBindTexture(GL_TEXTURE_2D, _textures[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, WindowWidth, WindowHeight, 0, GL_RGBA, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i + _firstIndex, GL_TEXTURE_2D, _textures[i], 0);
}
And with this change, I get the expected result (with only c in the fragment shader, and similar correct results if I switch to visualizing the normal / position).
Conclusion: one must specify the texture parameters for deferred shading to work (at least with the graphics setup of my application / machine).

OpenGL Render To Texture (To screen) blank

I'm drawing a lot of points to the screen, and I am trying to get them to render to a texture for post processing before then rendering the texture back to the screen. Currently I'm trying to just pass through and get the texture rendering but it appears to be rendering nothing.
My fragment shader works (without render to texture - used bellow in mEllipseTextureProgram) and the only change I have made is to include
out vec3 color;
to render to the texture itself (and obviously change to color= rather than gl_FragColor=). The second program referenced below (mScreenProgram) is as follows:
Vertex Shader:
#version 330 compatibility
in vec2 vUV;
out vec2 UV;
void main()
{
gl_Position = gl_Vertex;
UV = vUV;
}
Fragment Shader:
#version 330 core
in vec2 UV;
out vec3 color;
uniform sampler2D renderedTexture;
void main(){
color = texture( renderedTexture, UV ).xyz;
}
I set up my render to texture stuff like this:
glGenFramebuffers(1, &mGaussianFrameBuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mGaussianFrameBuffer);
glGenTextures(1, &mGaussianRenderTexture);
glBindTexture(GL_TEXTURE_2D, mGaussianRenderTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1024,
768,
0, GL_RGBA, GL_UNSIGNED_BYTE,
NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mGaussianRenderTexture, 0);
glGenTextures(1, &mGaussianDepthBuffer);
glBindTexture(GL_TEXTURE_2D, mGaussianDepthBuffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
1024,
768,
0, GL_DEPTH_COMPONENT, GL_FLOAT,
NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, mGaussianDepthBuffer, 0);
which returns a successful GL_FRAMEBUFFER_COMPLETE.
Here are the three concerning rendering functions:
void Draw()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//gluPerspective(45, 1024.0/768.0, 3.0, 20000);
perspectiveGL(45, 1024.0/768.0, 1.0, 20000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
gluLookAt(cameraData[0],cameraData[1], cameraData[2],
cameraData[3],cameraData[4], cameraData[5],
0,1,0);
glEnable(GL_DEPTH_TEST);
glClearColor( 0.2f, 0.2f, 0.9f, 0.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// OTHER STUFF POTENTIALLY DRAW HERE IN DIFFERENT WAYS
glUseProgram(mEllipseTextureProgram);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mGaussianFrameBuffer);
GLuint attachments[1] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, attachments);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
DrawEllipseToTexture();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glUseProgram(mScreenProgram);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
DrawTextureToScreen();
}
void DrawEllipseToTexture()
{
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, mVBO);
glVertexPointer(3, GL_FLOAT, 0, 0);
glEnable(GL_PROGRAM_POINT_SIZE);
glEnable(GL_POINT_SPRITE);
glEnable( GL_TEXTURE_2D );
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mBMP);
glProgramUniform1i(mEllipseTextureProgram, mTextureLocation, 0);
glBindBuffer(GL_ARRAY_BUFFER, mUV);
glEnableVertexAttribArray(mTexCoordLocation);
glVertexAttribPointer(mTexCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, mSpacial);
glEnableVertexAttribArray(mSpacialLocation);
glVertexAttribPointer(mSpacialLocation, 1, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, mNormals);
glEnableVertexAttribArray(mNormalLocation);
glVertexAttribPointer(mNormalLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, mVerticalSpat);
glEnableVertexAttribArray(mMajorLocation);
glVertexAttribPointer(mMajorLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, mHorizontalSpat);
glEnableVertexAttribArray(mMinorLocation);
glVertexAttribPointer(mMinorLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable( GL_BLEND );
glDrawArrays(GL_POINTS, 0, mNumberPoints);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisable( GL_TEXTURE_2D );
glDisableVertexAttribArray(mSpacialLocation);
glDisable(GL_POINT_SPRITE);
glDisable( GL_POINT_SMOOTH );
glDisable(GL_PROGRAM_POINT_SIZE);
glDisableClientState(GL_VERTEX_ARRAY);
}
void DrawTextureToScreen()
{
glEnableClientState(GL_VERTEX_ARRAY);
glEnable( GL_TEXTURE_2D );
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mGaussianRenderTexture);
glProgramUniform1i(mScreenProgram, mGaussianTextureLocation, 0);
GLfloat vertices[] = { -1, -1, 2,
1, -1, 2,
1, 1, 2,
-1, 1, 2 };
GLfloat uv[] = { 0, 0,
1, 0,
1, 1,
0, 1,};
glVertexPointer(3, GL_FLOAT, 0, vertices);
glEnableVertexAttribArray(mGaussianUV);
glVertexAttribPointer(mGaussianUV, 2, GL_FLOAT, GL_FALSE, 0, uv);
glDrawArrays(GL_TRIANGLES, 0, 4);
glDisable ( GL_TEXTURE_2D );
glDisableClientState(GL_VERTEX_ARRAY);
}
I still don't know what was wrong with my solution above (to which I tried a lot of variations) - but following this tutorial got it working: Tutorial
I usually use `out vec4 color', I am not sure whether it will work after you setting your texture type is GL_RGBA and then return vec3 for each fragment.
And I didnt see you set glViewport() in your code which means there is no specify affine transformation to mapping the screen position (x,y) from NDC to Screen space. If you don't have a viewport during fbo render, that definitely gives you nothing.
I am same as you struggling in the similar situation. Read the functions you don't know from GL documentation instead of blog is a much better way to understand things correctly...
: )

opengl shader problems with mrt

I have two textures with same size attached to one fbo, and I want to render another texture into one of the attached textures, and I want to render a blue shape of the figure of the input texture to the other fbo attached texture.
the (updated) vertex shader:
#version 330
in vec2 coord;
out vec2 f_coord;
void main() {
gl_Position = vec4(coord, 0.0, 1.0);
f_coord = (1.0+coord)/2.0;
}
the (updated) fragment shader:
#version 330
uniform sampler2D my_texture;
in vec2 f_coord;
out vec4 FragData[2];
void main() {
if(texture(my_texture,f_coord).a == 0.0)
discard;
FragData[0]=texture(my_texture,f_coord);
FragData[1]=vec4(0.5, 0.5, 1.0, 1.0);
}
With this fragment shader everything works fine. The texture and the blue stamp of the texture contures are rendered properly.
Here is a screenshot:
http://s14.directupload.net/file/d/3487/kvkqdbl7_png.htm
But if I want to render the texture into gl_FragData[1] and the blue conture stamp into gl_FragData[0]
#version 330
uniform sampler2D my_texture;
in vec2 f_coord;
out vec4 FragData[2];
void main() {
if(texture(my_texture,f_coord).a == 0.0)
discard;
FragData[0]=vec4(0.5, 0.5, 1.0, 1.0);
FragData[1]=texture(my_texture,f_coord);
}
than I get two totally blue textures. The strange thing is: Both target textures are totally blue, but I have set the glViewport just to a part of the texture.
Here a screenshot:
http://s1.directupload.net/file/d/3487/9loqibdc_png.htm
The fbo attachments have the half screen size
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glutGet(GLUT_WINDOW_WIDTH)/2, glutGet(GLUT_WINDOW_HEIGHT), 0, GL_RGBA, GL_BYTE, 0);
So I can render both textures to the screen for checking.
This is how I created the framebufferobject
void init_fbo()
{
glGenTextures(1, &fbo.texture0);
glBindTexture(GL_TEXTURE_2D, fbo.texture0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glutGet(GLUT_WINDOW_WIDTH)/2, glutGet(GLUT_WINDOW_HEIGHT), 0, GL_RGBA, GL_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glGenTextures(1, &fbo.texture1);
glBindTexture(GL_TEXTURE_2D, fbo.texture1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glutGet(GLUT_WINDOW_WIDTH)/2, glutGet(GLUT_WINDOW_HEIGHT), 0, GL_RGBA, GL_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
glGenFramebuffers(1, &fbo.fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo.fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
fbo.texture0, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D,
fbo.texture1, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
I use those global struct variables
struct
{
GLuint fbo;
GLuint texture0;
GLuint texture1;
} fbo;
struct
{
GLuint program;
GLint uni_texture;
GLint att_coord;
} shader_fbo;
struct
{
GLuint program;
GLint uni_texture;
GLint att_coord;
} shader_screen;
And this is my render function
void render()
{
GLenum buffers[2];
GLfloat vertices[] = { -1.0, -1.0,
-1.0, 1.0,
1.0, -1.0,
1.0, 1.0 };
GLubyte indices[] = { 0, 1, 2,
1, 2, 3 };
/*render to mrt fbo*/
glUseProgram(shader_fbo.program);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture.texID);
glUniform1i(shader_fbo.uni_texture, 0);
glEnableVertexAttribArray(shader_fbo.att_coord);
glVertexAttribPointer(shader_fbo.att_coord,
2,
GL_FLOAT,
GL_FALSE,
0,
vertices);
glBindFramebuffer(GL_FRAMEBUFFER, fbo.fbo);
buffers[0] = GL_COLOR_ATTACHMENT0;
buffers[1] = GL_COLOR_ATTACHMENT1;
glDrawBuffers(2, buffers);
glViewport(0, 0,
texture.width, texture.height);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture.texID);
glUniform1i(shader_fbo.uni_texture, 0);
glClear(GL_COLOR_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);
glDisableVertexAttribArray(shader_fbo.att_coord);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
/*render both textures now to screen*/
glUseProgram(shader_screen.program);
glEnableVertexAttribArray(shader_screen.att_coord);
glVertexAttribPointer(shader_screen.att_coord,
2,
GL_FLOAT,
GL_FALSE,
0,
vertices);
/*render the first texture to the left side of the screen*/
glViewport(0, 0,
glutGet(GLUT_WINDOW_WIDTH)/2, glutGet(GLUT_WINDOW_HEIGHT));
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, fbo.texture0);
glUniform1i(shader_screen.uni_texture, 0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);
/*render the second texture to the right side of the screen*/
glViewport(glutGet(GLUT_WINDOW_WIDTH)/2, 0,
glutGet(GLUT_WINDOW_WIDTH)/2, glutGet(GLUT_WINDOW_HEIGHT));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, fbo.texture1);
glUniform1i(shader_screen.uni_texture, 0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);
glutSwapBuffers();
}