【问题标题】:How do I put a texture on my object?如何在对象上添加纹理?
【发布时间】:2018-08-18 13:41:04
【问题描述】:

我正在尝试在我的对象(这是一个 3D 立方体)上添加纹理,但我不知道该怎么做,因为我没有得到正确的结果。另外,我正在为此使用 SDL。

这是我初始化所有内容的地方:

void OpenGLWindow::initGL()
{
    .
    .
    .
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    shader = loadShaderProgram("simple.vert", "simple.frag");
    glUseProgram(shader);

    // ambient
    glUniform3f(glGetUniformLocation(shader, "objectColor"), 1.0f, 0.5f, 0.31f);
    glUniform3f(glGetUniformLocation(shader, "lightColor"), 1.0f, 1.0f, 1.0f);
    glUniform3fv(glGetUniformLocation(shader, "lightPos"), 1, &lightPos[0]);
    glUniform3f(glGetUniformLocation(shader, "viewPos"), 0.0f, 0.0f, 3.0f);

    int width, height, nrChannels;
    unsigned char *data = stbi_load("container.png", &width, &height, &nrChannels, 0);

    if (data) {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
    }

    else {
        std::cout << "Failed to load texture" << std::endl;
    }

    stbi_image_free(data);

    // Set our viewing and projection matrices, since these do not change over time
    glm::mat4 projectionMat = glm::perspective(glm::radians(90.0f), 4.0f/3.0f, 0.1f, 10.0f);
    int projectionMatrixLoc = glGetUniformLocation(shader, "projectionMatrix");
    glUniformMatrix4fv(projectionMatrixLoc, 1, false, &projectionMat[0][0]);

    glm::vec3 eyeLoc(0.0f, 0.0f, 2.0f);
    glm::vec3 targetLoc(0.0f, 0.0f, 0.0f);
    glm::vec3 upDir(0.0f, 1.0f, 0.0f);
    glm::mat4 viewingMat = glm::lookAt(eyeLoc, targetLoc, upDir);
    int viewingMatrixLoc = glGetUniformLocation(shader, "viewingMatrix");
    glUniformMatrix4fv(viewingMatrixLoc, 1, false, &viewingMat[0][0]);

    // Load the model that we want to use and buffer the vertex attributes
    //geometry.loadFromOBJFile("sphere.obj");
    geometry.loadFromOBJFile("cube.obj");

    GLuint vertexbuffer;
    glGenBuffers(1, &vertexbuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
    glBufferData(GL_ARRAY_BUFFER, 3*geometry.vertexCount()*sizeof(float), geometry.vertexData(), GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

    GLuint texturebuffer;
    glGenBuffers(1, &texturebuffer);
    glBindBuffer(GL_ARRAY_BUFFER, texturebuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(geometry.textureCoordData()) * sizeof(glm::vec3), geometry.textureCoordData(), GL_STATIC_DRAW);
    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER, texturebuffer);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);

    glPrintError("Setup complete", true);
}

我正在读取一个 .obj 文件,其中包含顶点、法线和纹理的坐标,该文件已经使用了一个将每个坐标存储在适当向量中的类;

例如std::vector 顶点; std::vector 纹理坐标; std::vector 法线;

如何将纹理矢量内的值发送到着色器?

这是我的顶点着色器:

in vec3 position;

out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoord;

uniform mat4 projectionMatrix;
uniform mat4 viewingMatrix;
uniform mat4 modelMatrix;

void main()
{
    vec4 transformedPosition = projectionMatrix * viewingMatrix * modelMatrix * vec4(position, 1.0f);
    gl_Position = transformedPosition;
    FragPos = vec3(modelMatrix * vec4(position, 1.0));
    Normal = mat3(transpose(inverse(modelMatrix))) * position;
}

片段着色器:

out vec4 outColor;
in vec3 Normal;
in vec3 FragPos;

uniform vec3 lightPos;
uniform vec3 objectColor;
uniform vec3 lightColor;
uniform vec3 viewPos;

