I've been trying to get texturing working under opengl 3.1 on an intel HD graphics 2000/3000 graphics card running on ubuntu 13.04. The issue i'm running into is textures either dont load and the basic triangle i'm trying to texture comes up black, or some color from the texture will get loaded but not the entire image. I get the same outcomes using a raw image file as the source or loading a jpeg with libjpeg.
My shaders are as follows:
Vertex shader
#version 130
in vec3 vert;
in vec2 vertTextCoord;
out vec2 fragTexCoord;
void main(){
fragTexCoord = vertTextCoord;
gl_Position = vec4(vert,1);
}
Fragment shader
#version 130
uniform sampler2D tex;
in vec2 fragTexCoord;
out vec4 finalColor;
void main() {
finalColor = texture(tex, fragTexCoord);
}
code for creating the texture
glGenTextures( 1, &texture);
glBindTexture( GL_TEXTURE_2D, texture);
imgdata image_data = loadRaw("texture.bmp", 256, 256);
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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE,image_data.data);
and the render function
void display(void){
glClearColor( 1.f, 0.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT );
//load program to use
glUseProgram(shaderprogram);
GLint uniform = glGetUniformLocation(shaderprogram, "tex");
if(uniform == -1){
throw std::runtime_error(std::string("program uniform not found: tex"));
}
// bind the texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(uniform, 0);
//load vertex array to use
glBindVertexArray(cubeVAO);
//draw triangle
glDrawArrays(GL_TRIANGLES, 0, 3);
//unbind for next pass
glBindVertexArray(0);
glUseProgram(0);
glfwSwapBuffers();
}
the geometry and texture coordinates
GLfloat data[] = {
//X Y Z U V
0.0f, 0.8f, 0.0f, 0.5f, 1.0f,
-0.8f, -0.8f, 0.0f, 0.0f, 0.0f,
0.8f, -0.8f, 0.0f, 1.0f, 0.0f
};
VBO and VAO being setup
glGenVertexArrays(1, &cubeVAO);
glBindVertexArray(cubeVAO);
glGenBuffers(1, &cubeVBO);
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
glEnableVertexAttribArray(vertprog);
glVertexAttribPointer(vertprog, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), NULL);
glEnableVertexAttribArray(verttexprog);
glVertexAttribPointer(verttexprog, 2, GL_FLOAT, GL_TRUE, 5*sizeof(GLfloat), (const GLvoid*)(3*sizeof(GLfloat)));
glBindVertexArray(0);
You have not shown the code where you determine the value of verttexprog. From the code you have currently, I have to assume that verttexprog (this is a terrible variable name, by the way) is uninitialized.
You should initialize verttexprog to glGetAttribLocation (program, "vertTextCoord"); after you link your program. Likewise, do not query uniform locations each frame, the only time they change is after you (re-)link a GLSL program.
Your texture is being loaded correctly, but your texture coordinates are not. If you want to see this in action, you can replace:
finalColor = texture(tex, fragTexCoord);
with:
finalColor = texture(tex, gl_FragCoord.st);
This is not the behavior you want, but it is a great way to show that your texture is loaded fine.
Related
I wrote a simple OpenGL program to sample a 256x256 PNG texture and render it on a rectangle in a window. I relied heavily on a tutorial for this. When I followed the tutorial almost directly (making minimal changes so as to use SDL2 for [x]), the texture did not render correctly and seemed to be somehow scaled down by a factor of 2. Here is the first version of the source code, as well as a screenshot of the results:
// Link statically with GLEW
#define GLEW_STATIC
// Headers
#include <GL/glew.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_opengl.h>
// Shader sources
const GLchar* vertexSource = R"glsl(
#version 150 core
in vec2 position;
in vec2 color;
out vec2 Color;
void main()
{
Color = color;
gl_Position = vec4(position, 0.0, 1.0);
}
)glsl";
const GLchar* fragmentSource = R"glsl(
#version 150 core
in vec2 Color;
out vec4 outColor;
uniform sampler2D tex;
void main()
{
outColor = texture(tex,Color);
}
)glsl";
int main()
{
SDL_Init(SDL_INIT_VIDEO);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_Window* window = SDL_CreateWindow("OpenGL", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI);
SDL_GLContext context = SDL_GL_CreateContext(window);
glViewport(0, 0, 800, 600);
// Initialize GLEW
glewExperimental = GL_TRUE;
glewInit();
// Create Vertex Array Object
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// Create a Vertex Buffer Object and copy the vertex data to it
GLuint vbo;
glGenBuffers(1, &vbo);
GLfloat vertices[] = {
// x y u v
-0.5f, 0.5f, 0.0f, 0.0f, // Top-left
0.5f, 0.5f, 1.0f, 0.0f, // Top-right
0.5f, -0.5f, 1.0f, 1.0f, // Bottom-right
-0.5f, -0.5f, 0.0f, 1.0f // Bottom-left
};
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Create an element array
GLuint ebo;
glGenBuffers(1, &ebo);
GLuint elements[] = {
0, 1, 2,
2, 3, 0
};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
// Create and compile the vertex shader
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSource, NULL);
glCompileShader(vertexShader);
// Create and compile the fragment shader
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
glCompileShader(fragmentShader);
// Link the vertex and fragment shader into a shader program
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glBindFragDataLocation(shaderProgram, 0, "outColor");
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);
// Specify the layout of the vertex data
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
glEnableVertexAttribArray(colAttrib);
glVertexAttribPointer(colAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
SDL_Surface* surface = IMG_Load("../textures/16x16-sb-ascii.png");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, surface->w, surface->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels);
SDL_FreeSurface(surface);
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);
bool running = true;
while (running)
{
SDL_Event windowEvent;
while (SDL_PollEvent(&windowEvent))
{
switch (windowEvent.type)
{
case SDL_QUIT:
running = false;
break;
}
}
// Clear the screen to black
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Draw a rectangle from the 2 triangles using 6 indices
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// Swap buffers
SDL_GL_SwapWindow(window);
}
glDeleteProgram(shaderProgram);
glDeleteShader(fragmentShader);
glDeleteShader(vertexShader);
glDeleteBuffers(1, &ebo);
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
SDL_Quit();
return 0;
}
Initial results
For reference, here is the actual texture file:
Original texture file
As you can see, the texture appears to have been quadrupled in the different quadrants of the rectangle, with the lower two copies inexplicably being thoroughly corrupted.
As one might expect, normalizing all the texture coordinates to 0.5 produces a single copy of the texture at the intended scale, although many strange yellow/blue artifacts are still visible, as are some very subtle noisy artifacts around the edges:
GLfloat vertices[] = {
// x y u v
-0.5f, 0.5f, 0.0f, 0.0f, // Top-left
0.5f, 0.5f, 0.5f, 0.0f, // Top-right
0.5f, -0.5f, 0.5f, 0.5f, // Bottom-right
-0.5f, -0.5f, 0.0f, 0.5f // Bottom-left
};
Results after scaling down the coordinates.
I'm doing this on a Dell laptop which came with Ubuntu 18.04.4 LTS pre-installed. My graphics card is an Intel UHD Graphics 630 (Coffeelake 3x8 GT2).
Running glxinfo | grep "OpenGL version" gives the following result: OpenGL version string: 3.0 Mesa 19.2.8.
Any help with either the scaling or the blue/yellow artifacts would be greatly appreciated. Thank you!
The generated texture image is a luminance/alpha image and has just one color channel and one alpha channel. Thus you have to use the format GL_RG when you specify the 2 dimensional texture image by glTexImage2D:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG, surface->w, surface->h, 0,
GL_RG, GL_UNSIGNED_BYTE, surface->pixels);
Either set a Swizzle mask to read the green and blue color from the red color channel and the alpha value from the green color channel:
GLint swizzleMask[] = {GL_RED, GL_RED, GL_RED, GL_GREEN};
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
or use Swizzling to get the red color channel and the alpha channel when you do the texture lookup in the fragment shader:
#version 150 core
in vec2 Color;
out vec4 outColor;
uniform sampler2D tex;
void main()
{
outColor = texture(tex,Color).rrrg;
}
I am learning OpenGL through the tutorials at learnopengl.com.
I've already drawn my hand-defined 3x3 texture onto a square using 2 triangles without a shader. Using shaders, however, I don't understand this weird behavior:
The fragment shader seems to ignore texture coordinates but strangely paints my two triangles with the color of the first pixel. I tried putting garbage values into the texture coordinates and it always stays the same.
unsigned char texture_buffer[9*4] = // 3x3 texture RGBA ...
{
255,40,100,255, 100,200,200,255, 150,150,200,255,
100,100,150,255, 200,200,100,255, 150,200,150,255,
150,100,100,255, 200,100,200,255, 200,150,150,255
};
float positions_texcoords[] =
{ // x y z tex coords
0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.0f, 1.0f, 1.0f,
0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f, 1.0f
};
one time draw call:
GLuint texture = 0;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 3, 0,
GL_RGBA, GL_UNSIGNED_BYTE, (void *)texture_buffer );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions_texcoords),
positions_texcoords, GL_STATIC_DRAW);
// 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);
glClearColor(0.3f, 0.0f, 0.1f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texture);
glUseProgram(shader_program_id);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
SwapBuffers(window_dc);
vertex shader:
#version 330 core
layout (location = 0) in vec3 in_pos;
layout (location = 1) in vec2 in_tex_coord;
out vec2 out_tex_coord;
void main()
{
gl_Position = vec4(in_pos, 1.0);
out_tex_coord = in_tex_coord;
}
fragment shader:
#version 330 core
out vec4 FragColor;
in vec2 in_tex_coord;
uniform sampler2D in_texture;
void main()
{
FragColor = texture(in_texture, in_tex_coord);
}
I'd appreciate any suggestions about what might be going on. Thank you.
The output of a shader stage is linked to the input of the next shader stage by its name (except when you use a layout qualifier). See interface matching rules between shader stages.
The name of the fragment shader input variable has to be the same as the name of the vertex shader output variable.
Since the name of the texture coordinate output in the vertex shader is out_tex_coord
out vec2 out_tex_coord;
the name of the corresponding input in the fragment shader has to be out_tex_coord, too:
in vec2 out_tex_coord;
void main()
{
FragColor = texture(in_texture, out_tex_coord);
}
I am attempting to draw a png file using OpenGL and seem to have a problem with how I am setting up the textures.
Main.cpp:
float positions[] = {
-1.0f, -1.0f,
0.0f, 1.0f,
1.0f, 1.0f,
};
float texCoords[] = {
-1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};
unsigned int buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
unsigned int texBuffer;
glGenBuffers(1, &texBuffer);
glBindBuffer(GL_ARRAY_BUFFER, texBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(texCoords), texCoords, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
int w;
int h;
int comp;
unsigned char* image = stbi_load("res/images/background_level.png", &w, &h, &comp, STBI_rgb_alpha);
if (image == nullptr)
throw(std::string("Failed to load texture"));
//std::cout << image << std::endl;
unsigned int m_texture;
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
if (comp == 3)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
else if (comp == 4)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(image);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
// draw our first triangle
glUseProgram(programID);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
int uniformLoc = glGetUniformLocation(programID, "tex");
glUniform1i(uniformLoc, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
vertex.shader:
#shader VERTEX
#version 330 core
layout (location=0) in vec2 vert;
layout (location=1) in vec2 vertTexCoord;
out vec2 fragTexCoord;
void main() {
// Pass the tex coord straight through to the fragment shader
fragTexCoord = vertTexCoord;
gl_Position = vec4(vert, 0, 1);
}
fragment.shader:
#shader FRAGMENT
#version 330 core
uniform sampler2D tex; //this is the texture
in vec2 fragTexCoord; //this is the texture coord
out vec4 finalColor; //this is the output color of the pixel
void main() {
//finalColor = vec4(1.0, 1.0, 1.0, 1.0);
finalColor = texture(tex, fragTexCoord);
}
If I swap the line commented out in the fragment shader, I get an all white triangle rendered. However with the line attempting to use the texture, the triangle comes out all black. I am just beginning with OpenGL so I don't necessarily have all of the beginning concepts down pat. Textures may be ahead of my skill level but I figured it couldn't hurt to try and ask here as someone may be able to show me where I have things confused.
You are calling glBindTexture(GL_TEXTURE_2D, 0) instead of glBindTexture(GL_TEXTURE_2D, m_texture) inside the renderloop. With this command, a texture is bound to the currently active texture unit.
I can't seem to get this OpenGL program to render a quad after I add a VAO.
Assuming the program is correctly initialized without errors, the following is the code that fills the VAO.
float quad[] =
{
//verts colors
32.0f, 0.0f, 1.0f, 0.0f, 0.0f, // Top-left
32.0f, 32.0f, 0.0f, 1.0f, 0.0f, // Top-right
0.0f, 32.0f, 0.0f, 0.0f, 1.0f, // Bottom-right
0.0f, 0.0f, 1.0f, 1.0f, 1.0f // Bottom-left
};
float textureCoords[] =
{
0.0f, 0.0f, //x
0.5f, 0.0f, //w
0.5f, 0.5f, //y
0.0f, 0.5f //h
};
float elements[] =
{
0,1,2,
2,3,0
};
//loadShaders compiles and links both shaders
GLuint shaders = loadShaders("vertexShader.c", "fragmentShader.c");
GLuint VAO, VBO[2], EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(2, VBO);
glGenBuffers(1, &EBO);
//bind VAO
glBindVertexArray(VAO);
glUseProgram(shaders);
//quad and color data
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW);
GLint quadAttrib = glGetAttribLocation(shaders, "quad");
glEnableVertexAttribArray(quadAttrib);//target 'quad' in shader
glVertexAttribPointer(quadAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), 0);
//color data
GLint colorAttrib = glGetAttribLocation(shaders, "color");
glEnableVertexAttribArray(colorAttrib);//target 'color' in shader
glVertexAttribPointer(colorAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
//UV data
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(textureCoords), textureCoords, GL_STATIC_DRAW);
GLint uvAttrib = glGetAttribLocation(shaders, "uvCoords");//target 'uvCoords' in shaders
glEnableVertexAttribArray(uvAttrib);
glVertexAttribPointer(uvAttrib, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);
//TEXTURES
//laod and use textures
GLuint textures[2];
glGenTextures(2, textures);
int texWidth, texHeigth;
unsigned char *image;
//activate texture 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
image = SOIL_load_image("atlas.png", &texWidth, &texHeigth, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texWidth, texHeigth, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
SOIL_free_image_data(image);
glUniform1i(glGetUniformLocation(shaders, "img1"), 0);
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_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//element buffer data
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
//UNIFORMS
//projection matrix
GLint projectionUniform = glGetUniformLocation(shaders, "projection");
glm::mat4 orthoProjection = glm::ortho( 0.0f, static_cast<float>(480), 0.0f, static_cast<float>(272));
glUniformMatrix4fv(projectionUniform, 1, GL_FALSE, glm::value_ptr(orthoProjection));
//model view projection
GLint modelViewUniform = glGetUniformLocation(shaders, "modelView");
//unbind VAO and current shader, the VAO remembers the bound shader
glBindVertexArray(0);
glUseProgram(0);
I'm assuming that the VAO has now kept track of the following:
The quad buffer 'VBO[0]' and its corresponding attribPointer 'quadAttrib' to "quad" in the shader
The color buffer 'same VBO[0]' and its corresponding attribPointer 'colorAttrib' to 'color' in shader
The UV buffer 'VBO[1]' and its corresponding attribPointer 'uvAttrib' to 'uvCoords' in shader
That the current texture unit (0) corresponds to the loaded texture and the bind to "img1" in the fragment shader as well as its parameters
The EBO that is bounded to GL_ELEMENT_ARRAY_BUFFER
The projection matrix and its uniform
The handler to the model matrix
The shader program that was in use while the VAO was bound? Not sure, I still explicitly use the only shader program in the program
Later in the main loop, if I attempt the following, nothing gets drawn:
// Clear the screen to black
glClearColor(0.2f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
//draw the quad within this VAO
glBindVertexArray(VAO);
glUseProgram(shaders);
glm::mat4 model;
model = glm::translate(glm::mat4(1.0f), glm::vec3(newTransX, newTransY, newTransZ));
model = glm::scale(model, glm::vec3(newScale));
model = glm::rotate(
model,
(GLfloat)clock() / (GLfloat)CLOCKS_PER_SEC * 10000.0f,
glm::vec3(0.0f, 0.0f, 1.0f)
);
// upload the uniform matrix, modelViewUniform should be already linked to the shader uniform through the VAO
glUniformMatrix4fv(modelViewUniform, 1, GL_FALSE, glm::value_ptr(model));
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
SDL_GL_SwapWindow(window);
Vertex shader:
#version 330
in vec2 quad;
in vec3 color;
in vec2 uvCoords;
out vec3 Color;
out vec2 UVCoords;
uniform mat4 modelView;
uniform mat4 projection;
void main()
{
Color = color;
UVCoords = uvCoords;
gl_Position = projection * modelView * vec4(quad, 0.0f, 1.0f);
}
Fragment shader:
#version 330
in vec3 Color;//not in use, simple pipeline test
in vec2 UVCoords;
out vec4 outColor;
uniform sampler2D img1;
void main()
{
vec4 finalTexture = texture(img1, UVCoords);
outColor = finalTexture;
}
What am I doing wrong? I know for a fact that the values in the modelView and projection matrix are correct, since the program works If I never use a VAO.
Am I assuming that the VAO remembers more than it actually does? If not, what am I doing wrong?
This can't be right:
float elements[] =
{
0,1,2,
2,3,0
};
You can't use floats for vertex indices. Based on the type you pass to glDrawElements(), this should be:
GLuint elements[] =
{
0,1,2,
2,3,0
};
As for the state tracked in a VAO: No, it does not hold on to all that state. It only tracks the vertex attribute setup state. From your list:
The quad buffer 'VBO[0]' and its corresponding attribPointer 'quadAttrib' to "quad" in the shader
Yes. More precisely, the VBO/pointer are associated with the location quadAttrib, and that association is tracked in the VAO. You queried quadAttrib from your shader, but the VAO state does not contain any direct association with the shader.
The color buffer 'same VBO[0]' and its corresponding attribPointer 'colorAttrib' to 'color' in shader
Same here.
The UV buffer 'VBO[1]' and its corresponding attribPointer 'uvAttrib' to 'uvCoords' in shader
And here.
That the current texture unit (0) corresponds to the loaded texture and the bind to "img1" in the fragment shader as well as its parameters
No. That has nothing to do with the vertex attribute state.
The EBO that is bounded to GL_ELEMENT_ARRAY_BUFFER
Yes.
The projection matrix and its uniform
No. The uniform value is part of the program state.
The handler to the model matrix
No.
The shader program that was in use while the VAO was bound?
No.
I have been trying to display a 2D image over a 3D scene and have had absolutely no results (as in nothing is displayed over the 3D scene at all). I have tried normal gdb debugging, and using APITrace to make sure all the OpenGL calls are working properly. I have no idea why the image is not displaying. After some more tests, I believe the issue is not the texture itself, but something about the rendering of the 2 triangles which the texture is on. Below is all the relevant code:
// Constants
const int COORD_LOCATION = 10;
const int UV_LOCATION = 5;
// Program Loading
uint program = loadShaders("2d.fs","2d.vs") // Same function used for loading shaders for 3D objects, so the function itself should work
// Texture creation
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, temp_width, temp_height, 0, GL_RGB, GL_UNSIGNED_BYTE, image_data); // image_data is generated by libpng earlier, and it is valid according to apitrace
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
/* Later, when texture rendering is started... */
uint UV_BUFFER, cb;
glGenBuffers(1, &UV_BUFFER);
glGenBuffers(1, &cb);
const float data[] = { 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f };
glBindBuffer(GL_ARRAY_BUFFER, UV_BUFFER);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), &data[0], GL_STATIC_DRAW);
vec2 f1 = vec2(-0.5f, -0.5f);
vec2 f2 = vec2(0.5f, 0.5f);
// Set the 2d coordinates for the shader
const float data2[] = { f1.x, f1.y,
f1.x, f2.y,
f2.x, f1.y,
f2.x, f1.y,
f1.x, f2.y,
f2.x, f2.y };
// Load into buffer
glBindBuffer(GL_ARRAY_BUFFER, cb);
glBufferData(GL_ARRAY_BUFFER, sizeof(data2), &data2[0], GL_STATIC_DRAW);
// During rendering...
glUseProgram(program);
glEnableVertexAttribArray(COORD_LOCATION);
glBindBuffer(GL_ARRAY_BUFFER, cb);
glVertexAttribPointer(
COORD_LOCATION, // attribute. No particular reason for 0, but must match the layout in the shader.
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Send uniform texture
uint tex = glGetUniformLocation(program, TEXTURE_UNIFORM);
// 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(tex, 0);
// Send UVs to the location
glEnableVertexAttribArray(UV_LOCATION);
glBindBuffer(GL_ARRAY_BUFFER, UV_BUFFER);
glVertexAttribPointer(
UV_LOCATION, // attribute. No particular reason for 0, but must match the layout in the shader.
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisable(GL_BLEND);
glDisableVertexAttribArray(COORD_LOCATION);
glDisableVertexAttribArray(UV_LOCATION);
2D Vertex Shader:
#version 330 core
layout(location = 10) in vec2 coords;
layout(location = 5) in vec2 inUV;
out vec2 UV;
void main(){
gl_Position.x = coords.x;
gl_Position.y = coords.y;
gl_Position.z = 0;
gl_Position.w = 1;
UV = inUV;
}
2D Fragment Shader:
#version 330 core
in vec2 UV;
uniform sampler2D tex;
out vec3 color;
void main(){
color = texture(tex, UV);
}
The code is actually quite a bit more scattered than this, but this is what I have confirmed it comes down to. See the full code in our VCS (this is just a random game my friend and I decided to develop to practice OpenGL, we dont even have a real name for it yet).
vec2 f1 = vec2(-0.5f, -0.5f);
vec2 f2 = vec2(-0.5f, -0.5f);
Those look like the same point. Zero-(screenspace-)area triangles generally aren't rasterized.
Try changing f2 to this:
vec2 f2 = vec2(0.5f, 0.5f);
glDrawArrays(GL_TRIANGLES, 0, 10000);
^^^^^
Try changing that 10000 to 6. Since you only have 6 vertices in your VBOs.