简体   繁体   English

如何使用 OpenGL FBO 进行多重采样

[英]How to use Multisampling with OpenGL FBOs

I'm trying to enable mutlisampling and alpha-to-coverage for an FBO.我正在尝试为 FBO 启用多重采样和 alpha-to-coverage。 Using the default framebuffer, all I have to do is call glEnable(GL_MULTISAMPLE) and glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE) .使用默认帧缓冲区,我所要做的就是调用glEnable(GL_MULTISAMPLE)glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE) However, I am unable to achieve the same effect using my own FBO.但是,我无法使用我自己的 FBO 达到相同的效果。

My goal: Draw the scene to an FBO the same way it would be drawn to the default framebuffer with the above properties.我的目标:将场景绘制到 FBO,就像将场景绘制到具有上述属性的默认帧缓冲区一样。 From there I want to be able to use the image as a texture for future passes through a shader.从那里我希望能够将图像用作未来通过着色器的纹理。

This works : Code for making an FBO without multisampling/alpha-to-coverage, 1 color attachment, 1 depth attachment:这有效:用于制作没有多重采样/alpha 覆盖、1 个颜色附件、1 个深度附件的 FBO 的代码:

// Generate the color attachment
glGenTextures(1,&defaultColorAttachment0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,defaultColorAttachment0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,screenWidth,screenHeight,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL);

// Bind the texture to the FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, defaultColorAttachment0,0);

// Generate the depth attachment
glGenRenderbuffers(1,&defaultDepthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, defaultDepthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, screenWidth, screenHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, defaultDepthBuffer);

This doesn't work .这行不通 Code trying to make a multisampled FBO:尝试制作多采样 FBO 的代码:

// Generate the color attachment
glGenTextures(1,&defaultColorAttachment0);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, defaultColorAttachment0);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA, screenWidth, screenHeight, GL_FALSE);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, defaultColorAttachment0,0);

// Generate the depth attachment
glGenRenderbuffers(1,&defaultDepthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, defaultDepthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, screenWidth, screenHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, defaultDepthBuffer);

I have tried looking through the OpenGL wiki on this, although the it's incomplete (various unfinished headings make it look unprofessional).我试过浏览 OpenGL wiki,虽然它不完整(各种未完成的标题使它看起来不专业)。 glGetError never complains. glGetError从不抱怨。 I've tried messing around with this, but I either get a black screen or a screen full of garbage pixels.我已经尝试过解决这个问题,但我要么得到黑屏,要么得到一个满是垃圾像素的屏幕。

Main Question: What things do I need to consider/change and where (FBO creation, textures, shaders) in order to get multisampling and alpha-to-coverage to work with an FBO?主要问题:为了让多重采样和 alpha-to-coverage 与 FBO 一起工作,我需要考虑/更改哪些内容以及在何处(FBO 创建、纹理、着色器)?

You need to allocate a multisampled depth buffer for this to work correctly and give it the same number of samples as your color buffer.您需要为此分配一个多采样深度缓冲区才能正常工作,并为其提供与颜色缓冲区相同数量的样本。 In other words, you should be calling glRenderbufferStorageMultisample (...) instead of glRenderbufferStorage (...) .换句话说,您应该调用glRenderbufferStorageMultisample (...)而不是glRenderbufferStorage (...)

Your FBO should be failing a completeness check the way it is allocated right now.您的 FBO 应该无法通过其现在分配方式的完整性检查。 A call to glCheckFramebufferStatus (...) ought to return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE because your depth buffer has exactly 1 sample and your color buffer attachment has 4 .调用glCheckFramebufferStatus (...)应该返回GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE因为您的深度缓冲区正好有1 个样本,而您的颜色缓冲区附件有4 个


Since you are also using a multisampled texture attachment in this FBO, you should be aware of differences between sampling a single-sampled texture vs. multisampled in GLSL shaders.由于您还在此 FBO 中使用了多重采样纹理附件,因此您应该了解在 GLSL 着色器中采样单采样纹理与多重采样之间的差异。