void main()
{
    float ambientStrength = 0.06;
    vec3 ambient = ambientStrength * lightColor;

    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(lightPos - FragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * lightColor;

    float specularStrength = 0.1;
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
    vec3 specular = specularStrength * spec * lightColor;
    vec3 result = (ambient + diffuse + specular) * objectColor;
    outColor = vec4(result, 1.0);
}

如何将纹理放在对象(3D 立方体)上?

这就是我目前所得到的:

纹理不会出现在所有面上,放大或缩小时,表面会出现一些红色、绿色或蓝色线条。

【问题讨论】:

标签: opengl graphics sdl sdl-2 opengl-3


【解决方案1】:

由于您有 3 种类型的顶点坐标,您需要 3 个Vertex Shader inputs

in vec3 a_position;
in vec2 a_uv;
in vec3 a_normal;

对于每个属性,您分别通过glVertexAttribPointerglEnableVertexAttribArray 定义并启用了一个通用顶点属性数据数组。顶点属性的索引(glEnableVertexAttribArrayglVertexAttribPointer的第一个参数),可以通过glGetAttribLocation获取。

例如

GLint uv_inx = glGetAttribLocation(shader, "a_uv");
glEnableVertexAttribArray(uv_inx);
glBindBuffer(GL_ARRAY_BUFFER, texturebuffer);
glVertexAttribPointer(uv_inx, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);

但现代方法是使用Layout Qualifiers 在着色器中定义顶点属性索引,这使得glGetAttribLocation 调用变得多余:

layout (location = 0) in vec3 a_position;
layout (location = 1) in vec2 a_uv;
layout (location = 2) in vec3 a_normal;

您必须将属性从顶点着色器传递到片段着色器。最终的顶点着色器和片段着色器的输入可能如下所示:

顶点着色器:

#version 400

layout (location = 0) in vec3 a_position;
layout (location = 1) in vec2 a_uv;
layout (location = 2) in vec3 a_normal;

out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoord;

uniform mat4 projectionMatrix;
uniform mat4 viewingMatrix;
uniform mat4 modelMatrix;

void main()
{
    vec4 transformedPosition = projectionMatrix * viewingMatrix * modelMatrix * vec4(a_position, 1.0f);
    gl_Position = transformedPosition;
    FragPos     = vec3(modelMatrix * vec4(a_position, 1.0));
    Normal      = mat3(transpose(inverse(modelMatrix))) * a_normal;
    TexCoord    = a_uv;
}

片段着色器:

in vec3 Normal;
in vec3 FragPos;
in vec2 TexCoord;

要在片段着色器中加载和查找纹理,您需要一个统一的纹理采样器。见Sampler。 对于采样器制服,您必须分配纹理单元的索引 - 请参阅glActiveTexture。 在您的情况下,GL_TEXTURE00(这是默认值)。

片段着色器中的纹理采样器统一:

uniform sampler2D u_texture;

在 c++ 代码中将纹理单元 0 设置为纹理采样器统一:

GLint tex_loc = glGetUniformLocation(shader, "u_texture");
glUniform1i(tex_loc, 0); // 0 because of GL_TEXTURE0

从 GLSL 4.2 版开始,这可以通过 Binding point 限定符在着色器代码中完成:

layout (binding = 0) uniform sampler2D u_texture;

片段着色器可能如下所示:

#version 420

out vec4 outColor;

in vec3 Normal;
in vec3 FragPos;
in vec2 TexCoord;

.....

layout (binding = 0) uniform sampler2D u_texture;

void main()
{
    vec4 textureColor = texture(u_texture, TexCoord);

    ....
    vec3 result = (ambient + diffuse + specular) * textureColor.rgb;
    outColor = vec4(result, 1.0);
}

当然,您可以通过将它们相乘来“调制”对象颜色和纹理 corot:

vec3 result = (ambient + diffuse + specular) * objectColor.rgb * textureColor.rgb;

【讨论】:

  • 抱歉回复晚了,我不在。所以我只是在你的答案中添加了所有内容,但我收到了这个错误:Shader load error: error: linking with uncompiled shadererror: linking with uncompiled shader 而且我没有从我的任何文件中添加/删除任何内容。
  • 好的,我认为问题在于我使用了#version 330 core,而您将#version 420 core#version 400 core 分别放在片段和顶点着色器中。有没有办法解决这个问题?
  • 我恢复到#version 330 core,我只是使用uniform sampler2D u_texture;而不是layout (binding = 0) uniform sampler2D u_texture;。这应该不是问题吧?现在一切都编译了,但我的对象的颜色变为蓝色,但纹理没有显示在对象上。我错过了什么吗?我将更新我的initGL(),在那里我初始化了上面问题中的所有内容。
  • @pk123 正如我在答案中提到的,layout (binding = 0) 自 GLSL 版本 4.20 起可用。由于您使用的是 3.30 版本,因此您必须删除 layout (binding = 0)。仅使用uniform sampler2D u_texture;。由于您的纹理绑定到纹理单元 0,因此这将起作用。我更改了答案以澄清这一点。
  • 是的,它现在编译没有错误。但是纹理不正确。我在上面编辑了我的问题。可以的话请看一下。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-12
相关资源
最近更新 更多