I have accomplished to make a coloured square, that is rotating around the centre. And can also texture the square. But when I combine the two I only get a rotating black square.
In the fragment shader I can exchange between showing the colours defined in the vertex array and showing the image I chose for texture. This by interchanging the comments of the two lines in main. Both work fine when not rotating:
#version 450 core
in vec3 ourColor;
in vec2 TexCoord;
out vec4 color;
uniform sampler2D ourTexture;
void main()
{
// color = vec4(ourColor, 1.0f);
color = texture(ourTexture, TexCoord);
}
In the Vertex shader I can chose to rotate or not by interchanging the commenting of the gl_Position
lines:
#version 450 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
layout (location = 2) in vec2 texCoord;
out vec3 ourColor;
out vec2 TexCoord;
uniform mat4 transform;
void main()
{
gl_Position = transform*vec4(position, 1.0f);
// gl_Position = vec4(position, 1.0f);
ourColor = color;
TexCoord = vec2(texCoord.x, 1.0 - texCoord.y);
}
And the code to drive these:
GLfloat vertices[] = {
// Positions // Colors // Texture Coords
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // Top Right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // Bottom Right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // Bottom Left
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top Left
};
unsigned int indices[] = {
0, 1, 3, // First Triangle
1, 2, 3, // Second Triangle
};
GLuint VBO, VAO, indexBuffer;
glCreateVertexArrays(1, &VAO);
glCreateBuffers(1, &indexBuffer);
glCreateBuffers(1, &VBO);
glNamedBufferStorage(VBO, sizeof (vertices), vertices, GL_DYNAMIC_STORAGE_BIT);
glNamedBufferStorage(indexBuffer, sizeof (indices), indices, GL_DYNAMIC_STORAGE_BIT);
// Create index buffer
glVertexArrayElementBuffer(VAO, indexBuffer);
//position
glEnableVertexArrayAttrib(VAO, 0);
glVertexArrayAttribFormat(VAO, 0, 3, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribBinding(VAO, 0, 0);
//color
glEnableVertexArrayAttrib(VAO, 1);
glVertexArrayAttribFormat(VAO, 1, 3, GL_FLOAT, GL_FALSE, (3 * sizeof ( GLfloat))); // relative offset is the size in bytes until the first "color" attribute
glVertexArrayAttribBinding(VAO, 1, 0);
//texture
glEnableVertexArrayAttrib(VAO, 2);
glVertexArrayAttribFormat(VAO, 2, 2, GL_FLOAT, GL_FALSE, (6 * sizeof ( GLfloat))); // relative offset is the size in bytes until the first "color" attribute
glVertexArrayAttribBinding(VAO, 2, 0);
glVertexArrayVertexBuffer(VAO, 0, VBO, 0, 8 * sizeof ( GLfloat)); // The stride is the number of bytes between hver vertex
// ===================
// Texture
GLuint texture = 0;
int width = 0, height = 0;
glCreateTextures(GL_TEXTURE_2D, 1, &texture);
unsigned char *image = SOIL_load_image("image2.png", &width, &height, 0, SOIL_LOAD_RGBA);
std::cout << "Bredde: " << width << " Højde: " << height << "\n";
glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTextureParameteri(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTextureParameteri(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextureStorage2D(texture, 1, GL_RGBA2, width, height);
glTextureSubImage2D(texture, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, image);
glGenerateTextureMipmap(texture);
SOIL_free_image_data(image);
glBindTextureUnit(0, 0);
// Game loop
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
ourShader.Use();
glm::mat4 transform = glm::mat4(1.0);
transform = glm::rotate(transform, (GLfloat) glfwGetTime() * 5.0f, glm::vec3(0.0f, 0.0f, 1.0f));
const auto Textureloc = glGetUniformLocation(ourShader.Program, "ourTexture");
glBindTextureUnit(Textureloc, texture);
// Get matrix's uniform location and set matrix
const GLint transformLoc = glGetUniformLocation(ourShader.Program, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));
std::cout << "Transform location: " << transformLoc << "\n";
std::cout << "Texture location: " << Textureloc << "\n";
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 9, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glBindTextureUnit(0, 0);
// Swap the screen buffers
glfwSwapBuffers(window);
}
I'm afraid I have mixed up some DSA stuff with non-DSA stuff. Therefore the post in: Using glBindVertexArray in update loop in DSA code or not
Can anybody see what I'm doing wrong?
You confuse the location of the texture sampler uniform variable and the texture unit.
The location of the uniform variable is an active program resource, which can be get by glGetUniformLocation
:
const auto Textureloc = glGetUniformLocation(ourShader.Program, "ourTexture");
But you can choose a texture unit a texture unit, and bind the texture to this unit.
Then you have to set the texture unit index value to the texture sampler uniform:
e.g.
GLuint unit = 3;
glBindTextureUnit(unit, texture);
glUniform1i(Textureloc, unit);
Note, the texture unit is the link between the shader program and the texture object.
See OpenGL 4.6 API Compatibility Profile Specification; 7.10 Samplers; page 154:
Samplers are special uniforms used in the OpenGL Shading Language to identify the texture object used for each texture lookup. The value of a sampler indicates the texture image unit being accessed. Setting a sampler’s value to
i
selects texture image unit numberi
.
The former code has worked and you have "seen" the texture because, if you the uniform variable "transform" is not used, then the uniform is not active and doesn't get a uniform location. So "ourTexture"
is the only uniform left and likely has the uniform location 0 (Textureloc == 0
).
Since the value of "ourTexture"
is not set explicitly, its value is the default value 0.
In this special case the texture unit, the location Textureloc
and the value of "ourTexture"
are equal, they are all 0. Your code worked coincidentally.
Since GLSL version 4.2, the texture unit can be set by a Layout Qualifier (GLSL) within the shader, too. Set a Binding point, with the texture unit:
GLuint unit = 3;
glBindTextureUnit(unit, texture);
Vertex shader: binding = 3
means texture unit 3
layout(binding = 3) uniform sampler2D ourTexture;