Трансляция вывода фрагмента шейдера на все цветовые вложения FBO? - PullRequest
0 голосов
/ 08 декабря 2018

Есть ли способ заставить OpenGL ES 3.0 транслировать значение фрагментного шейдера с одним выходом всем активным (согласно glDrawBuffers()) цветным вложениям FBO?

Если возможно, я бы хотелсохраняйте мои шейдеры более или менее как есть и избегайте перезаписи, требуемой для нескольких layout 'd выводов:

layout( location = 0 ) out vec4 out_color0;
layout( location = 1 ) out vec4 out_color1;
layout( location = 2 ) out vec4 out_color2;
layout( location = 3 ) out vec4 out_color3;
void main()
{
    out_color0 = vec4( 1.0, 0.2, 0.0, 1.0 );
    out_color1 = vec4( 1.0, 0.2, 0.0, 1.0 );
    out_color2 = vec4( 1.0, 0.2, 0.0, 1.0 );
    out_color3 = vec4( 1.0, 0.2, 0.0, 1.0 );
}

... или выходного массива:

out vec4 out_color[4];
void main()
{
    out_color[0] = vec4( 1.0, 0.2, 0.0, 1.0 );
    out_color[1] = vec4( 1.0, 0.2, 0.0, 1.0 );
    out_color[2] = vec4( 1.0, 0.2, 0.0, 1.0 );
    out_color[3] = vec4( 1.0, 0.2, 0.0, 1.0 );
}

Вот программа, которую я использую для тестирования, она (пытается) нарисовать красный треугольник для всех четырех вложений FBO, а затем перетаскивает 3-е вложение в стандартный кадровый буфер:

#include <glad/glad.h>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>

#include <cstdlib>
#include <cstdarg>
#include <iostream>
#include <vector>

struct Program
{
    static GLuint Load( const char* shader, ... )
    {
        const GLuint prog = glCreateProgram();
        va_list args;
        va_start( args, shader );
        while( shader )
        {
            AttachShader( prog, va_arg( args, GLenum ), shader );
            shader = va_arg( args, const char* );
        }
        va_end( args );
        glLinkProgram( prog );
        CheckStatus( prog );
        return prog;
    }

private:
    static void CheckStatus( GLuint obj )
    {
        GLint status = GL_FALSE;
        if( glIsShader(obj) ) glGetShaderiv( obj, GL_COMPILE_STATUS, &status );
        if( glIsProgram(obj) ) glGetProgramiv( obj, GL_LINK_STATUS, &status );
        if( status == GL_TRUE ) return;
        GLchar log[ 1 << 15 ] = { 0 };
        if( glIsShader(obj) ) glGetShaderInfoLog( obj, sizeof(log), NULL, log );
        if( glIsProgram(obj) ) glGetProgramInfoLog( obj, sizeof(log), NULL, log );
        std::cerr << log << std::endl;
        std::exit( EXIT_FAILURE );
    }

    static void AttachShader( GLuint program, GLenum type, const char* src )
    {
        const GLuint shader = glCreateShader( type );
        glShaderSource( shader, 1, &src, NULL );
        glCompileShader( shader );
        CheckStatus( shader );
        glAttachShader( program, shader );
        glDeleteShader( shader );
    }
};

const char* vert = 1 + R"GLSL(
#version 300 es
void main()
{
    const vec2 verts[3] = vec2[3]
    (
        vec2( -0.5, -0.5 ),
        vec2(  0.5, -0.5 ),
        vec2(  0.0,  0.5 )
    );
    gl_Position = vec4( verts[ gl_VertexID ], 0.0, 1.0 );
}
)GLSL";

const char* frag = 1 + R"GLSL(
#version 300 es
precision mediump float;
out vec4 out_color;
void main()
{
    out_color = vec4( 1.0, 0.2, 0.0, 1.0 );
}
)GLSL";

