无法同时进行纹理处理和变换

时间:2019-01-10 17:03:46

标签: opengl textures fragment-shader vertex-shader opengl-4

我已经做出了一个彩色的正方形,该正方形围绕中心旋转。并且还可以纹理正方形。但是,当我将两者结合时,只会得到一个旋转的黑色正方形。

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

#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内容混在一起了。因此,该帖子位于:Using glBindVertexArray in update loop in DSA code or not

有人可以看到我在做什么吗?

1 个答案:

答案 0 :(得分:1)

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

统一变量的位置是活动程序资源,可以通过glGetUniformLocation获得:

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

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

例如

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

请注意,纹理单位是着色器程序和纹理对象之间的链接。

请参见OpenGL 4.6 API Compatibility Profile Specification; 7.10 Samplers; page 154

  

Samplers是OpenGL Shading Language中使用的特殊制服,用于识别   用于每个纹理查找的纹理对象。采样器的值指示正在访问的纹理图像单元。将采样器的值设置为i可以选择纹理图像单位编号i

以前的代码已经奏效,并且您可以“看到”纹理,因为如果不使用统一变量“ transform”,则该制服将不处于活动状态并且不会获得一个统一位置。因此,"ourTexture"是唯一的统一左边,可能具有统一的位置0(Textureloc == 0)。
由于"ourTexture"的值未明确设置,因此其值为默认值0。
在这种特殊情况下,纹理单位,位置Textureloc和值"ourTexture"相等,它们都为0。您的代码同时工作。

从GLSL 4.2版开始,纹理单元也可以由着色器中的Layout Qualifier (GLSL)设置。使用纹理单位设置Binding point

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

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

layout(binding = 3) uniform sampler2D ourTexture;