Multisampled textures have a special sampler uniform type ( eg sampler2DMS ) and you have to explicitly fetch each sample in the texture by its integer (non-normalized) texel coordinate and sample index using texelFetch (...) .多重采样纹理具有特殊的采样器统一类型(例如sampler2DMS ),您必须使用texelFetch (...)通过其整数(非标准化)纹素坐标和样本索引明确获取纹理中的每个样本。 This also means that they cannot be filtered or mip-mapped.这也意味着它们不能被过滤或 mip 映射。

You probably do not want a multisampled texture in this case, you probably want to use glBlitFramebuffer (...) to do the MSAA resolve into a single-sampled FBO.在这种情况下,您可能不想要多采样纹理,您可能想要使用glBlitFramebuffer (...)将 MSAA 解析为单采样 FBO。 If you do this instead you can read the anti-aliased results in your shaders rather than having to fetch each sample and implement the anti-aliasing yourself.如果您这样做,您可以在着色器中读取抗锯齿结果,而不必获取每个样本并自己实施抗锯齿。

Here is a working example to go along with the accepted answer.这是一个与接受的答案一起使用的工作示例。 It is a modified example of the triangle example from the LearnopenGL tutorials to draw a MSAA custom framebuffer to a quad which is then draw to the default framebuffer (the screen):这是 LearnopenGL 教程中三角形示例的修改示例,用于将 MSAA 自定义帧缓冲区绘制到四边形,然后绘制到默认帧缓冲区(屏幕):

#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>

const char *vertexShaderSource = "#version 330 core\n"
    "layout (location = 0) in vec3 aPos;\n"
    "void main()\n"
    "{\n"
    "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
    "}\0";
const char *fragmentShaderSource = "#version 330 core\n"
    "out vec4 FragColor;\n"
    "void main()\n"
    "{\n"
    "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
    "}\n\0";

const char *postProcessvertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec2 position;\n"             
"layout (location = 1) in vec2 inTexCoord;\n"

"out vec2 texCoord;\n"
"void main(){\n"
"    texCoord = inTexCoord;\n"
"    gl_Position = vec4(position.x, position.y, 0.0f, 1.0f);\n"
"}\n\0";

const char *postProcessFragmentShaderSource = "#version 330 core\n"
"out vec4 fragmentColor;\n"
"in vec2 texCoord;\n"
"//notice the sampler\n"
"uniform sampler2DMS screencapture;\n"
"uniform int viewport_width;\n"
"uniform int viewport_height;\n"

"void main(){\n"
"   //texelFetch requires a vec of ints for indexing (since we're indexing pixel locations)\n"
"   //texture coords is range [0, 1], we need range [0, viewport_dim].\n"
"   //texture coords are essentially a percentage, so we can multiply text coords by total size \n"
"   ivec2 vpCoords = ivec2(viewport_width, viewport_height);\n"
"   vpCoords.x = int(vpCoords.x * texCoord.x); \n"
"   vpCoords.y = int(vpCoords.y * texCoord.y);\n"
"   //do a simple average since this is just a demo\n"
"   vec4 sample1 = texelFetch(screencapture, vpCoords, 0);\n"
"   vec4 sample2 = texelFetch(screencapture, vpCoords, 1);\n"
"   vec4 sample3 = texelFetch(screencapture, vpCoords, 2);\n"
"   vec4 sample4 = texelFetch(screencapture, vpCoords, 3);\n"
"   fragmentColor = vec4(sample1 + sample2 + sample3 + sample4) / 4.0f;\n"
"}\n\0";

