现代 OpenGL 问题纹理平面

Modern OpenGL issue texturing plane

我一直难以为我制作的飞机制作纹理。平面上的第一个四边形纹理正确,但平面的其余部分似乎只使用纹理的第一个像素,所以它最终都是纯色。如果我制作一架巨大的飞机并对其进行纹理处理,它似乎可以正常工作,但是当我尝试将飞机分成几部分时,我一直遇到这个问题。我假设就坐标而言我遗漏了一些东西,但根据我的理解,我认为它们总是应该在 0 和 1 之间?感谢任何帮助。

[![在此处输入图片描述][1]][1]

纹理坐标

GLfloat grassTexCoords[]
{
    0.0f, 0.0f,
    0.0f, 1.0f,
    1.0f, 0.0f,
    1.0f, 0.0f,
    0.0f, 1.0f,
    1.0f, 1.0f
};

正在设置 VAO

GLuint makePlane()
{
    float size = 5;
    for (int i = -5; i < 5; ++i)
    {
        for (int j = -5; j < 5; ++j)
        {
            verts.push_back({ glm::vec3((i * size), -11.f, (j * size)) });
            verts.push_back({ glm::vec3((i * size), -11.f, (j * size) + size) });
            verts.push_back({ glm::vec3((i * size) + size, -11.f, (j * size)) });

            verts.push_back({ glm::vec3((i * size) + size, -11.f, (j * size)) });
            verts.push_back({ glm::vec3((i * size), -11.f, (j * size) + size) });
            verts.push_back({ glm::vec3((i * size) + size, -11.f, (j * size) + size) });
        }
    }

    GLuint vbo;
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(VertexPos), verts.data(), GL_STATIC_DRAW);

    GLuint vboTex;
    glGenBuffers(1, &vboTex);
    glBindBuffer(GL_ARRAY_BUFFER, vboTex);
    glBufferData(GL_ARRAY_BUFFER, 2 * 6 * sizeof(GLfloat), &grassTexCoords, GL_STATIC_DRAW);

    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);

    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER, vboTex);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);

    return vao;
}

渲染

void render()
{
    glViewport(0, 0, window.getSize().x, window.getSize().y);
    glClearColor(.4f, .4f, .4f, 1.f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //1st program
    glUseProgram(sphereProgram);
    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
    glBindVertexArray(vao);
    glDrawArrays(GL_TRIANGLES, 0, objPointCount);

    //2nd program
    glFrontFace(GL_CCW);
    glDepthMask(GL_FALSE);
    glUseProgram(cubeProgram);
    glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
    glBindVertexArray(cubeVao);
    glDrawArrays(GL_TRIANGLES, 0, 36);
    glDepthMask(GL_TRUE);

    //3rd program
    glFrontFace(GL_CCW);
    glDisable(GL_CULL_FACE);
    glEnable(GL_TEXTURE_2D);
    sf::Texture::bind(&grassTex);
    glUseProgram(planeProgram);
    glBindVertexArray(planeVao);
    glDrawArrays(GL_TRIANGLES, 0, verts.size());
    //-----------------------

    window.display();
    //window.setFramerateLimit(FPS);
    window.setVerticalSyncEnabled(true);
}

顶点着色器

#version 410

layout (location = 0) in vec3 vertexPos;
layout (location = 1) in vec2 texCoords;

uniform mat4 view, proj;

out vec3 posEye;
out vec2 coords;

void main()
{
    coords = texCoords; //repeat texture over plane
    gl_Position = proj * view * vec4(vertexPos, 1.0);

    posEye = (view * vec4(vertexPos, 1.0)).xyz;
}

片段着色器

#version 410

in vec3 posEye;
in vec2 coords;
out vec4 fragColor;

uniform sampler2D tex;

//fog
const vec3 fogColor = vec3(0.2, 0.2, 0.2);
const float minFogRad = 300;
const float maxFogRad = 900;

void main()
{
    vec4 texture = texture2D(tex, coords);
    fragColor = texture;

    float distance = length(-posEye);
    float fogFactor = (distance - minFogRad) / (maxFogRad - minFogRad);
    fogFactor = clamp(fogFactor, 0.0, 1.0);

    fragColor.rgb = mix(fragColor.rgb, fogColor, fogFactor);
}

这里的问题是,纹理坐标只提供给第一个四边形(前 6 个顶点)。所有其他顶点似乎都得到 [0,0],这导致它们只读取左上角的纹素。这里的解决方案是为所有顶点提供足够的纹理坐标。

纹理坐标通常不一定在 0 和 1 之间。可以通过设置 GL_TEXTURE_WRAP_[RST].

来指定应如何处理 [0,1] 之外的值

请注意,当 OpenGL 尝试读取缓冲区外部数据时,在 VBO 中未提供足够的数据会导致崩溃(取决于驱动程序)。

您正在使用 GL_ARRAY_BUFFER 每个顶点存储 数据。

2GL_FLOAT glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL); 中的参数声明您在 vboTex 每个顶点 但你还没有这样做,你在 仅第一个四边形 .[=16= 中的每个顶点有 2 个浮点数]

以同样的方式,3GL_FLOAT 参数在 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL); 中声明你有3 个浮动 vbo 每个顶点 你已经完成了。

最简单的解决方法是创建一个更大的 GL_ARRAY_BUFFER,它为每个四边形重复相同的纹理坐标。