Normally this code renders the image of the texture to screen. But if I now add the command glBindFramebuffer(GL_FRAMEBUFFER,0) to the code, it will not render anything. It renders the screens just in the color of glClearColor. I am working with QT so using QOpenGLWidget.
glViewport(0, 0, _width, _height);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClearColor(0.0,0.0,0.0,1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
_program.bind();
glBindVertexArray(_vao);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textureID);
glUniform1i(glGetUniformLocation(_program.programId(), "u_texture"), 1);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
Want can go possibly wrong?
EDIT:
/* final.fsh */
# version 330 core
uniform sampler2D u_texture;
in vec4 qt_TexCoord0;
out vec4 fragColor;
void main(void)
{
fragColor = texture(u_texture, qt_TexCoord0.xy);
}
/* final.vsh */
# version 330 core
layout (location = 0) in vec3 a_position;
out vec4 qt_TexCoord0;
void main(void)
{
gl_Position = vec4(a_position, 1.0);
const mat4 B = mat4(0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0);
qt_TexCoord0 = B * vec4(a_position, 1.0);
}
/* Loads VAO to GPU */
GLfloat max_ = 1.0;
GLfloat min_ = -1.0;
GLfloat vert[] = {
max_, max_, 0,
max_, min_, 0,
min_, max_, 0,
max_, min_, 0,
min_, min_, 0,
min_, max_, 0,
};
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vert), vert, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*3, (GLvoid*)0);
glBindVertexArray(0);
As stated by G.M., and according to the docs, glBindFramebuffer(GL_FRAMEBUFFER, 0) "breaks the existing binding of a framebuffer object to the target". You need this call after having used your framebuffers to do some offscreen rendering. When you want to finally render to the screen, you have to render the the back buffer, by calling glDrawBuffer(GL_BACK).
So your render loop might look like
// Do some rendering stuff in n offscreen textures
glBindFramebuffer(GL_FRAMEBUFFER, the_buffer);
glDrawBuffers(n, buffers);
// Rendering calls
// Finally use the results for the final rendering
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDrawBuffer(GL_BACK);
// Rendering calls
EDIT:
It appears you are using QOpenGLWidget as your OpenGL provider / windowing system. The Qt guys are using framebuffers to render their UI, and the content of the result of your QOpenGLWidget is drawn inside an FBO.
So, what it means (at least in my experience, there might be a better way to tackle this problem), is that you cannot render in the backbuffer anymore, you have to render in Qts framebuffer.
One way to do this (again, it might not be the best way at all, but it has worked for me), is to save the bound framebuffer at the begining of your rendering, and do your final rendering in this buffer. Which leads to
// First of all, save the already bound framebuffer
GLint qt_buffer;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &qt_buffer);
// Do some rendering stuff in n offscreen textures
glBindFramebuffer(GL_FRAMEBUFFER, your_buffer);
glDrawBuffers(n, buffers);
// Rendering calls
// Finally use the results for the final rendering
if (glIsFramebuffer(qt_buffer))
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDrawBuffer(GL_BACK);
}
else
{
glBindFramebuffer(GL_FRAMEBUFFER, qt_buffer);
glDrawBuffers(1, buffers);
}
// Rendering calls
I have the same issue and finally I find the cause is glBindFramebuffer(GL_FRAMEBUFFER, 0);
QOpenGLWidget's default framebuffer may not be 0, so you need to get it by calling QOpenGLContext::defaultFramebufferObject()
so change like this:
glViewport(0, 0, _width, _height);
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject()); //<-- change here
glClearColor(0.0,0.0,0.0,1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
_program.bind();
glBindVertexArray(_vao);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textureID);
glUniform1i(glGetUniformLocation(_program.programId(), "u_texture"), 1);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
Related
I'm working on a old code that used fixed function pipeline, the scene is a bit complex but works fine. For the sake of simplicity, I replaced it with one blue triangle :
void RenduOpenGL::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glViewport(0, 0, this->width(), this->height());
glBegin(GL_TRIANGLES);
glColor3d(0,0,1);
glVertex3d(0.7, 0.7, 0.0);
glVertex3d(-0.5, 0.7, 0.0);
glVertex3d(0.1, -0.7, 0.0);
glEnd();
}
Now I want to add shaders for new elements in the scene but keep the old elements of the scene like this blue triangle.
I've read here that I can mix the two to produce a scene containing the first then the second.
Therefore I want to add this code after the blue triangle :
float vertices[] = {
0.6, 0.6, 0.0,
-0.6, 0.6, 0.0,
0.0, -0.6, 0.0,
};
vbo.create(); // glGenBuffers(...);
vbo.bind(); // glBindBuffer(GL_ARRAY_BUFFER, vbo);
vbo.allocate(vertices, sizeof(vertices)); // glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(float), vertices, GL_STATIC_DRAW);
vbo.release(); // glBindBuffer(GL_ARRAY_BUFFER, 0);
prog.addShaderFromSourceFile(QOpenGLShader::Vertex, "shaders/base.vert");
prog.addShaderFromSourceFile(QOpenGLShader::Fragment, "shaders/base.frag");
vao.create(); // glGenVertexArrays(...)
vao.bind(); // glBindVertexArray(vao);
prog.enableAttributeArray("position"); // glEnableVertexAttribArray(VAO_position);
prog.setAttributeBuffer("position", GL_FLOAT, 0, 3); // (offset, size, stride=0); // glVertexAttribPointer(VAO_position, 4, GL_FLOAT, False, 0, reinterpret_cast<const void *>(offset)(0)); (False,
vao.release(); // glBindVertexArray(0);
// draw the triangle
prog.bind(); // glUseProgram(shader_program);
vao.bind(); // glBindVertexArray(vertex_array_object);
glDrawArrays(GL_TRIANGLES, 0, 3);
vao.release(); // glBindVertexArray(0);
prog.release(); // glUseProgram(0);
I use Qt to call the openGL functions, the corresponding opengl functions are in comments.
My shaders are very basic :
// base.vert
#version 330
// vertex shader
in vec3 position;
void main() {
gl_Position = vec4(position.xyz, 1);
}
// base.frag
#version 330
// fragment shader
out vec4 pixel;
void main() {
pixel = vec4(1, 0.5, 0, 1);
}
That is supposed to draw an orange triangle, but when I put the code after the blue triangle code, I don't see the orange triangle created from shaders.
Short (with code) answer:
The VBO and the prog.enableAttributeArray and prog.setAttributeBuffer should be in the VAO.
Something along the lines:
float vertices[] = {
0.6, 0.6, 0.0,
-0.6, 0.6, 0.0,
0.0, -0.6, 0.0,
};
prog.bind(); // glUseProgram(shader_program);
vao.create(); // glGenVertexArrays(...)
vao.bind(); // glBindVertexArray(vao);
vbo.create(); // glGenBuffers(...);
vbo.bind(); // glBindBuffer(GL_ARRAY_BUFFER, vbo);
vbo.allocate(vertices, sizeof(vertices)); // glBufferData(GL_ARRAY_BUFFER, 9 * sizeof(float), vertices, GL_STATIC_DRAW);
//vbo.release(); // glBindBuffer(GL_ARRAY_BUFFER, 0);
prog.addShaderFromSourceFile(QOpenGLShader::Vertex, "shaders/base.vert");
prog.addShaderFromSourceFile(QOpenGLShader::Fragment, "shaders/base.frag");
prog.enableAttributeArray("position"); // glEnableVertexAttribArray(VAO_position);
prog.setAttributeBuffer("position", GL_FLOAT, 0, 3); // (offset, size, stride=0); // glVertexAttribPointer(VAO_position, 4, GL_FLOAT, False, 0, reinterpret_cast<const void *>(offset)(0)); (False,
vao.release(); // glBindVertexArray(0);
// draw the triangle
prog.bind(); // glUseProgram(shader_program);
vao.bind(); // glBindVertexArray(vertex_array_object);
glDrawArrays(GL_TRIANGLES, 0, 3);
vao.release(); // glBindVertexArray(0);
prog.release(); // glUseProgram(0);
Not so long but textual answer: OpenGL is a state machine, you need to link together: the VBO and how to read its data, inside the VAO. However, IMHO, Qt people have sadly chosen their abstractions poorly: enableAttributeArray and setAttributeBuffer would be clearer as members of the VAO class instead of the prog class.
I have been writing a program to visualize a fractal point cloud and so far everything has been working, camera movement is using arc-ball movement centered on the origin and points are being rendered. However, I am needing to output the scene into an integrated window inside a UI so i have been trying to get frame buffers to work.
So far i have got a texture to be successfully rendered onto a quad that i am then outputting to the screen which for testing purposes is basically the same as when i was not using a fbo. My issue comes when trying to get camera movement to also display using the rendered texture. i know this is definitely possible as there are lots of examples of this but i haven't been able to get any to work with my code. I'm fairly certain my issue is with my shaders but i have scoured lots of websites, YouTube tutorials, openGL examples and found nothing that works. to the best of my knowledge i have to render the scene as normal so i have been using the same shaders that have worked for me previously for the initial rendering step but i have using my fbo instead of the default fbo
for simplicity's sake, i have just been rendering a point cube as it is faster than generating a fractal each time.
here is the main setup of the fbo, texture and rbo:
GLuint fbo;
GLuint texturebuffer;
GLuint rbo;
void initFBO(){
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glGenTextures(1, &texturebuffer);
glBindTexture(GL_TEXTURE_2D, texturebuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WINDOW_WIDTH, WINDOW_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texturebuffer, 0);
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, WINDOW_WIDTH, WINDOW_HEIGHT);
glBindRenderbuffer(GL_RENDERBUFFER, 0); // once rbo memory allocated unbind
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
}
here is the main and the draw loop:
int main(){
if(!setup())
return -1;
// // white background
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// GLuint programID = LoadShaders( "new_vertex_shader", "new_fragment_shader" ); // custom shader
GLuint programID = LoadShaders("new_vertex_shader", "new_fragment_shader");
GLuint modelMatrixID = glGetUniformLocation(programID, "model");
GLuint viewMatrixID = glGetUniformLocation(programID, "view");
GLuint matrixID = glGetUniformLocation(programID, "MVP");
GLuint quad_programID = LoadShaders( "screen_vertex_shader", "screen_fragment_shader" );
GLuint textureID = glGetUniformLocation(quad_programID, "screenTexture");
// initialise mvp matrices
glm::mat4 ProjectionMatrix = perspective(radians(45.0f), 4.0f / 3.0f, 0.1f, 100.0f);
glm::mat4 ViewMatrix = translate(mat4(1.0f), vec3(0,0,-RADIUS));
glm::mat4 ModelMatrix = mat4(1.0f);
glm::mat4 MVP;
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
GLfloat cube[24] = {
0.5,0.5,0.5,
0.5,-0.5,0.5,
-0.5,0.5,0.5,
-0.5,-0.5,0.5,
0.5,0.5,-0.5,
0.5,-0.5,-0.5,
-0.5,-0.5,-0.5,
-0.5,0.5,-0.5
};
glBufferData(GL_ARRAY_BUFFER, sizeof(cube),cube, GL_STATIC_DRAW);
glfwSetMouseButtonCallback(window, mouseCallback);
// ################# main draw loop #######################
while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS && glfwWindowShouldClose(window) == 0 ){
// render to fbo first
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glEnable(GL_DEPTH_TEST);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
computeMatricesFromInputs();
ProjectionMatrix = getProjectionMatrix();
ViewMatrix = getViewMatrix();
ModelMatrix = getModelMatrix();
MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;
// Use our shader
glUseProgram(programID);
// 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]);
// render scene as normal
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); // index buffer
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glPointSize(POINT_SIZE);
glDrawArrays(GL_POINTS, 0, sizeof(cube));
glDisableVertexAttribArray(0);
// bind back to default frame buffer to show on screen
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDisable(GL_DEPTH_TEST);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(quad_programID);
glEnableVertexAttribArray(0);
glBindVertexArray(quad_vertex_buffer);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glDrawArrays(GL_POINTS, 0, sizeof(cube));
glDisableVertexAttribArray(0);
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
}
vertex shader:
#version 330 core
// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition_modelspace;
// Values that stay constant for the whole mesh.
uniform mat4 MVP;
uniform mat4 view;
uniform mat4 model;
void main(){
// Output position of the vertex, in clip space : MVP * position
gl_Position = MVP * vec4(vertexPosition_modelspace,1.0);
}
fragment shader:
#version 330 core
// Output data
out vec3 color;
void main(){
// Output color = black
color = vec3(0,0,0);
}
screen quad vertex shader:
#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec2 aTexCoords;
out vec2 TexCoords;
void main()
{
TexCoords = aTexCoords;
gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);
}
screen quad fragment shader:
#version 330 core
out vec4 FragColour;
in vec2 TexCoords;
uniform sampler2D screenTexture;
void main()
{
FragColour = texture(screenTexture, TexCoords);
}
sorry if this is quite a big block of code, im not entirely sure where the error would lie and im somewhat new to using openGL. many thanks in advance for anyhelp.
glEnableVertexAttribArray changes a state in the Vertex Array Object. It has to be done after binding the VAO by glBindVertexArray.
I assume that quad_vertex_buffer is a Vertex Array Object, even though the name "vertex_buffer" is misleading.
glBindVertexArray(quad_vertex_buffer);
glEnableVertexAttribArray(0);
When you draw the screen space quad (2nd pass), then you have to use a primitive type which generates a (filled) polygon (probably GL_TRIANGLES or GL_TRIANGLE_STRIP), rather than the point primitive type GL_POINTS:
glDrawArrays(GL_POINTS, 0, sizeof(cube));
glDrawArrays(GL_TRIANGLE_STRIP, 0, sizeof(cube))
I've found similar posts here, but none help me with my problem. I'm just using basic OpenGL, and trying to draw a triangle with a texture applied. But for some reason the triangle is one solid color. This color happens to be the same color as the background of the texture.
This is the texture I'm attempting to draw
And this is the result when I run the program
I've experimented by editing the texture to have some blue in the bottom left (the origin), and it came out like this
My guess is that it's interpolating the red and blue to give me purple. But I have no idea why it'd be interpolating the colors in the first place instead of just drawing the texture like I want.
This is some bits and pieces of the relevant parts of my code:
Enabling things before the main loop
glClearColor(0, 0, 0, 1);
glEnable(GL_BLEND);
glEnable(GL_TEXTURE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Loading the shaders
auto vertString = getSource("test.vert");
auto vertSource = vertString.c_str();
GLint vertLength = vertString.length();
auto fragString= getSource("test.frag");
auto fragSource = fragString.c_str();
GLint fragLength = fragString.length();
auto vertShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertShader, 1, &vertSource, &vertLength);
auto fragShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragShader, 1, &fragSource, &fragLength);
//compile shaders
glCompileShader(vertShader);
checkShaderCompilation(vertShader, "vertex shader");
glCompileShader(fragShader);
checkShaderCompilation(fragShader, "fragment shader");
auto program = glCreateProgram();
glAttachShader(program, vertShader);
glAttachShader(program, fragShader);
glBindAttribLocation(program, 0, "i_position");
glBindAttribLocation(program, 1, "i_texCoord");
//link program
glLinkProgram(program);
checkProgramLinkage(program, "vertex shader", "fragment shader");
glDetachShader(program, vertShader);
glDetachShader(program, fragShader);
glDeleteShader(vertShader);
glDeleteShader(fragShader);
Loading the Texture
SDL_Surface* surface = IMG_Load("Numel.png");
if (!surface)
{
std::cout << "Unable to load texture." << std::endl;
return 0;
}
auto width = surface->w;
auto height = surface->h;
GLuint texture = 0;
//generate the id
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
auto mode = surface->format->BytesPerPixel == 4 ? GL_RGBA : GL_RGB;
glTexImage2D(GL_TEXTURE_2D, 0, mode, surface->w, surface->h, false, mode, GL_UNSIGNED_BYTE, surface->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
SDL_FreeSurface(surface);
glBindTexture(GL_TEXTURE_2D, 0);
Vertex Structure
struct Vertex
{
Vector2 position;
Vector2 texCoord;
};
Generating the Vertex Array
Vertex data[] = {
-0.5, -0.5, 0, 0,
0.5, -0.5, 1, 0,
0.5, 0.5, 1, 1
};
GLuint vertexBuffer = 0, vertexArray = 0;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*3, data, GL_STATIC_DRAW);
glGenVertexArrays(1, &vertexArray);
glBindVertexArray(vertexArray);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, 0, sizeof(Vertex), (char*)offsetof(Vertex, position));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, 0, sizeof(Vertex), (char*)offsetof(Vertex, texCoord));
And binding/drawing everything in the main loop
glClear(GL_COLOR_BUFFER_BIT);
//texture
glBindTexture(GL_TEXTURE_2D, texture);
//shader
auto colorLoc = glGetUniformLocation(program, "u_color");
glUniform3f(colorLoc, 0, 0, 1);
auto useTextureLoc = glGetUniformLocation(program, "u_usingTexture");
glUniform1i(useTextureLoc, 1);
auto textureLoc = glGetUniformLocation(program, "u_sampler");
glUniform1i(textureLoc, 0);
glUseProgram(program);
//vertex array
glBindVertexArray(vertexArray);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRIANGLES, 0, 3);
SDL_GL_SwapWindow(window);
This is my vertex shader
#version 420
in vec2 i_position;
in vec2 i_texCoord;
out vec2 o_texCoord;
void main()
{
o_texCoord=i_texCoord;
gl_Position=vec4(i_position, 0, 1);
}
And my fragment shader
#version 420
uniform vec3 u_color;
uniform sampler2D u_sampler;
uniform bool u_usingTexture;
in vec2 i_texCoord;
out vec4 o_color;
void main()
{
if(u_usingTexture)
o_color=texture(u_sampler, i_texCoord);
else
o_color=vec4(u_color, 1);
}
I've literally been trying to solve this for days and I have no idea. If anyone could figure out why it's rendering with one color instead of the texture, it'd be very much appreciated.
You are not using your texcoords:
This is my vertex shader
[...]
out vec2 o_texCoord;
And my fragment shader
[...]
in vec2 i_texCoord;
The names of your vertex shader outputs must match those of your fragment shader inputs. Since they do not, your fragment shader sees an input value which will just be undefined as per the spec.
The only reason why you don't get an error during linking is that you use i_texCoord in the fragment shader in some conditional way ("dynamic use"). If you would statically use i_texCoord in the fragment shader, you actually would get a link error. However, since the comipler/linker cannot rule out that you never ever access that variable, this code is allowed as per the spec, and must not result in a compilation error. But if you actually access those values, they are undefined.
I using OpenGL 4.1 and GLSL 410. I am attempting to texture a square that I made using the following coordinates:
float points[] = {
-0.5, 0.5,
-0.5, -0.5,
0.5, -0.5,
-0.5, 0.5,
0.5, -0.5,
0.5, 0.5
};
I draw the square like this:
glDrawArrays (GL_TRIANGLES, 0, 6);
From all of the tutorials I have read, the author uses an element buffer to draw the square or has just four vertices. This means that all the tutorials I have read have texture coordinates that line up with each vertex. For me, I'm using 6 vertices, so I'm not sure how to line up the texture coordinates.
Would coordinates like this work for my case:
float texcoords[] = {
0.0, 1.0,
0.0, 0.0,
1.0, 0.0,
0.0, 1.0,
1.0, 0.0,
1.0, 1.0
};
I've done lots of reading, but haven't come across anyone else who is using six vertices like I am.
Would my texture coordinates work and if not, what is the best way to come up with texture coordinates.
Yes, that will work. You've divided the sqaure into 2 triangles and mapped the tex coords to the vertices of the triangles. What are your results?
See this question. The code uses one array for the vertices (although there each vertex has xyz values) and another array for the texture coords.
You need to be careful when defining the vertex attributes.
E.g. to setup the vertex data uisng 2 buffers
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
glGenBuffers(1, &texbuffer);
glBindBuffer(GL_ARRAY_BUFFER, texbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(texcoords), texcoords, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(0, // attribute 0
2, // 2 floats per vertex
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride -> tightly packed so make it zero
0); // array buffer offset
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, texbuffer);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glDrawArrays(GL_TRIANGLES, 0, 6);
To load the texture (Update and setup the sampler, see comments)
glGenTextures(1, &tex);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
GLuint TextureID = glGetUniformLocation(programID, "texture");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
Vertex shader
#version 410 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texcoord;
out vec2 texture_coordinates;
uniform mat4 MVP;
void main() {
gl_Position = position;
texture_coordinates = texcoord;
}
Fragment shader
in vec2 texture_coordinates;
uniform sampler2D texture;
out vec4 colour;
void main() {
colour = texture2D(basic_texture, texture_coordinates);
}
I implemented a volume rendering demo application a few months ago. Everything worked fine in Windows XP-32bits. I used OpenGL -glew and SFML2.0-rc as a windowing&input library.
Now. I moved to windows 7-64bits just recently.
The program did not work out of the box, SFML seemed to crash. I changed the windowing library to GLFW, still using Glew. By going through the code i realized the very basic render to texture technique did not work anymore.
So i broke everything down to a minimal case so i could present it to you. (I also made a port to Qt5.0.2 to cross-check my assumptions : same diagnosis).
So here is the problem :
The program is supposed to render a simple unit cube with front-face culling to a texture in pass 1. Then in pass 2 i switch to back-face culling and render the same cube again. In the fragment shader (pass 2) i have the option to read the texture (from pass 1) and write it to the output : but i get a big black screen when i should see the front-face culled cube ...
Initialization code :
glGenFramebuffers(1, &raycastingFrameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, raycastingFrameBuffer);
glGenTextures(1, &cubeRenderTexture);
glBindTexture(GL_TEXTURE_2D, cubeRenderTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, viewWidth, viewHeight, 0, GL_RGBA, GL_FLOAT, 0);
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);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cubeRenderTexture, 0);
GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, DrawBuffers);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
return false;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Render passes :
// PASS ONE :
// render the unit cube (with front face culling) to texture
// we end up with a texture whose colors represent outgoing rays locations on the box
//
glBindFramebuffer(GL_FRAMEBUFFER, raycastingFrameBuffer);
glEnable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glViewport(0, 0, viewWidth, viewHeight);
glCullFace(GL_FRONT);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderRaycasting1.getProgramID());
glBindBuffer(GL_ARRAY_BUFFER, cube_VBO_ID);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (char*)NULL + 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (char*)NULL + 108*sizeof(float));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUniformMatrix4fv(glGetUniformLocation(shaderRaycasting1.getProgramID(), "modelview"), 1, GL_TRUE, modelview.getData());
glUniformMatrix4fv(glGetUniformLocation(shaderRaycasting1.getProgramID(), "projection"), 1, GL_TRUE, projection.getData());
glDrawArrays(GL_TRIANGLES, 0, 36);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(0);
glUseProgram(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glEnable(GL_DEPTH_TEST);
// PASS TWO :
// render the unit cube (with back face culling this time)
// we get colors representing ray entrance locations on the box
//
glViewport(0, 0, viewWidth, viewHeight);
glCullFace(GL_BACK);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaderRaycasting2.getProgramID());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, cubeRenderTexture);
glUniform1i(cubeRenderTextureID, 0);
glUniform1i(glGetUniformLocation(shaderRaycasting2.getProgramID(), "displayWidth"), (GLint) viewWidth);
glUniform1i(glGetUniformLocation(shaderRaycasting2.getProgramID(), "displayHeight"), (GLint) viewHeight);
glBindBuffer(GL_ARRAY_BUFFER, cube_VBO_ID);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (char*)NULL + 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (char*)NULL + 108*sizeof(float));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUniformMatrix4fv(glGetUniformLocation(shaderRaycasting1.getProgramID(), "modelview"), 1, GL_TRUE, modelview.getData());
glUniformMatrix4fv(glGetUniformLocation(shaderRaycasting1.getProgramID(), "projection"), 1, GL_TRUE, projection.getData());
glDrawArrays(GL_TRIANGLES, 0, 36);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(0);
glActiveTexture(0);
glUseProgram(0);
... and finally the minimal fragment shader :
#version 330
in vec3 color;
uniform int displayWidth;
uniform int displayHeight;
uniform sampler2D cubeTex;
layout (location = 0) out vec4 outColor;
void main()
{
float viewWidth = displayWidth;
float viewHeight = displayHeight;
vec3 boxIn = color;
vec2 cubeCoord = vec2( (gl_FragCoord.x - 0.5) / viewWidth, (gl_FragCoord.y - 0.5) / viewHeight);
vec3 boxOut = texture(cubeTex, cubeCoord).rgb;
vec3 rayColor = boxOut;
outColor = vec4(rayColor, 1); // i get a black screen here ...
}
Some last words :
- Everything compiles with no warnings, no errors (same for Qt 5.0.2 port of the demo)
- I tried every possible little "tweaking" like glEnable(...), changing opengl version, using texelFetch, and what not ... obviously i can't find what's wrong with this code.
- The original code was much more complex and did run, but on XP and not on Win7.
- etc.
Did you install the original vendor drivers for your GPU as downloaded from the vendor's driver support website, or do you still have installed the crippled versions that are shipped with Windows 7?
The drivers shipping with Windows 7 do not offer modern OpenGL support. Microsoft strips them of anything OpenGL and the default OpenGL implementation of Windows-7 is just a OpenGL-1.4 emulation on top of Direct3D.
If you didn't already, then download the original drivers from your GPU's vendor and install those, then report back if this changed the outcome.