int main()
{
    int width = 800;
    int height = 600;
    
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

    GLFWwindow* window = glfwCreateWindow(width, height, "OpenglContext", nullptr, nullptr);
    if (!window)
    {
        std::cerr << "failed to create window" << std::endl;
        exit(-1);
    }
    glfwMakeContextCurrent(window);

    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cerr << "failed to initialize glad with processes " << std::endl;
        exit(-1);
    }

    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

    int samples = 4;
    float quadVerts[] = {
        -1.0, -1.0,     0.0, 0.0,
        -1.0, 1.0,      0.0, 1.0,
        1.0, -1.0,      1.0, 0.0,

        1.0, -1.0,      1.0, 0.0,
        -1.0, 1.0,      0.0, 1.0,
        1.0, 1.0,       1.0, 1.0
    };

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

    GLuint postVBO;
    glGenBuffers(1, &postVBO);
    glBindBuffer(GL_ARRAY_BUFFER, postVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(quadVerts), quadVerts, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), reinterpret_cast<void*>(0));
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), reinterpret_cast<void*>(2 * sizeof(float)));
    glEnableVertexAttribArray(1);

    glBindVertexArray(0);


    GLuint msaaFB;
    glGenFramebuffers(1, &msaaFB);
    glBindFramebuffer(GL_FRAMEBUFFER, msaaFB); //bind both read/write to the target framebuffer

    GLuint texMutiSampleColor;
    glGenTextures(1, &texMutiSampleColor);
    glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texMutiSampleColor);
    glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGB, width, height, GL_TRUE);
    glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, texMutiSampleColor, 0);

    glBindFramebuffer(GL_FRAMEBUFFER, 0);


    // vertex shader
    unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    // check for shader compile errors

    // fragment shader
    unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);
    // check for shader compile errors

    // link shaders
    unsigned int shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    // check for linking errors

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);


    //postprocess vertex shader
    unsigned int postProcessVertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(postProcessVertexShader, 1, &postProcessvertexShaderSource, NULL);
    glCompileShader(postProcessVertexShader);

    // postprocess fragment shader
    unsigned int postProcessFragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(postProcessFragmentShader, 1, &postProcessFragmentShaderSource, NULL);
    glCompileShader(postProcessFragmentShader);
    // check for shader compile errors

    // link shaders
    unsigned int postProcessShaderProgram = glCreateProgram();
    glAttachShader(postProcessShaderProgram, postProcessVertexShader);
    glAttachShader(postProcessShaderProgram, postProcessFragmentShader);
    glLinkProgram(postProcessShaderProgram);
    // check for linking errors

    glDeleteShader(postProcessVertexShader);
    glDeleteShader(postProcessFragmentShader);

    glUseProgram(postProcessShaderProgram);
    glUniform1i(glGetUniformLocation(postProcessShaderProgram, "screencapture"), 0); 
    glUniform1i(glGetUniformLocation(postProcessShaderProgram, "viewport_width"), width); 
    glUniform1i(glGetUniformLocation(postProcessShaderProgram, "viewport_height"), height); 

    float vertices[] = {
        -0.5f, -0.5f, 0.0f,
         0.5f, -0.5f, 0.0f,
         0.0f,  0.5f, 0.0f 
    }; 

    unsigned int VBO, VAO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0); 
    glBindVertexArray(0); 

    bool use_msaa = true;

    while (!glfwWindowShouldClose(window))
    {

        if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        {
            glfwSetWindowShouldClose(window, true);
        }

        if (glfwGetKey(window, GLFW_KEY_R) == GLFW_PRESS)
            use_msaa = true;
        if (glfwGetKey(window, GLFW_KEY_T) == GLFW_PRESS)
            use_msaa = false;     

        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        if (use_msaa) {
            glBindFramebuffer(GL_FRAMEBUFFER, msaaFB);
        }

        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // draw our first triangle
        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLES, 0, 3);

        if (use_msaa) {
            glBindFramebuffer(GL_FRAMEBUFFER, 0);
            glUseProgram(postProcessShaderProgram);
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texMutiSampleColor);
            glBindVertexArray(postVAO);
            glDrawArrays(GL_TRIANGLES, 0, 6);
        }

        glfwSwapBuffers(window);
        glfwPollEvents();

    }
    glfwTerminate();
    // cleanup
}

Thankyou Matt Stone from the comment section of LearnOpenGL for the working code.感谢来自 LearnOpenGL 评论部分的 Matt Stone 提供工作代码。

Adding to jackw11111's answer, I wanted to test this sample code in python.添加到 jackw11111 的答案中,我想在 python 中测试这个示例代码。 Enclosed is my near 1:1 translation to python of code apparently by Matt Stone in comments of LearnOpenGL.随附的是我对 python 代码的近 1:1 翻译,这显然是由 Matt Stone 在 LearnOpenGL 的评论中编写的。 Tested on Ubuntu and MacOS.在 Ubuntu 和 MacOS 上测试。

## Not needed for python.
## #include <glad/glad.h>

