The problem:
The code is supposed to render the scene and write the results into a depth texture. When I check the contents of the texture after the render, it contains all 0 values.
What I have tried:
I have tried outputting to the screen instead of the texture and it draws the scene as expected, so the vertex and matrix values are being read correctly. I have tried multiple tutorials an they all basically say to bind a framebuffer to a texture, which is exactly what I do. I believe the trouble is probably some sort of versioning issue or something I overlooked like a parameter or something. I've been at it for a few hours and I can't quite spot it. Hopefully someone can.
Details:
OpenGL 3.1
GLSL 140
Note: The purpose of this is to allow shadow mapping to work. So there are 2 sets of shaders and draw functions. One to draw to the depth buffer and the other to draw the objects.
Code:
Shader initialization code:
void Engine::loadMObject()
{
glGenFramebuffers(1, &MObject::fbo);
glGenTextures(1, &MObject::shadowMap);
glBindFramebuffer(GL_FRAMEBUFFER, MObject::fbo);
glBindTexture(GL_TEXTURE_2D, MObject::shadowMap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, windowWidth, windowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, MObject::shadowMap, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
assi(status == GL_FRAMEBUFFER_COMPLETE, "FBO error!");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
MObject::shadowProgram = Shader::compile((char*)MObject::shadowVertexShaderFile, (char*)MObject::shadowFramentShaderFile);
MObject::shadowPositionLoc = glGetAttribLocation(MObject::shadowProgram, "position");
MObject::shadowModelProjectionMatrixLoc = glGetUniformLocation(MObject::shadowProgram, "modelProjectionMatrix");
MObject::objectProgram = Shader::compile((char*)MObject::objectVertexShaderFile, (char*)MObject::objectFragmentShaderFile);
MObject::objectPositionLoc = glGetAttribLocation(MObject::objectProgram, "position");
MObject::objectTexCoordLoc = glGetAttribLocation(MObject::objectProgram, "texCoord");
MObject::objectNormalLoc = glGetAttribLocation(MObject::objectProgram, "normal");
MObject::objectWorldMatrixLoc = glGetUniformLocation(MObject::objectProgram, "worldMatrix");
MObject::objectViewMatrixLoc = glGetUniformLocation(MObject::objectProgram, "viewMatrix");
MObject::objectProjectionMatrixLoc = glGetUniformLocation(MObject::objectProgram, "projectionMatrix");
MObject::objectTextureLoc = glGetUniformLocation(MObject::objectProgram, "texture");
MObject::objectDepthModelProjectionMatrixLoc = glGetUniformLocation(MObject::objectProgram, "depthModelProjectionMatrix");
}
Object initialization code
void Engine::load(MObject* object)
{
unload(object);
// |Physics|
object->mesh = memoryManager.alloc<btTriangleIndexVertexArray>(
object->elements.length()/3,
(int*)&object->elements[0],
3*sizeof(GLuint),
object->attributes.length(),
(btScalar*)&object->attributes[0],
sizeof(MObject::Attribute));
btCollisionShape* shape;
btScalar mass = 0;
btVector3 inertia(0, 0, 0);
if(object->dynamic)
{
shape = memoryManager.alloc<btGImpactMeshShape>(object->mesh);
((btGImpactMeshShape*)shape)->updateBound();
mass = 1;
shape->calculateLocalInertia(mass, inertia);
}else{
shape = memoryManager.alloc<btBvhTriangleMeshShape>(object->mesh, true);
}
object->rigidBody = (btRigidBody*)memoryManager.galloc(sizeof(btRigidBody), memoryManager.alignment<btRigidBody>());
new (object->rigidBody) btRigidBody(mass, object, shape, inertia); // 16-byte aligned param work around...
physicsWorld->addRigidBody(object->rigidBody);
// |Graphics|
// Vertex array object
glGenVertexArrays(1, &object->objectvao);
glBindVertexArray(object->objectvao);
// Vertex buffer object
glGenBuffers(1, &object->vbo);
glBindBuffer(GL_ARRAY_BUFFER, object->vbo);
glBufferData(GL_ARRAY_BUFFER, object->attributes.length()*sizeof(MObject::Attribute), object->attributes.data, GL_STATIC_DRAW);
// Vertex attributes
glEnableVertexAttribArray(object->objectPositionLoc);
glVertexAttribPointer(object->objectPositionLoc, 3, GL_FLOAT, GL_FALSE, sizeof(MObject::Attribute), (void*)0);
glEnableVertexAttribArray(object->objectTexCoordLoc);
glVertexAttribPointer(object->objectTexCoordLoc, 2, GL_FLOAT, GL_FALSE, sizeof(MObject::Attribute), (void*)offsetof(class MObject::Attribute, texCoord));
glEnableVertexAttribArray(object->objectNormalLoc);
glVertexAttribPointer(object->objectNormalLoc, 3, GL_SHORT, GL_TRUE, sizeof(MObject::Attribute), (void*)offsetof(class MObject::Attribute, normal));
// Element buffer object
object->eboNumElements = object->elements.length();
glGenBuffers(1, &object->ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object->ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, object->elements.length()*sizeof(GLuint), object->elements.data, GL_STATIC_DRAW);
glBindVertexArray(0);
// Shadow vao
glGenVertexArrays(1, &object->shadowvao);
glBindVertexArray(object->shadowvao);
glBindBuffer(GL_ARRAY_BUFFER, object->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object->ebo);
glEnableVertexAttribArray(object->shadowPositionLoc);
glVertexAttribPointer(object->shadowPositionLoc, 3, GL_FLOAT, GL_FALSE, sizeof(MObject::Attribute), (void*)0);
glBindVertexArray(0);
mObjectList.pushBack(object);
}
Draw code:
/* START - SECTION OF MAIN UPDATE LOOP */
// |Draw update|
// Shadow Pass
// testing...
if(isKeyDown(SDL_SCANCODE_0)){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(MObject::shadowProgram);
glBindFramebuffer(GL_FRAMEBUFFER, MObject::fbo);
glBindTexture(GL_TEXTURE_2D, MObject::shadowMap);
for(U32 i=0;i<mObjectList.length();++i)
{
drawShadow(mObjectList[i]);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, MObject::shadowMap);
GLfloat* pixels = new GLfloat[windowWidth*windowHeight];
glGetTexImage(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GL_FLOAT, pixels);
for(U32 i=0;i<windowHeight*windowHeight;++i)
{
if(pixels[i] != 0.0f)
printd("I GOT IT!");
}
delete[] pixels;
}else{
// Object Pass
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(MObject::objectProgram);
for(U32 i=0;i<mObjectList.length();++i)
{
drawObject(mObjectList[i]);
}
}
// Swapping buffers
SDL_GL_SwapWindow(mainWindow);
/* END - SECTION OF MAIN UPDATE LOOP*/
void Engine::drawObject(MObject* object)
{
TransformMatrix matrix;
getOrthographicMatrix(matrix, -10, 10, 10, -10, -10, 20);
glBindVertexArray(object->objectvao);
glUniformMatrix4fv(MObject::objectWorldMatrixLoc, 1, GL_FALSE, (GLfloat*)&object->worldMatrix);
glUniformMatrix4fv(MObject::objectViewMatrixLoc, 1, GL_FALSE, (GLfloat*)&getViewMatrix());
glUniformMatrix4fv(MObject::objectProjectionMatrixLoc, 1, GL_FALSE, (GLfloat*)&getProjectionMatrix());
glUniformMatrix4fv(MObject::objectDepthModelProjectionMatrixLoc, 1, GL_FALSE, (GLfloat*)&getProjectionMatrix());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, object->tbo);
glUniform1i(MObject::objectTextureLoc, 0);
glDrawElements(GL_TRIANGLES, object->eboNumElements, GL_UNSIGNED_INT, 0);
}
void Engine::drawShadow(MObject* object)
{
TransformMatrix matrix;
//getOrthographicMatrix(matrix, -10, 10, 10, -10, -10, 20);
matrix = getProjectionMatrix() * getViewMatrix() * object->worldMatrix;
glBindVertexArray(object->shadowvao);
glUniformMatrix4fv(MObject::shadowModelProjectionMatrixLoc, 1, GL_FALSE, (GLfloat*)&matrix);
glDrawElements(GL_TRIANGLES, object->eboNumElements, GL_UNSIGNED_INT, 0);
}
Vertex Shader:
#version 140
in vec3 position;
uniform mat4 modelProjectionMatrix;
void main(){
gl_Position = modelProjectionMatrix * vec4(position, 1.0f);
}
Fragment Shader:
#version 140
out float fragmentdepth;
void main(){
fragmentdepth = gl_FragCoord.z;
}
/*
out vec4 color;
void main(){
color = vec4(clamp(gl_FragCoord.z, 0.0f, 1.0f), 0.0f, 0.0f, 1.0f);
}*/
I figured it out. Apparently if you rearrange the opengl calls a little bit it works. I believe what I did was put glBindFramebuffer before glUseProgram and it worked.
Related
I'm trying to display RGB images in a GtkGLArea using a gtk/epoxy stack in C(/C++) langage brought by vcpkg.
I have no errors but the widget stay white.
Can someone teel me what I'm missing ?
here are the shaders:
#include <gtk/gtk.h>
#include <epoxy/gl.h>
const char* vertexShaderCode =
"#version 330 core\n"
"in vec3 a_position;"
"void main() {"
" gl_Position = vec4(a_position,1.0);"
"}";
const char* fragmentShaderCode =
"#version 330 core\n"
"uniform sampler2D u_texture;"
"in vec2 tex_pos;"
"out vec3 color;"
"void main() {"
" vec3 texel = texture2D(u_texture, tex_pos).rgb;"
" color = texel;"
"}";
used variables (class members):
guint width, height;
guint vao;
guint texture;
guint program;
void* pixels; // image content
some Triangle coordinates:
GLfloat vertices[12] = {
-1, -1, 0,
1, -1, 0,
-1, 1, 0,
1, 1, 0
};
GLfloat textureVertices[8] = {
0, 1,
1, 1,
0, 0,
1, 0
};
Init:
glViewport(0, 0, width, height);
glClearColor(1.0f, 1.0f, 1.0f, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// shaders
guint vshader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vshader, 1, &vertexShaderCode, NULL);
glCompileShader(vshader);
guint fshader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fshader, 1, &fragmentShaderCode, NULL);
glCompileShader(fshader);
//program
program = glCreateProgram();
glAttachShader(program, vshader);
glAttachShader(program, fshader);
glLinkProgram(program);
glUseProgram(program);
glDisable(GL_BLEND);
glDisable(GL_DITHER);
glDisable(GL_DEPTH_TEST);
glDeleteShader(vshader);
glDeleteShader(fshader);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint buffers[2];
glGenBuffers(2, &buffers[0]);
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(textureVertices), textureVertices, GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
int textureHandle = glGetUniformLocation(program, "u_texture");
glUniform1i(textureHandle, 0);
glBindAttribLocation(program, 0, "a_position");
glBindAttribLocation(program, 1, "tex_pos");
// textures
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);// OR LINEAR
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glTexImage2D(
GL_TEXTURE_2D, 0,
GL_RGB,
width, height, 0,
GL_RGB,
GL_UNSIGNED_BYTE, NULL);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(0);
glDeleteBuffers(2, &buffers[0]);
update drawing:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texture);
// Bind the VAO
glViewport(0, 0, areaWidth, areHeight);
glUseProgram(program);
glBindVertexArray(vao);
glBindTexture(GL_TEXTURE_2D, texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindTexture(GL_TEXTURE_2D, 0);
each time needed data is copied to pixels pointer and rendering is requested:
gtk_gl_area_queue_render(GTK_GL_AREA(widget));
but the image is never rendered
All vertex attributes are inputs to the vertex shader. You need to pass the texture coordinates from the vertex shader to the fragment shader:
#version 330 core
in vec3 a_position;
in vec2 a_tex_pos;
out vec2 tex_pos;
void main() {
tex_pos = a_tex_pos;
gl_Position = vec4(a_position,1.0);
}
glBindAttribLocation(program, 1, "tex_pos");
glBindAttribLocation(program, 1, "a_tex_pos");
Note that the vertex shader runs per vertex, but the fragment shader runs per fragment. The vertex shader outputs are interpolated along the fragments between the vertices. The interpolated outputs are the inputs to the fragment shader. With the interpolated texture coordinates, a different pixel of the image can be looked up for each fragment of the primitive.
I fixed it, there was several mistakes:
mainly:
draw strips without an bound vertice buffer
working example:
here are the shaders:
#include <gtk/gtk.h>
#include <epoxy/gl.h>
const char* vertexShaderCode =
"#version 330 core\n"
"layout(location = 0) in vec3 a_position;"
"in vec2 a_tex_pos;"
"out vec2 tex_pos;"
"void main() {"
" tex_pos = a_tex_pos;"
" gl_Position = vec4(a_position,1.0);"
"}";
const char* fragmentShaderCode =
"#version 330 core\n"
"uniform sampler2D u_texture;"
"in vec2 tex_pos;"
"layout(location = 0) out vec4 color;"
"void main() {"
" vec4 texel = texture2D(u_texture, tex_pos);"
" color = texel;"
"}";
used variables (class members):
guint width, height;
guint vao;
guint texture;
guint program;
guint buffers[2];
void* pixels; // image content
some Triangle coordinates:
GLfloat vertices[12] = {
-1, -1, 0,
1, -1, 0,
-1, 1, 0,
1, 1, 0
};
GLfloat textureVertices[8] = {
0, 1,
1, 1,
0, 0,
1, 0
};
Init:
glViewport(0, 0, width, height);
glClearColor(1.0f, 1.0f, 1.0f, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// shaders
guint vshader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vshader, 1, &vertexShaderCode, NULL);
glCompileShader(vshader);
guint fshader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fshader, 1, &fragmentShaderCode, NULL);
glCompileShader(fshader);
//program
program = glCreateProgram();
glAttachShader(program, vshader);
glAttachShader(program, fshader);
glLinkProgram(program);
glUseProgram(program);
//glDisable(GL_BLEND);
glDisable(GL_DITHER);
//glDisable(GL_DEPTH_TEST);
glDeleteShader(vshader);
glDeleteShader(fshader);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
fbo = 0;
glGenFramebuffers(1, &fbo);
GLuint buffers[2];
glGenBuffers(2, &buffers[0]);
// I swap buffers order
glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(textureVertices), textureVertices, GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
glEnableVertexAttribArray(0);
//glBindBuffer(GL_ARRAY_BUFFER, 0); not yet !
int textureHandle = glGetUniformLocation(program, "u_texture");
glUniform1i(textureHandle, 0);
glBindAttribLocation(program, 0, "a_position");
glBindAttribLocation(program, 1, "a_tex_pos");
// textures
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);// OR LINEAR
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glTexImage2D(
GL_TEXTURE_2D, 0,
GL_RGB,
width, height, 0,
GL_RGBA,
GL_UNSIGNED_BYTE, NULL);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // it is effective now
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, DrawBuffers);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0); // unbind now
glDisableVertexAttribArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(0);
//glDeleteBuffers(2, &buffers[0]); no !
update drawing:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texture);
// Bind the VAO
glViewport(0, 0, areaWidth, areHeight);
glUseProgram(program);
glBindVertexArray(vao);
glBindTexture(GL_TEXTURE_2D, texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
// rebind vertices
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
each time needed data is copied to pixels pointer and rendering is requested:
gtk_gl_area_queue_render(GTK_GL_AREA(widget));
I am facing an issue with font rendering. I am using the tutorial https://learnopengl.com/In-Practice/Text-Rendering for this.
I am developing the application in OpenGLESV3.
I have made different shader programs for 3D object drawing, for loading textures and lastly for the font rendering.
I am drawing the fonts after the 3D objects and texture drawing is done.
However the issue is that the font is not seen when i draw using orthographic projection. I am able to only see the 3D objects and texture. (Even though the shaders are different)
when I only draw font only with orthographic projection it is drawing perfectly.
I am sure it is the issue with the settings in projection, but i am unable to figure out the issue.
Can anybody help please ?
Here is the code inside my render loop
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, (GLsizei)SCR_WIDTH, (GLsizei)SCR_HEIGHT);
/********************************* 3D objects Rendering ********************************************************/
glUseProgram(shaderpgmPoints);
projection = glm::perspective(glm::radians(camspec.fov), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
glUniformMatrix4fv(glGetUniformLocation(shaderpgmPoints, "projection"), 1, false, &projection[0][0]);
view = glm::lookAt(camspec.cameraPos, camspec.cameraPos + camspec.cameraFront, camspec.cameraUp);
glUniformMatrix4fv(glGetUniformLocation(shaderpgmPoints, "view"), 1, false, &view[0][0]);
model = glm::mat4(1.0f);
glUniformMatrix4fv(glGetUniformLocation(shaderpgmPoints, "model"), 1, false, &model[0][0]);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, quadBufferObject);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)64);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindBuffer(GL_ARRAY_BUFFER, leftlaneBufferObject);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)192);
;
glEnable(GL_PROGRAM_POINT_SIZE);
glDrawArrays(GL_LINES, 0, 12);
glDisable(GL_BLEND);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindBuffer(GL_ARRAY_BUFFER, rightlaneBufferObject);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)32);
glLineWidth(10.0f);
glDrawArrays(GL_LINES, 0, 2);
glDisable(GL_BLEND);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glUseProgram(0);
/********************************* 3D objects Rendering -End ********************************************************/
/********************************* Texture Rendering ********************************************************/
glUseProgram(shaderpgmTexture);
glm::mat4 transform = glm::mat4(1.0f);
transform = glm::translate(transform, glm::vec3(0.0f, 0.0f, 0.0f));
glUniformMatrix4fv(glGetUniformLocation(shaderpgmTexture, "transform"), 1, false, &transform[0][0]);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUniform1i(glGetUniformLocation(shaderpgmTexture, "outputTexture"), 1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, camTexture);
glBindBuffer(GL_ARRAY_BUFFER, camTextureBufferObject);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// texture coord attribute
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glDrawArrays(GL_QUADS, 0, 4);
glDisable(GL_BLEND);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glUseProgram(0);
/********************************* Texture Rendering - End ********************************************************/
/********************************* Font Rendering ********************************************************/
glDisable(GL_DEPTH_TEST);
glUseProgram(shaderpgmFont);
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glm::mat4 project = glm::ortho(0.0f, static_cast<GLfloat>(SCR_WIDTH), 0.0f, static_cast<GLfloat>(SCR_HEIGHT));
glUniformMatrix4fv(glGetUniformLocation(shaderpgmFont, "projection"), 1, false, &project[0][0]);
glUniform3f(glGetUniformLocation(shaderpgmFont, "textColor"), 1.0f, 0.0f, 0.0f);
glActiveTexture(GL_TEXTURE0);
GLfloat scale = 1.0f;
GLfloat x = 10.0f;
GLfloat y = 10.0f;
std::string text = "THE";
std::string::const_iterator c;
for (c = text.begin(); c != text.end(); c++)
{
Character ch = Characters[*c];
GLfloat xpos = x + ch.Bearing.x * scale;
GLfloat ypos = y - (ch.Size.y - ch.Bearing.y) * scale;
GLfloat w = ch.Size.x * scale;
GLfloat h = ch.Size.y * scale;
GLfloat vertices[6][4] = {
{ xpos, ypos + h, 0.0, 0.0 },
{ xpos, ypos, 0.0, 1.0 },
{ xpos + w, ypos, 1.0, 1.0 },
{ xpos, ypos + h, 0.0, 0.0 },
{ xpos + w, ypos, 1.0, 1.0 },
{ xpos + w, ypos + h, 1.0, 0.0 }
};
// Render glyph texture over quad
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
// Update content of VBO memory
glBindBuffer(GL_ARRAY_BUFFER, FontVertexBufferObject);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); // Be sure to use glBufferSubData and not glBufferData
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Now advance cursors for next glyph (note that advance is number of 1/64 pixels)
x += (ch.Advance >> 6) * scale; // Bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels))
}
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_BLEND);
glDisable(GL_CULL_FACE);
glUseProgram(0);
glEnable(GL_DEPTH_TEST);
/********************************* Font Rendering - End********************************************************/
I am Initializing the font buffer like this
glDisable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(shaderpgmFont);
// FreeType
FT_Library ft;
// All functions return a value different than 0 whenever an error occurred
if (FT_Init_FreeType(&ft))
std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << std::endl;
// Load font as face
FT_Face face;
if (FT_New_Face(ft, "fonts/arial.ttf", 0, &face))
{
std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl;
}
else
{
// Set size to load glyphs as
FT_Set_Pixel_Sizes(face, 0, 48);
// Disable byte-alignment restriction
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Load first 128 characters of ASCII set
for (GLubyte c = 0; c < 128; c++)
{
// Load character glyph
if (FT_Load_Char(face, c, FT_LOAD_RENDER))
{
std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl;
continue;
}
// Generate texture
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_ALPHA,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_ALPHA,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
// Set texture options
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Now store character for later use
Character character = {
texture,
glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
face->glyph->advance.x
};
Characters.insert(std::pair<GLchar, Character>(c, character));
}
glBindTexture(GL_TEXTURE_2D, 0);
// Destroy FreeType once we're finished
FT_Done_Face(face);
FT_Done_FreeType(ft);
// Configure VAO/VBO for texture quads
glGenBuffers(1, &FontVertexBufferObject);
glBindBuffer(GL_ARRAY_BUFFER, FontVertexBufferObject);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
glUseProgram(0);
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
In your initialization function, you've set up some OpenGL state via glVertexAttribPointer, which later gets clobbered.
To fix this, modify your text-rendering code so that it makes two calls glVertexAttribPointer after glBindBuffer.
I am trying to put either a color or an image to the background of the rectangle I draw using OpenGL 3.3.
I'm trying to generate the image color myself for testing, but it seems something is wrong with my code and I only see a single color.
Vertex shader:
#version 330 core
layout(location = 0) in vec2 VertexPosition;
layout(location = 1) in vec2 VertexUV;
out vec2 UV;
void main() {
gl_Position = vec4(VertexPosition.x, VertexPosition.y, 0.0, 1.0);
UV = VertexUV;
}
Fragment Shader:
#version 330 core
in vec2 UV;
out vec3 Color;
uniform sampler2D TextureSampler;
void main() {
Color = texture(TextureSampler, UV).rgb;
}
The way I generate textures:
GLuint data[3] = {64, 128, 192};
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
The way I draw my elements:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
glUniform1i(TextureSamplerID, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, UVBuffer);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindTexture(GL_TEXTURE_2D, 0);
The way I generate buffers:
glGenBuffers(1, &VertexBuffer);
glGenBuffers(1, &UVBuffer);
glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
const GLfloat uv_coordinates[] = {
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
1.0f, 1.0f,
0.0f, 1.0f,
0.0f, 0.0f
};
glBindBuffer(GL_ARRAY_BUFFER, UVBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(uv_coordinates), uv_coordinates, GL_STATIC_DRAW);
When I create and draw a rectangle using these, I see this:
I try to generate texture data with these:
GLuint data2[192];
for(int i = 0; i < 192; i++) data2[i] = i;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, data2);
and I see this:
Since the type which enumerator which is passed to glTexImage2D is GL_UNSIGNED_BYTE, the data typo of the array of pixel data has to be GLubyte (which corresponds to GL_UNSIGNED_BYTE) instead of GLuint:
GLubyte data2[192];
for(int i = 0; i < 192; i++) data2[i] = i;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, data2);
When I run this program, it seems to only be mapping my textures to 3 sides of a right angle triangle (the first 3 points in my vertices array), and completely missing out the fourth, as when I change that bit, nothing changes in the image. https://imgur.com/a/MvhsYYv here is the current output as the top image, and the expected output as the 2nd image. When I texture it with just a colour in my shader, it maps fine, with a texture, it still seems that it is drawing a square, but then mapping to the top left when it should be mapping to the top right.
Vertex vertices[] = {
//Position //Colour
vec3(-0.5f, 0.5f, 0.f), vec3(1.f, 0.f, 0.f), vec2(0.f, 1.f), //Top left
vec3(-0.5f, -0.5f, 0.f), vec3(0.f, 1.f, 0.f), vec2(0.f, 0.f), //Bottom Left
vec3(0.5f, -0.5f, 0.f), vec3(0.f, 0.f, 1.f), vec2(1.f, 0.f), //Bottom Right
vec3(0.5f, 0.5f, 0.f), vec3(1.f, 1.f, 1.f), vec2(1.f, 1.f) //Top Right
};
unsigned int numOfVertices = sizeof(vertices) / sizeof(Vertex);
GLuint indices[] = {
0,1,2,
3,0,2
};
unsigned numOfIndices = sizeof(indices) / sizeof(GLint);
void updateInput(GLFWwindow* window) {
if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}
int main() {
//INIT GLFW
glfwInit();
Wrapper mainWrapper = Wrapper();
Shader *mainShader = new Shader(vs_source.c_str(), fs_source.c_str());
GLuint VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
GLuint VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
GLuint EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0,4, GL_FLOAT, GL_FALSE, sizeof(Vertex),(GLvoid*)offsetof(Vertex, position));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, color));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, texcoord));
glEnableVertexAttribArray(2);
glBindVertexArray(0);
//TEXTURE INIT
int image_width = 0;
int image_height = 0;
unsigned char* image = SOIL_load_image("images/super-meat-boy.png", &image_width, &image_height, NULL, SOIL_LOAD_RGBA);
GLuint texture0;
glGenTextures(1, &texture0);
glBindTexture(GL_TEXTURE_2D, texture0);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (image) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
std::cout << "IMAGE LOADED";
}
else {
std::cout << "Error loading image";
}
//Clean up, needed when stuff done with texture
glActiveTexture(0);
glBindTexture(GL_TEXTURE_2D, 0);
SOIL_free_image_data(image);
//MAIN LOOP
while (!glfwWindowShouldClose(mainWrapper.getWindow())) {
//UPDATE INPUT
updateInput(mainWrapper.getWindow());
glfwPollEvents();
//UPDATE
//DRAW------
//clear
glClearColor(0.f,0.f,0.f,1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//draw
glUseProgram(mainShader->myProgram);
//activate texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture0);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, numOfIndices, GL_UNSIGNED_INT, 0);
//END DRAW
glfwSwapBuffers(mainWrapper.getWindow());
glFlush();
}
//END OF PROGRAM
glfwDestroyWindow(mainWrapper.getWindow());
delete mainShader;
glfwTerminate();
return 0;
}
#version 440
layout (location = 0) in vec3 vertex_position;
layout (location = 1) in vec3 vertex_color;
layout (location = 2) in vec3 vertex_texcoord;
out vec3 vs_position;
out vec3 vs_color;
out vec2 vs_texcoord;
void main() {
vs_position = vertex_position;
vs_color = vertex_color;
vs_texcoord = vec2(vertex_texcoord.x, vertex_texcoord.y * -1.f);
gl_Position = vec4(vertex_position, 1.f);
}
#version 440
in vec3 vs_position;
in vec3 vs_color;
in vec2 vs_texcoord;
out vec4 fs_color;
uniform sampler2D texture0;
void main() {
fs_color = vec4(vs_color, 1.f);
fs_color = texture(texture0, vs_texcoord);
}
The 2nd parameter of glVertexAttribPointer has to be the tuple size (number) of components) of the attribute in the vertex buffer.
Your vertex coordinates have 3 components x, y, z. The color attributes have 3 components too (red, green, blue). The texture coordinate have 2 components u and v:
glVertexAttribPointer(0,
3, // 3 instead of 4
GL_FLOAT, GL_FALSE, sizeof(Vertex),(GLvoid*)offsetof(Vertex, position));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1,
3, // 3 instead of 4
GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, color));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2,
3, // 2 instead of 3
GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, texcoord));
glEnableVertexAttribArray(2);
The parameter of 3 for the tuple size of the texture coordinates causes that you access the vertex buffer out of bounds for the vertex coordinate with index 3.
It was incorrect sizing in my glVertexAttribPointer. I have since changed my vertices to vec2, vec3, vec2, and changed the sizing accordingly.
I need to render a 3d model into many views and the image size is much larger than screen resolution, so I can not open a so large window and I do not need to open a window to see the rendering result, too. I only want to render the 3d model into many images with different viewpoints.
I find this tutorial, http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/, and I try to use glGetTexImage and glReadPixels to read pixel values from fbo.
The problem is if the window is not hidden, it is OK. If I set the window hidden using
glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
I can only read the background color from fbo using glGetTexImage or glReadPixels. And the model drawed using glDrawElements disappears.
Could anyone help me or show me an example? Thanks!
This my code of reading fbo: (It work well if the window is not hidden, the remaining part of my code is same as http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/)
Here is my code is:
if (!glfwInit())
{
fprintf(stderr, "Failed to initialize GLFW\n");
getchar();
return -1;
}
glfwWindowHint(GLFW_SAMPLES, 1);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_VISIBLE, GL_TRUE);
// Open a window and create its OpenGL context
int windowWidth = 4000;
int windowHeight = 3000;
window = glfwCreateWindow(windowWidth, windowHeight, "Tutorial 14 - Render To Texture", NULL, NULL);
if (window == NULL) {
fprintf(stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n");
getchar();
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// Initialize GLEW
glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
getchar();
glfwTerminate();
return -1;
}
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
// Hide the mouse and enable unlimited mouvement
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// Set the mouse at the center of the screen
glfwPollEvents();
glfwSetCursorPos(window, windowWidth / 2, windowHeight / 2);
// Dark blue background
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
// Enable depth test
glEnable(GL_DEPTH_TEST);
// Accept fragment if it closer to the camera than the former one
glDepthFunc(GL_LESS);
// Cull triangles which normal is not towards the camera
glEnable(GL_CULL_FACE);
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// Create and compile our GLSL program from the shaders
GLuint programID = LoadShaders("StandardShadingRTT.vertexshader", "StandardShadingRTT.fragmentshader");
// Get a handle for our "MVP" uniform
GLuint MatrixID = glGetUniformLocation(programID, "MVP");
GLuint ViewMatrixID = glGetUniformLocation(programID, "V");
GLuint ModelMatrixID = glGetUniformLocation(programID, "M");
// Load the texture
GLuint Texture = loadDDS("uvmap.DDS");
// Get a handle for our "myTextureSampler" uniform
GLuint TextureID = glGetUniformLocation(programID, "myTextureSampler");
// Read our .obj file
std::vector<glm::vec3> vertices;
std::vector<glm::vec2> uvs;
std::vector<glm::vec3> normals;
bool res = loadOBJ("suzanne.obj", vertices, uvs, normals);
std::vector<unsigned short> indices;
std::vector<glm::vec3> indexed_vertices;
std::vector<glm::vec2> indexed_uvs;
std::vector<glm::vec3> indexed_normals;
indexVBO(vertices, uvs, normals, indices, indexed_vertices, indexed_uvs, indexed_normals);
// Load it into a VBO
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, indexed_vertices.size() * sizeof(glm::vec3), &indexed_vertices[0], GL_STATIC_DRAW);
GLuint uvbuffer;
glGenBuffers(1, &uvbuffer);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glBufferData(GL_ARRAY_BUFFER, indexed_uvs.size() * sizeof(glm::vec2), &indexed_uvs[0], GL_STATIC_DRAW);
GLuint normalbuffer;
glGenBuffers(1, &normalbuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glBufferData(GL_ARRAY_BUFFER, indexed_normals.size() * sizeof(glm::vec3), &indexed_normals[0], GL_STATIC_DRAW);
// Generate a buffer for the indices as well
GLuint elementbuffer;
glGenBuffers(1, &elementbuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned short), &indices[0], GL_STATIC_DRAW);
// Get a handle for our "LightPosition" uniform
glUseProgram(programID);
GLuint LightID = glGetUniformLocation(programID, "LightPosition_worldspace");
// ---------------------------------------------
// Render to Texture - specific code begins here
// ---------------------------------------------
// The framebuffer, which regroups 0, 1, or more textures, and 0 or 1 depth buffer.
GLuint FramebufferName = 0;
glGenFramebuffers(1, &FramebufferName);
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
// The texture we're going to render to
GLuint renderedTexture;
glGenTextures(1, &renderedTexture);
// "Bind" the newly created texture : all future texture functions will modify this texture
glBindTexture(GL_TEXTURE_2D, renderedTexture);
// Give an empty image to OpenGL ( the last "0" means "empty" )
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, windowWidth, windowHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
// Poor filtering
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_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Set "renderedTexture" as our colour attachement #0
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexture, 0);
// Set the list of draw buffers.
GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers
// Always check that our framebuffer is ok
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
return false;
// Render to our framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
glViewport(0, 0, windowWidth, windowHeight); // Render on the whole framebuffer, complete from the lower left corner to the upper right
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Use our shader
glUseProgram(programID);
// Compute the MVP matrix from keyboard and mouse input
computeMatricesFromInputs();
glm::mat4 ProjectionMatrix = getProjectionMatrix();
glm::mat4 ViewMatrix = getViewMatrix();
glm::mat4 ModelMatrix = glm::mat4(1.0);
glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;
// Send our transformation to the currently bound shader,
// in the "MVP" uniform
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &ModelMatrix[0][0]);
glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);
glm::vec3 lightPos = glm::vec3(4, 4, 4);
glUniform3f(LightID, lightPos.x, lightPos.y, lightPos.z);
// Bind our texture in Texture Unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Texture);
// Set our "myTextureSampler" sampler to user Texture Unit 0
glUniform1i(TextureID, 0);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 2nd attribute buffer : UVs
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glVertexAttribPointer(
1, // attribute
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 3rd attribute buffer : normals
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glVertexAttribPointer(
2, // attribute
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
// Draw the triangles !
glDrawElements(
GL_TRIANGLES, // mode
indices.size(), // count
GL_UNSIGNED_SHORT, // type
(void*)0 // element array buffer offset
);
unsigned char *image = new unsigned char[windowWidth * windowHeight * 3];
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(0, 0, windowWidth, windowHeight, GL_RGB, GL_UNSIGNED_BYTE, image);
cv::Mat img;
img = cv::Mat::zeros(windowHeight, windowWidth, CV_8UC3);
for (int i = 0; i < windowHeight; i ++) {
for (int j = 0; j < windowWidth; j ++) {
int index = (i * windowWidth + j) * 3;
cv::Vec3b px;
px.val[0] = image[index + 0];
px.val[1] = image[index + 1];
px.val[2] = image[index + 2];
img.at<cv::Vec3b>(i, j) = px;
}
}
cv::imwrite("test.png", img);
It works very well when the window is visible
glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
but if I set it to be GL_TRUE, I can not get the results any more!
Could any one help me?
Thanks very much!
Have you checked this example? It uses Frame Buffer
https://www.opengl.org/wiki/Framebuffer_Object_Examples#Quick_example.2C_render_to_texture_.282D.29
Code below (in case the link gets broken on the future):
//RGBA8 2D texture, 24 bit depth texture, 256x256
glGenTextures(1, &color_tex);
glBindTexture(GL_TEXTURE_2D, color_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//NULL means reserve texture memory, but texels are undefined
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
//-------------------------
glGenFramebuffersEXT(1, &fb);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
//Attach 2D texture to this FBO
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, color_tex, 0);
//-------------------------
glGenRenderbuffersEXT(1, &depth_rb);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_rb);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, 256, 256);
//-------------------------
//Attach depth buffer to FBO
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_rb);
//-------------------------
//Does the GPU support current FBO configuration?
GLenum status;
status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
switch(status)
{
case GL_FRAMEBUFFER_COMPLETE_EXT:
cout<<"good";
default:
HANDLE_THE_ERROR;
}
//-------------------------
//and now you can render to GL_TEXTURE_2D
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//-------------------------
glViewport(0, 0, 256, 256);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 256.0, 0.0, 256.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//-------------------------
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
//-------------------------
//**************************
//RenderATriangle, {0.0, 0.0}, {256.0, 0.0}, {256.0, 256.0}
//Read http://www.opengl.org/wiki/VBO_-_just_examples
RenderATriangle();
//-------------------------
GLubyte pixels[4*4*4];
glReadPixels(0, 0, 4, 4, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
//pixels 0, 1, 2 should be white
//pixel 4 should be black
//----------------
//Bind 0, which means render to back buffer
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
Code cleanup:
//Delete resources
glDeleteTextures(1, &color_tex);
glDeleteRenderbuffersEXT(1, &depth_rb);
//Bind 0, which means render to back buffer, as a result, fb is unbound
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glDeleteFramebuffersEXT(1, &fb);