int main( int argc, char** argv )
{
    glfwSetErrorCallback( []( int err, const char* desc )
    {
        std::cerr << "GLFW error: " << desc << std::endl;
    } );

    if( !glfwInit() )
        return EXIT_FAILURE;

    glfwWindowHint( GLFW_CLIENT_API, GLFW_OPENGL_ES_API );
    glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
    glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 0 );
    glfwWindowHint( GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API );
    GLFWwindow* window = glfwCreateWindow( 640, 480, "GLFW", NULL, NULL );
    if( nullptr == window )
        return EXIT_FAILURE;

    glfwMakeContextCurrent( window );
    glfwSwapInterval( 1 );
    gladLoadGLES2Loader( (GLADloadproc)glfwGetProcAddress );

    const GLuint prog = Program::Load( vert, GL_VERTEX_SHADER, frag, GL_FRAGMENT_SHADER, NULL );
    glUseProgram( prog );

    // init framebuffer attachments
    std::vector< GLuint > textures( 4, 0 );
    glGenTextures( 4, textures.data() );
    for( size_t i = 0; i < textures.size(); ++ i )
    {
        glBindTexture( GL_TEXTURE_2D, textures[i] );
        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, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr );
    }
    GLuint rbDepth = 0;
    glGenRenderbuffers(1, &rbDepth );
    glBindRenderbuffer( GL_RENDERBUFFER, rbDepth );
    glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32 );

    // init FBO
    GLuint fbo = 0;
    glGenFramebuffers( 1, &fbo );
    glBindFramebuffer( GL_FRAMEBUFFER, fbo );
    for( size_t i = 0; i < textures.size(); ++ i )
    {
        glFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, textures[i], 0 );
    }
    glFramebufferRenderbuffer( GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbDepth );
    if( GL_FRAMEBUFFER_COMPLETE != glCheckFramebufferStatus( GL_FRAMEBUFFER ) )
    {
        std::cerr << "Incomplete framebuffer" << std::endl;
        std::exit( EXIT_FAILURE );
    }

    while( !glfwWindowShouldClose( window ) )
    {
        glfwPollEvents();

        // render to FBO
        glBindFramebuffer( GL_FRAMEBUFFER, fbo );
        GLenum bufs[] =
        {
            GL_COLOR_ATTACHMENT0 + 0,
            GL_COLOR_ATTACHMENT0 + 1,
            GL_COLOR_ATTACHMENT0 + 2,
            GL_COLOR_ATTACHMENT0 + 3,
        };
        glDrawBuffers( 4, bufs );
        glViewport( 0, 0, 32, 32 );
        glClearColor( 0.0f, 0.6f, 1.0f, 1.f );
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
        glDrawArrays( GL_TRIANGLES, 0, 3 );

        // switch back to default framebuffer & clear it with non-black color
        glBindFramebuffer( GL_FRAMEBUFFER, 0 );
        GLenum defaultBuf = GL_BACK;
        glDrawBuffers( 1, &defaultBuf );
        glClearColor( 1.0f, 0.0f, 1.0f, 1.f );
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        // blit a color attachment to the default framebuffer
        glBindFramebuffer( GL_READ_FRAMEBUFFER, fbo );
        glReadBuffer( GL_COLOR_ATTACHMENT0 + 2 );
        glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
        glBlitFramebuffer( 0, 0, 32, 32, 0, 0, 640, 480, GL_COLOR_BUFFER_BIT, GL_LINEAR );

        glfwSwapBuffers( window );
    }

    glfwMakeContextCurrent( NULL );
    glfwDestroyWindow( window );

    glfwTerminate();
    return EXIT_SUCCESS;
}

В этой Windows10 машина, использующая недавно созданную версию ANGLE Я получаю синий прозрачный цвет, но без треугольника («неопределенный») для 3-го вложения:

bad output

Первое вложение в порядке:

good output

1 Ответ

0 голосов
/ 10 декабря 2018

В API нет такой функциональности :

3) Должны ли мы поддерживать широковещательную рассылку от gl_FragColor на все gl_FragData [x] или она должна быть синонимом gl_FragData [0]?

ОБСУЖДЕНИЕ. При использовании NV_draw_buffers запись в gl_FragColor выполняет запись во все включенные буферы рисования (т. Е. Широковещательную рассылку).В OpenGL ES 3.0 при использовании ESSL 1.0 gl_FragColor эквивалентно записи одного вывода в gl_FragData [0], и несколько выходов невозможно.При использовании ESSL 3.0 могут использоваться только определяемые пользователем переменные.

Если поддерживается широковещание, некоторым реализациям может потребоваться заменить записи в gl_FragColor реплицированными записями во все возможные местоположения gl_FragData, когда это расширение включено.

RESOLVED: записи в gl_FragColor транслируются во все разрешенные цветовые буферы.ES 3.0, использующий ESSL 1.0, не поддерживает широковещательную передачу, поскольку ESSL 1.0 не был расширен, чтобы иметь несколько цветовых выходов (но это то, что добавляет это расширение). ESSL 3.0 не поддерживает широковещательную рассылку, поскольку у него вообще нет переменной gl_FragColor, а есть только определенные пользователем переменные. Это расширение расширяет ESSL 1.0, чтобы иметь несколько цветовых выходов.Трансляция с gl_FragColor на все включенные цветовые буферы наиболее соответствует существующим на сегодняшний день расширениям буфера рисования (как NV_draw_buffers, так и настольному GL).

...