# Setup might be something like:
#     python3 -m venv venv_msaa
#     source venv_msaa/bin/activate
#     pip install PyOpenGL glfw numpy

# Note: On a MacOS hidpi screen, the results will vary.

import ctypes
import numpy as np

import glfw
from OpenGL.GL import *

VERTEX_SHADER_SOURCE = """#version 330 core
    layout (location = 0) in vec3 aPos;

    void main()
    {
       gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
    }
"""

FRAGMENT_SHADER_SOURCE = """#version 330 core
    out vec4 FragColor;

    void main()
    {
       FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
    }
"""

POSTPROCESS_VERTEX_SHADER_SOURCE = """#version 330 core
    layout (location = 0) in vec2 position;
    layout (location = 1) in vec2 inTexCoord;
    out vec2 texCoord;

    void main(){
        texCoord = inTexCoord;
        gl_Position = vec4(position.x, position.y, 0.0f, 1.0f);
    }
"""

POSTPROCESS_FRAGMENT_SHADER_SOURCE = """#version 330 core
    out vec4 fragmentColor;
    in vec2 texCoord;
    // notice the sampler
    uniform sampler2DMS screencapture;
    uniform int viewport_width;
    uniform int viewport_height;
    
    void main(){
       // texelFetch requires a vec of ints for indexing (since we're indexing pixel locations)
       // texture coords is range [0, 1], we need range [0, viewport_dim].
       // texture coords are essentially a percentage, so we can multiply text coords by total size 
       ivec2 vpCoords = ivec2(viewport_width, viewport_height);
       vpCoords.x = int(vpCoords.x * texCoord.x); 
       vpCoords.y = int(vpCoords.y * texCoord.y);
       // do a simple average since this is just a demo
       vec4 sample1 = texelFetch(screencapture, vpCoords, 0);
       vec4 sample2 = texelFetch(screencapture, vpCoords, 1);
       vec4 sample3 = texelFetch(screencapture, vpCoords, 2);
       vec4 sample4 = texelFetch(screencapture, vpCoords, 3);
       fragmentColor = vec4(sample1 + sample2 + sample3 + sample4) / 4.0f;
    }
"""

def main():
    width = 800
    height = 600
    
    glfw.init()
    glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
    glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3)
    glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
    glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, GL_TRUE)

    window = glfw.create_window(width, height, "OpenglContext", None, None)
    if not window:
        print("failed to create window")
        sys.exit(-1)
    glfw.make_context_current(window);

