如何在对象上放置纹理?

时间:2018-08-18 13:41:05

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

我正在尝试在我的对象(这是一个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 textureCoords; 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立方体)上?

这是我到目前为止所要了解的:

enter image description here

纹理并非在所有面上都出现,并且在放大或缩小时,表面上会出现一些红色,绿色或蓝色的线条。

1 个答案:

答案 0 :(得分: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_TEXTURE0 0 (默认)。

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

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;