glClearColor 和混合

问题描述

我使用 GLFW、OpenGL 4.6 和 VSCode,以及 MinGW64 g++。我正在尝试使用 glEnable(GL_BLEND);glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC1_ALPHA); 渲染透明纹理。虽然纹理确实在我的窗口上呈现,但似乎 glClearColor() 会显着影响混合。我对图形仍然很陌生,所以我不确定如何正确渲染纹理,而不管清晰的颜色设置为什么。另外,我是否需要为 2D 游戏启用深度? (shader.cpp 和 texture.cpp 取自 The Cherno 的 OpenGL 教程系列)

没有混合

混合

混合和黑色透明色(所需混合)

enter image description here

main.cpp:

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "GeometryUtil.h"
#include "Shader.h"
#include "Texture.h"
#include "Object.h"

#include <iostream>
#include <vector>

using namespace std;

int main() {
    if (!glfwInit()) { // Initialise GLFW
        cerr << "Failed to initialize GLFW" << endl;
        return -1;
    }

    glfwWindowHint(GLFW_SAMPLES,4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MInor,6);
    glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow* window {glfwCreateWindow(1280,720,"2D GAME",NULL,NULL)};
    if (window == NULL) {
        cerr << "Failed to open GLFW window." << endl;
        glfwTerminate();
        return -1;
    }

    glfwSetInputMode(window,GLFW_STICKY_KEYS,GL_TRUE);
    glfwMakeContextCurrent(window);

    glewExperimental = true;
    if (glewInit() != GLEW_OK) {
        cerr << "Failed to initialize GLEW" << endl;
        glfwTerminate();
        return -1;
    }
    
    cout << "OpenGL Version: " << glGetString(GL_VERSION) << endl;
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC1_ALPHA);
    glClearColor(0.0f,1.0f,0.0f,1.0f);

    gluint VAO;
    glGenVertexArrays(1,&VAO);
    glBindVertexArray(VAO);

    Object object {608,392};
    vector<float> vectorData;
    createQuad(object.getX(),object.getY(),vectorData);

    static const GLfloat texCoords[8] {
        0.0f,0.0f
    };

    gluint VBOs[2];
    glGenBuffers(2,VBOs);
    glBindBuffer(GL_ARRAY_BUFFER,VBOs[0]);
    glBufferData(GL_ARRAY_BUFFER,vectorData.size() * sizeof(vectorData),&vectorData.front(),GL_DYNAMIC_DRAW);
    glEnabLevertexAttribArray(0);
    glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,3 * sizeof(GLfloat),(void *) 0);
    glEnabLevertexAttribArray(2);
    glVertexAttribPointer(2,1,(void *) (2 * sizeof(GLfloat)));

    glBindBuffer(GL_ARRAY_BUFFER,VBOs[1]);
    glBufferData(GL_ARRAY_BUFFER,sizeof(texCoords),texCoords,GL_STATIC_DRAW);
    glEnabLevertexAttribArray(1);
    glVertexAttribPointer(1,nullptr);
    

    static const gluint texIndex[6] {
        0,3
    };
    gluint indexBuffer;
    glGenBuffers(1,&indexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,indexBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,6 * sizeof(texIndex),texIndex,GL_STATIC_DRAW);

    glm::mat4 Projection {glm::ortho(0.0f,1280.0f,720.0f,1.0f)};
    glm::mat4 View {glm::translate(glm::mat4(1.0f),glm::vec3(0,0))};

    glm::vec3 translationA {glm::vec3(0,0)};
    glm::mat4 Model = glm::translate(glm::mat4(1.0f),translationA); // Model Matrix (Using Identity Matrix - Origin)
    glm::mat4 mvp = Projection * View * Model;

    Shader shader {"shader/vertexShader.vert","shader/fragmentShader.frag"};
    shader.bind();
    shader.setUniformMat4f("MVP",mvp);
    int sampler[] {0,1};
    shader.setUniform1iv("v_Textures",sampler,2);

    Texture texture {"resources/sprites/test.png"};
    texture.bind();

    while (glfwGetKey(window,GLFW_KEY_ESCAPE) != GLFW_PRESS && glfwWindowShouldClose(window) == 0) {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,nullptr);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    glfwTerminate();
    return 0;
}

texture.cpp:

#define STB_IMAGE_IMPLEMENTATION
#include <GL/glew.h>
#include "Texture.h"
#include "stb_image.h"

#include <iostream>

Texture::Texture(const std::string &path) 
    : rendererID{0},filePath{path},localBuffer{nullptr},width{0},height{0},bPP{0} {
        // stbi_set_flip_vertically_on_load(1);
        localBuffer = stbi_load(path.c_str(),&width,&height,&bPP,4);
        if (localBuffer == nullptr)
            std::cout << "Unable to load texture file: " << path << std::endl;

        glGenTextures(1,&rendererID);
        glBindTexture(GL_TEXTURE_2D,rendererID);

        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
        glTexImage2D(GL_TEXTURE_2D,GL_RGBA8,width,height,GL_RGBA,GL_UNSIGNED_BYTE,localBuffer);

        unbind();

        if (localBuffer)
            stbi_image_free(localBuffer);
}
Texture::~Texture() {
    glDeleteTextures(1,&rendererID);
}

void Texture::bind(gluint slot) const {;
    glActiveTexture(GL_TEXTURE0 + slot);
    glBindTexture(GL_TEXTURE_2D,rendererID);
}
void Texture::unbind() const {
    glBindTexture(GL_TEXTURE_2D,0);
}

顶点着色器:

#version 460 core

layout(location = 0) in vec3 vertexCoords;
layout(location = 1) in vec2 textureCoords;
layout(location = 2) in float textureIndex;

out vec2 v_TexCoords;
out float v_TexIndex;

uniform mat4 MVP;

void main() {
    gl_Position = MVP * vec4(vertexCoords,1.0);
    v_TexCoords = textureCoords;
    v_TexIndex = textureIndex;
}

片段着色器:

#version 460 core

in vec2 v_TexCoords;
in float v_TexIndex;

uniform sampler2D v_Textures[2];

void main() {
    gl_FragColor = texture2D(v_Textures[int(v_TexIndex)],v_TexCoords);
}

解决方法

乍一看,一切都是正确的代码,是的,在 GL_SRC_ALPHA 作为第一个参数的情况下,背景会影响混合。

问题是第二个参数应该是 GL_ONE_MINUS_SRC_ALPHA 而不是 GL_ONE_MINUS_SRC1_ALPHA。在您的情况下,混合没有标准化,因此过多的绿色和全红色的值加起来就是黄色。

来源:https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBlendFuncSeparate.xhtml