OpenGL + SDL2 + Compute Shader = черный экран - PullRequest
2 голосов
/ 27 октября 2019

Я перевожу C raytracer в glsl, чтобы использовать его в вычислительном шейдере. Сейчас я просто пытаюсь отобразить на экране нечеткие узоры. Нет ошибок компиляции, но ничего не рендерится.

Я следовал этим двум урокам (последний довольно неполный и оставляет некоторые части, я мог бы пропустить некоторые вещи там) SDL2 с OpenGL - LeeZhi Eng Вычислительные шейдеры - уроки Антона по OpenGL4

Я не эксперт в opengl, поэтому я не уверен, что шейдер выводит текстуру? Или текстура не прорисована? Или проблема в другом месте?

Пожалуйста, опубликуйте точный синтаксис вместо просто расплывчатой ​​инструкции, такой как «вам нужно сделать x, инициализируя y и сбрасывая z», потому что я, вероятно, не буду знать синтаксис для выполнения xyz.

Обратите внимание: основная программа все еще на C, а не на C ++.

Скомпилировано с: -std=gnu18 -ffast-math -O3 -lm -lGLEW -lGL -lglut -Wall -pedantic -Werror -Wshadow -Wstrict-aliasing -Wstrict-overflow

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <math.h>

#define GLEW_STATIC
#include <GL/glew.h>
#include <GL/glu.h>
#include <GL/gl.h>

#include <SDL2/SDL.h>

int main(void)
{
    int tex_w = 1920;
    int tex_h = 1080;



    //////////////////////
    //
    //   SDL Stuff

    if (SDL_Init(SDL_INIT_VIDEO) < 0){
        printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
        return EXIT_FAILURE;
    }

    SDL_Window * window;
    window = SDL_CreateWindow(
        "Rendering first frame", 
        SDL_WINDOWPOS_UNDEFINED, 
        SDL_WINDOWPOS_UNDEFINED, 
        tex_w*scale, 
        tex_h*scale, 
        SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE
    );

    if (window == NULL){
        printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
        return EXIT_FAILURE;
    }

    #ifdef FULLSCREEN
    SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
    #endif

    SDL_Event event;



    //////////////////////
    //
    //   GL Stuff

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

    SDL_GLContext glContext = SDL_GL_CreateContext(window);

    if (glContext == NULL){
        printf("OpenGL context could not be created! SDL Error: %s\n", SDL_GetError());
        return EXIT_FAILURE;
    }

    glewInit();

    GLuint tex_output;
    glGenTextures(1, &tex_output);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, tex_output);
    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_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex_w, tex_h, 0, GL_RGBA, GL_FLOAT, NULL);
    glBindImageTexture(0, tex_output, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);



    //////////////////////
    //
    //   init compute shader

        const GLchar *the_ray_shader_string = "#ifdef GL_ES\
precision mediump float;\
#endif\
\
#extension GL_OES_standard_derivatives : enable\
\
uniform float time;\
uniform vec2 mouse;\
uniform vec2 resolution;\
layout(local_size_x = 1, local_size_y = 1) in;\
layout(rgba32f, binding = 0) uniform image2D img_output;\
\
void main( void ) {\
\
    vec2 position = ( gl_FragCoord.xy / resolution.xy ) + mouse / 4.0;\
\
    float color = 0.0;\
    color += sin( position.x * cos( time / 15.0 ) * 80.0 ) + cos( position.y * cos( time / 15.0 ) * 10.0 );\
    color += sin( position.y * sin( time / 10.0 ) * 40.0 ) + cos( position.x * sin( time / 25.0 ) * 40.0 );\
    color += sin( position.x * sin( time / 5.0 ) * 10.0 ) + sin( position.y * sin( time / 35.0 ) * 80.0 );\
    color *= sin( time / 10.0 ) * 0.5;\
\
    gl_FragColor = vec4( vec3( color, color * 0.5, sin( color + time / 3.0 ) * 0.75 ), 1.0 );\
\
}\0";

    GLuint ray_shader = glCreateShader(GL_COMPUTE_SHADER);
    glShaderSource(ray_shader, 1, &the_ray_shader_string, NULL);
    glCompileShader(ray_shader);

    GLuint ray_program = glCreateProgram();
    glAttachShader(ray_program, ray_shader);
    glLinkProgram(ray_program);


    int delta, leftToWait;

    int startTime, i = 0;

    while (++i && demoRunning)
    {
        startTime = SDL_GetTicks();

        SDL_PollEvent(&event);
        demoHandleInput(&event);

        glClear(GL_COLOR_BUFFER_BIT);

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, tex_output);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

        glUseProgram(ray_program);
        glDispatchCompute((GLuint)tex_w, (GLuint)tex_h, 1);

        glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);

        SDL_GL_SwapWindow(window);

        delta = SDL_GetTicks() - startTime;
        leftToWait = (16 - delta); // aim for 60 fps

        if (leftToWait > 0){
            SDL_Delay(leftToWait);
        }
    }

    SDL_DestroyWindow(window);
    SDL_Quit();

    return EXIT_SUCCES;
}

1 Ответ

2 голосов
/ 28 октября 2019

То, что вы называете вычислительным шейдером, на самом деле является фрагментным шейдером , чем вычислительным шейдером . gl_FragCoord - это встроенный входной фрагментный шейдер, а gl_FragColor - (устаревшая) выходная переменная фрагментного шейдера. Прикрепленный к шейдерному объекту GL_COMPUTE_SHADER, этот шейдер не сможет скомпилироваться.

Вы должны использовать gl_GlobalInvocationID, чтобы идентифицировать вызов, и вы должны использовать imageStore для записи текселя в выходное изображение (img_output). Например:

#version 460

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;
layout(local_size_x = 1, local_size_y = 1) in;
layout(rgba32f, binding = 0) uniform image2D img_output;

void main( void ) {

    vec2 position = vec2(gl_GlobalInvocationID.xy) / resolution.xy + mouse / 4.0;

    float color = 0.0;
    color += sin( position.x * cos( time / 15.0 ) * 80.0 ) + cos( position.y * cos( time / 15.0 ) * 10.0 );
    color += sin( position.y * sin( time / 10.0 ) * 40.0 ) + cos( position.x * sin( time / 25.0 ) * 40.0 );
    color += sin( position.x * sin( time /  5.0 ) * 10.0 ) + sin( position.y * sin( time / 35.0 ) * 80.0 );
    color *= sin( time / 10.0 ) * 0.5;

    vec4 pixel = vec4( vec3( color, color * 0.5, sin( color + time / 3.0 ) * 0.75 ), 1.0 );
    imageStore(img_output, ivec2(gl_GlobalInvocationID.xy), pixel);
}

Но обратите внимание, это не будет ничего рисовать в окне (кадровый буфер по умолчанию), целью компьютерного шейдера является изображение. Вычислительный шейдер просто устанавливает пиксель на изображении.
Если вы хотите «увидеть» изображение на дисплее, то вам нужно визуализировать квад с объектом текстуры или прикрепить текстуру к буферу кадров и «blit»"(glBlitFramebuffer) это к кадровому буферу по умолчанию.

...