## Not needed for python.
##    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
##    {
##        std::cerr << "failed to initialize glad with processes " << std::endl;
##        exit(-1);
##    }

    glfw.set_input_mode(window, glfw.CURSOR, glfw.CURSOR_DISABLED)

    samples = 4
    quadVerts = np.array([
        -1.0, -1.0,  0.0, 0.0,
        -1.0,  1.0,  0.0, 1.0,
         1.0, -1.0,  1.0, 0.0,

         1.0, -1.0,  1.0, 0.0,
        -1.0,  1.0,  0.0, 1.0,
         1.0,  1.0,  1.0, 1.0
    ], dtype=np.float32)

    postVAO = glGenVertexArrays(1)
    glBindVertexArray(postVAO)

    sizeof_float = ctypes.sizeof(ctypes.c_float) # Complicated way of saying 4
    postVBO = glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, postVBO)
    glBufferData(GL_ARRAY_BUFFER, quadVerts.nbytes, quadVerts.ctypes._as_parameter_, GL_STATIC_DRAW)

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof_float, ctypes.c_void_p(0))
    glEnableVertexAttribArray(0)

    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof_float, ctypes.c_void_p(2 * sizeof_float))
    glEnableVertexAttribArray(1)

    glBindVertexArray(0)


    msaaFB = glGenFramebuffers(1)
    glBindFramebuffer(GL_FRAMEBUFFER, msaaFB); # bind both read/write to the target framebuffer

    texMutiSampleColor = glGenTextures(1)
    glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texMutiSampleColor)
    glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGB, width, height, GL_TRUE)
    glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0)
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, texMutiSampleColor, 0)

    glBindFramebuffer(GL_FRAMEBUFFER, 0)

    # vertex shader
    vertexShader = glCreateShader(GL_VERTEX_SHADER)
    glShaderSource(vertexShader, VERTEX_SHADER_SOURCE)
    glCompileShader(vertexShader)
    # check for shader compile errors

    # fragment shader
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER)
    glShaderSource(fragmentShader, FRAGMENT_SHADER_SOURCE)
    glCompileShader(fragmentShader)
    # check for shader compile errors

    # link shaders
    shaderProgram = glCreateProgram()
    glAttachShader(shaderProgram, vertexShader)
    glAttachShader(shaderProgram, fragmentShader)
    glLinkProgram(shaderProgram)
    # check for linking errors

    glDeleteShader(vertexShader)
    glDeleteShader(fragmentShader)

    #postprocess vertex shader
    postProcessVertexShader = glCreateShader(GL_VERTEX_SHADER)
    glShaderSource(postProcessVertexShader, POSTPROCESS_VERTEX_SHADER_SOURCE)
    glCompileShader(postProcessVertexShader)
    # check for shader compile errors

    # postprocess fragment shader
    postProcessFragmentShader = glCreateShader(GL_FRAGMENT_SHADER)
    glShaderSource(postProcessFragmentShader, POSTPROCESS_FRAGMENT_SHADER_SOURCE)
    glCompileShader(postProcessFragmentShader)
    # check for shader compile errors

    # link shaders
    postProcessShaderProgram = glCreateProgram()
    glAttachShader(postProcessShaderProgram, postProcessVertexShader)
    glAttachShader(postProcessShaderProgram, postProcessFragmentShader)
    glLinkProgram(postProcessShaderProgram)
    # check for linking errors

    glDeleteShader(postProcessVertexShader)
    glDeleteShader(postProcessFragmentShader)

    glUseProgram(postProcessShaderProgram)
    glUniform1i(glGetUniformLocation(postProcessShaderProgram, "screencapture"), 0) 
    glUniform1i(glGetUniformLocation(postProcessShaderProgram, "viewport_width"), width) 
    glUniform1i(glGetUniformLocation(postProcessShaderProgram, "viewport_height"), height) 

    vertices = np.array([
        -0.5, -0.5, 0.0,
         0.5, -0.5, 0.0,
         0.0,  0.5, 0.0 
    ], dtype=np.float32)

    VAO = glGenVertexArrays(1)
    VBO = glGenBuffers(1)
    glBindVertexArray(VAO)
    glBindBuffer(GL_ARRAY_BUFFER, VBO)
    glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices.ctypes._as_parameter_, GL_STATIC_DRAW)
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof_float, ctypes.c_void_p(0))
    glEnableVertexAttribArray(0)
    glBindBuffer(GL_ARRAY_BUFFER, 0) 
    glBindVertexArray(0)

    use_msaa = True

    while not glfw.window_should_close(window):

        if glfw.get_key(window, glfw.KEY_ESCAPE) == glfw.PRESS:
            glfw.set_window_should_close(window, True)

        if glfw.get_key(window, glfw.KEY_R) == glfw.PRESS:
            use_msaa = True
        if glfw.get_key(window, glfw.KEY_T) == glfw.PRESS:
            use_msaa = False

        glClearColor(0.0, 0.0, 0.0, 1.0)
        glClear(GL_COLOR_BUFFER_BIT)

        if use_msaa:
            glBindFramebuffer(GL_FRAMEBUFFER, msaaFB)

        glClearColor(0.0, 0.0, 0.0, 1.0)
        glClear(GL_COLOR_BUFFER_BIT)

        # draw our first triangle
        glUseProgram(shaderProgram)
        glBindVertexArray(VAO)
        glDrawArrays(GL_TRIANGLES, 0, 3)
        glBindVertexArray(0)

        if use_msaa:
            glBindFramebuffer(GL_FRAMEBUFFER, 0)
            glUseProgram(postProcessShaderProgram)
            glActiveTexture(GL_TEXTURE0)
            glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texMutiSampleColor)
            glBindVertexArray(postVAO)
            glDrawArrays(GL_TRIANGLES, 0, 6)
            glBindVertexArray(0)

        glfw.swap_buffers(window)
        glfw.poll_events()

    glfw.terminate()
    # cleanup

if __name__ == "__main__":
    main()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM