opengl 2D纹理之间的黑线

ltskdhd1  于 2022-11-04  发布在  其他
关注(0)|答案(2)|浏览(277)

我刚开始学习opengl技术。我的程序绘制二维等距图块,程序输出如下:

当两个纹理重叠或两个纹理接触时,出现黑线的原因未知。
程式码范例:

typedef unsigned int ID;

class GraphicEngine {
public:
    GraphicEngine();
    ~GraphicEngine();
    void initShaders(const char* vertexShaderSource, const char* fragmentShaderSource);
    void initRenderData(float vertices[], unsigned int size);
    std::vector<ID> initTextures(std::vector<std::string>& paths);
    void drawTextures(std::vector<ID> testuresIds);

private:
    GraphicEngine(GraphicEngine&) = delete;
    GraphicEngine(GraphicEngine&&) = delete;
    GraphicEngine& operator=(const GraphicEngine& other) = delete;
private:
    unsigned int VBO = 0; 
    unsigned int VAO = 0;
    unsigned int EBO = 0;
    unsigned int shaderProgram;
};

GraphicEngine::GraphicEngine() {

}

GraphicEngine::~GraphicEngine() {
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
}

void GraphicEngine::initShaders(const char* vertexShaderSource, const char* fragmentShaderSource) {
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    shaderProgram = glCreateProgram();
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
}

void GraphicEngine::initRenderData(float vertices[], unsigned int size) {
    unsigned int indices[] = {
        0, 1, 3,
        1, 2, 3
    };
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
}

std::vector<ID> GraphicEngine::initTextures(std::vector<std::string>& paths) {
    std::vector<ID> ids(paths.size());
    stbi_set_flip_vertically_on_load(true);
    for (int i = 0; i < paths.size(); i++) {
        unsigned int texture;
        glGenTextures(1, &ids[i]);
        glBindTexture(GL_TEXTURE_2D, ids[i]);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        int width, height, nrChannels;
        unsigned char* data = stbi_load(paths[i].c_str(), &width, &height, &nrChannels, STBI_rgb_alpha);
        if (data)
        {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
            glGenerateMipmap(GL_TEXTURE_2D);
        }
        stbi_image_free(data);
    }
    return ids;
}

void GraphicEngine::drawTextures(std::vector<ID> testuresIds) {
    static bool ex = false;
    for (auto testureId : testuresIds) {
        for (int i = 0; i < 4; i++) {
            glBindTexture(GL_TEXTURE_2D, testureId);
            glm::mat4 transform = glm::mat4(1.0f);
            transform = glm::translate(transform, glm::vec3(i * 0.6f + 0.0f, 0.0f, 0.0f));
            glUseProgram(shaderProgram);
            unsigned int transformLoc = glGetUniformLocation(shaderProgram, "transform");
            glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));
            glBindVertexArray(VAO);
            glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        }
        for (int i = 0; i < 4; i++) {
            glBindTexture(GL_TEXTURE_2D, testureId);
            glm::mat4 transform = glm::mat4(1.0f);
            transform = glm::translate(transform, glm::vec3(i * 0.6f - 0.3f, -0.16f, 0.0f));
            glUseProgram(shaderProgram);
            unsigned int transformLoc = glGetUniformLocation(shaderProgram, "transform");
            glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));
            glBindVertexArray(VAO);
            glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        }
    }

const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

Window::Window():window(nullptr) {}

Window::~Window() {
    glfwTerminate();
}

bool Window::initWindowResources() {
    bool result = false;
    if (glfwInit() == GLFW_TRUE) {
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
        window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
        if (window != nullptr) {
            glfwMakeContextCurrent(window);
            if (glfwSetFramebufferSizeCallback(window, [](GLFWwindow* window, int width, int height) {
                glViewport(0, 0, width, height); }) == NULL) {
                if (gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
                    result = true;
                }
            }
        }
    }
    return result;
}

const char* vertexShaderSource =
"#version 330 core\n"
"layout(location = 0) in vec3 aPos;\n"
"layout(location = 1) in vec2 aTexCoord;\n"
"out vec2 TexCoord;\n"
"uniform mat4 transform;\n"
"void main()\n"
"{\n"
"    gl_Position = transform * vec4(aPos, 1.0);\n"
"    TexCoord = vec2(aTexCoord.x, aTexCoord.y);\n"
"}\n\0";

const char* fragmentShaderSource =
"#version 330 core\n"
"out vec4 FragColor;\n"
"in vec3 ourColor;\n"
"in vec2 TexCoord;\n"
"uniform sampler2D texture1;\n"
"void main()\n"
"{\n"
"    FragColor = texture(texture1, TexCoord);\n"
"}\n\0";

void Window::mainWindowLoop() {

    graphicEngine.initShaders(vertexShaderSource, fragmentShaderSource);
    std::vector<std::string> pathsTextures = { "C:\\Users\\Олег\\\Desktop\\sea1.png" };
    float vertices[] = {
        // positions          // colors           // texture coords
        -1.3f,  0.16f, 0.0f,  1.0f, 1.0f, // top right
        -1.3f, -0.16f, 0.0f,  1.0f, 0.0f, // bottom right
        -0.7f, -0.16f, 0.0f,  0.0f, 0.0f, // bottom left
        -0.7f,  0.16f, 0.0f,  0.0f, 1.0f  // top left 
    };
    graphicEngine.initRenderData(vertices, sizeof(vertices));
    std::vector<ID> idsTextures = graphicEngine.initTextures(pathsTextures);
    while (!glfwWindowShouldClose(window))
    {
        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        graphicEngine.drawTextures(idsTextures);
        glfwSwapBuffers(window);
        glfwPollEvents();
    }
}

int main()
{
    Window window;
    if (window.initWindowResources()) {
        window.mainWindowLoop();
    }

    return 0;
}

图片大小:62x34像素,透明子画面,使用prog创建png:皮斯克拉普
请提供有关此问题的信息:有关此问题的原因以及如何解决此问题的信息。

svmlkihl

svmlkihl1#

我能够重现你的问题。你正在使用非预乘alpha,这是众所周知的产生不理想的结果时,渲染半透明的图像。看看这篇文章:http://www.realtimerendering.com/blog/gpus-prefer-premultiplication/
现在,要解决您的问题,请首先将混合函数更改为glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA)。其次,stbi在加载时不会预乘alpha,您必须手动执行此操作。每个像素由4个字节组成,即0-255范围内的红、绿色、蓝和alpha。将每个值转换为规范化范围(0.0f - 1.0f)除以255.0f,将r、g和b乘以α,然后将其乘以255.0f;

相关问题