不能同时进行纹理和变换

Can't texture and transform at the same time

我已经制作了一个彩色正方形,它围绕中心旋转。并且还可以对正方形进行纹理处理。但是当我将两者结合起来时,我只会得到一个旋转的黑色方块。

在片段着色器中,我可以在显示顶点数组中定义的颜色和显示我为纹理选择的图像之间进行交换。这是通过交换 main 中两行的注释来实现的。不旋转时两者都工作正常:

#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); 
}

在顶点着色器中,我可以通过交换 gl_Position 行的注释来选择是否旋转:

#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);
}

以及驱动这些的代码:

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);
}

恐怕我混淆了一些 DSA 内容和非 DSA 内容。因此 post 中:

有人能看出我做错了什么吗?

你混淆了纹理采样器统一变量和纹理单元的位置。

uniform变量所在位置是一个活跃的程序资源,可以通过glGetUniformLocation获取:

const auto Textureloc = glGetUniformLocation(ourShader.Program, "ourTexture");

但是你可以选择一个texture unit一个纹理单元,并将纹理绑定到这个单元上。
然后你必须将纹理单元索引值设置为纹理采样器统一:

例如

GLuint unit = 3;
glBindTextureUnit(unit, texture); 
glUniform1i(Textureloc, unit);      

注意,纹理单元是着色器程序和纹理对象之间的link。

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 number i.

之前的代码有效,并且您拥有 "seen" 纹理,因为如果您未使用统一变量 "transform",则统一未激活且无法获得统一位置.所以 "ourTexture" 是唯一剩下的统一并且可能具有统一位置 0 (Textureloc == 0).
由于"ourTexture"的值没有明确设置,所以它的值为默认值0。
在这种特殊情况下,纹理单元、位置 Textureloc"ourTexture" 的值相等,它们都是 0。您的代码巧合地工作。

从GLSL 4.2版本开始,可以通过Layout Qualifier (GLSL) within the shader, too. Set a Binding point设置纹理单元,其中纹理单元:

GLuint unit = 3;
glBindTextureUnit(unit, texture); 

顶点着色器:binding = 3表示纹理单元3

layout(binding = 3) uniform sampler2D ourTexture;