2017-09-03 2 views
0

Ich versuche, eine Kombination von SFML und OpenGL für ein Projekt zu verwenden, aber ich habe Probleme beim Rendern auf eine sf::RenderTexture. Genauer gesagt, wenn ich versuche zu zeichnen, während der RenderTexture aktiv ist, stürze ich ab. (Sieht aus wie eine Nullzeiger-Dereferenz in glDrawElements.)Rendering OpenGL Mesh zu SFML RenderTexture

Rendern direkt in das Fenster funktioniert gut. Und wenn ich manuell einen Framebuffer durch OpenGL selbst erstelle, funktioniert das auch gut. Aber ich würde gerne in der Lage sein, RenderTexture wenn möglich zu verwenden, um eine Menge Code zu vereinfachen.

Ich kann etwas Dummes tun, aber ich bin noch neu bei OpenGL, also bin ich mir nicht sicher. (Besonders bei der Mischung aus SFML und OpenGL scheint es so, als könnten viele Dinge kaputt gehen, wenn der Kontextwechsel nicht korrekt funktioniert.) Ich sehe keine Warnungen von OpenGL oder SFML.

Nachfolgend gibt das Problem ich sehe (Windows 10, Visual Studio 2017, OpenGL 4.5, GLEW 2.1.0, SFML 2.4.0):

#include <iostream> 
#include <string> 
#include <SFML/Window.hpp> 
#include <SFML/Graphics.hpp> 
#define GL_GLEXT_PROTOTYPES 
#include <GL/glew.h> 
#include <SFML/OpenGL.hpp> 

GLenum glCheckError_(const char *file, int line) 
{ 
    GLenum errorCode; 
    while ((errorCode = glGetError()) != GL_NO_ERROR) 
    { 
     std::string error; 
     switch (errorCode) 
     { 
     case GL_INVALID_ENUM:     error = "INVALID_ENUM"; break; 
     case GL_INVALID_VALUE:     error = "INVALID_VALUE"; break; 
     case GL_INVALID_OPERATION:    error = "INVALID_OPERATION"; break; 
     case GL_STACK_OVERFLOW:    error = "STACK_OVERFLOW"; break; 
     case GL_STACK_UNDERFLOW:    error = "STACK_UNDERFLOW"; break; 
     case GL_OUT_OF_MEMORY:     error = "OUT_OF_MEMORY"; break; 
     case GL_INVALID_FRAMEBUFFER_OPERATION: error = "INVALID_FRAMEBUFFER_OPERATION"; break; 
     } 
     std::cerr << error << " | " << file << " (" << line << ")" << std::endl; 
    } 
    return errorCode; 
} 
#define glCheckError() glCheckError_(__FILE__, __LINE__) 

int main() 
{ 
    sf::RenderWindow window(sf::VideoMode(800, 600, 32), "test"); 
    glewInit(); 
    std::cout << "Using OpenGL " << window.getSettings().majorVersion << "." << window.getSettings().minorVersion << std::endl; 
    //std::cout << "Available GL extensions: " << glGetString(GL_EXTENSIONS) << std::endl; 

    sf::Shader shader; 
    { // Shader 
     const char* vs = R"(
      #version 330 core 
      layout (location = 0) in vec3 pos; 

      void main() 
      { 
       gl_Position = vec4(pos, 1.0); 
      } 
     )"; 
     const char* fs = R"(
      #version 330 core 
      out vec4 color; 

      void main() 
      { 
       color = vec4(0.3, 0.8, 0.2, 1.0); 
      } 
     )"; 
     shader.loadFromMemory(vs, fs); 
    } 

    unsigned int vao; 
    { // Mesh 
     float vertices[] = { 
      0.3f, 0.5f, 1.0f, // top right 
      0.5f, -0.5f, -0.5f, // bottom right 
      -0.5f, -0.5f, -1.0f, // bottom left 
      -0.3f, 0.5f, 0.5f, // top left 
     }; 
     unsigned int indices[] = { 
      0, 3, 1, // first triangle 
      1, 3, 2, // second triangle 
     }; 
     unsigned int vbo, ebo; 
     glGenVertexArrays(1, &vao); 
     glCheckError(); 
     glGenBuffers(1, &vbo); 
     glCheckError(); 
     glGenBuffers(1, &ebo); 
     glCheckError(); 
     glBindVertexArray(vao); 
     glCheckError(); 
     glBindBuffer(GL_ARRAY_BUFFER, vbo); 
     glCheckError(); 

     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 
     glCheckError(); 

     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 
     glCheckError(); 
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); 
     glCheckError(); 

     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); 
     glCheckError(); 

     glEnableVertexAttribArray(0); 
     glCheckError(); 
     glBindBuffer(GL_ARRAY_BUFFER, 0); 
     glCheckError(); 
     glBindVertexArray(0); 
     glCheckError(); 
    } 

    sf::RenderTexture texture; 
    sf::Sprite sprite; 
    { // Render Texture 
     if (!texture.create(800, 600, true)) { 
      std::cerr << "Failed to create RenderTexture" << std::endl; 
     } 
     sprite.setTexture(texture.getTexture()); 
    } 

    int frame = 0; 
    while (window.isOpen()) 
    { 
     ++frame; 
     sf::Event event; 
     while (window.pollEvent(event)) 
     { 
      if (event.type == sf::Event::Closed) 
      { 
       window.close(); 
      } 
     } 

     window.clear(); 
     if (frame > 1) 
     { 
      window.popGLStates(); 
     } 

     { // Render to screen 
      sf::Shader::bind(&shader); 
      glBindVertexArray(vao); 
      glCheckError(); 

      glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); 
      glCheckError(); 

      glBindVertexArray(0); 
      glCheckError(); 
      sf::Shader::bind(nullptr); 
     } 

     window.pushGLStates(); 
     window.display(); 

     // Press space to continue... 
     bool waiting = true; 
     while (waiting) { 
      while (window.pollEvent(event)) 
      { 
       if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Space) 
       { 
        waiting = false; 
        break; 
       } 
      } 
     } 

     window.clear(); 
     if (frame > 1) 
     { 
      window.popGLStates(); 
     } 

     { // Render to texture 
      sf::Shader::bind(&shader); 
      glBindVertexArray(vao); 
      glCheckError(); 

      texture.pushGLStates(); 
      if (!texture.setActive(true)) { // TODO Setting the texture as active is causing me to segfault, messing up my state somehow 
       std::cerr << "Failed to activate RenderTexture" << std::endl; 
      } 
      texture.clear(); 
      texture.popGLStates(); 

      glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // <-- Crashes here! 
      glCheckError(); 

      texture.pushGLStates(); 
      texture.display(); 
      if (!texture.setActive(false)) { 
       std::cerr << "Failed to deactivate RenderTexture" << std::endl; 
      } 
      texture.popGLStates(); 

      glBindVertexArray(0); 
      glCheckError(); 
      sf::Shader::bind(nullptr); 
     } 

     window.pushGLStates(); 
     window.draw(sprite); 
     window.display(); 
    } 
}; 

Hat Ideen jemand?

EDIT: Nun, ich habe den Absturz Teil gelöst. sf::RenderTexture s haben ihren eigenen GL-Kontext, und ich denke, Sie können Daten zwischen Kontexten nicht wiederverwenden. Also musste ich zuerst die Textur generieren und dann texture.setActive() verwenden, bevor ich den Shader und Mesh erzeuge. Auf diese Weise hat der Kontext diese Objekte verfügbar.

Jetzt bekomme ich nur einen schwarzen Bildschirm. Ich bin in der Lage, eine neue sf::RectangleShape zu demselben RenderTexture zu zeichnen, aber mein GL-Netz scheint nicht zu zeichnen. Noch ... Untersuchung

Falls jemand das gleiche Problem hat, sind hier Schnipsel von dem, was ich ändern musste:

// --- initialization --- 

// Generate the texture first so its context is available 
sf::RenderTexture texture; 
sf::Sprite sprite; 
{ // Render Texture 
    if (!texture.create(800, 600, true)) { 
     std::cerr << "Failed to create RenderTexture" << std::endl; 
    } 
    sprite.setTexture(texture.getTexture()); 
} 

// Generate the rest of the data within the texture's context 
sf::Shader shader; 
{ // Shader 
    if (!texture.setActive(true)) { 
     std::cerr << "Failed to activate RenderTexture" << std::endl; 
    } 
    shader.loadFromMemory(vs, fs); 
    if (!texture.setActive(false)) { 
     std::cerr << "Failed to deactivate RenderTexture" << std::endl; 
    } 
} 

unsigned int vao; 
{ // Mesh 
    if (!texture.setActive(true)) { 
     std::cerr << "Failed to activate RenderTexture" << std::endl; 
    } 
    unsigned int vbo, ebo; 
    glGenVertexArrays(1, &vao); 
    glCheckError(); 
    glGenBuffers(1, &vbo); 
    glCheckError(); 

    // ... 

    glBindBuffer(GL_ARRAY_BUFFER, 0); 
    glCheckError(); 
    glBindVertexArray(0); 
    glCheckError(); 
    if (!texture.setActive(false)) { 
     std::cerr << "Failed to deactivate RenderTexture" << std::endl; 
    } 
} 

// --- drawing --- 

{ // Render to texture 
    // Make sure we use the appropriate context for all drawing to texture 
    if (!texture.setActive(true)) { 
     std::cerr << "Failed to activate RenderTexture" << std::endl; 
    } 
    texture.clear(); 
    sf::Shader::bind(&shader); 

    glBindVertexArray(vao); 
    glCheckError(); 

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // TODO rendering nothing here... 
    glCheckError(); 

    glBindVertexArray(0); 
    glCheckError(); 
    sf::Shader::bind(nullptr); 

    // Drawing to the texture through SFML works fine 
    texture.pushGLStates(); 
    sf::RectangleShape rect(sf::Vector2f(20, 20)); 
    rect.setFillColor(sf::Color::Cyan); 
    texture.draw(rect); 
    texture.popGLStates(); 

    texture.display(); 
    if (!texture.setActive(false)) { 
     std::cerr << "Failed to deactivate RenderTexture" << std::endl; 
    } 
} 

if (!window.setActive(true)) { 
    std::cerr << "Failed to activate window" << std::endl; 
} 
window.pushGLStates(); 
window.draw(sprite); 
window.display(); 

EDIT 2: Zeichnung Probleme gelöst, meine Antwort sehen.

Antwort

0

Ich fand die Antwort! Alle durch „Groogy“ in diesem Thema: https://en.sfml-dev.org/forums/index.php?topic=7446.0

ich früher, dass Faden abgeschöpft hatte, die mich dazu veranlasst texture.setView(texture.getDefaultView()); hinzuzufügen, wenn die RenderTexture zu schaffen. Allerdings war das nicht genug, ich musste stattdessen glViewport mit der Textur gebunden aufrufen. (. Ich nahm an, ist das, was sf::View unter die Decke tun würde, aber anscheinend ist das nicht der Fall ist)

Also meine RenderTexture Schöpfung sieht nun wie folgt aus:

sf::RenderTexture texture; 
sf::Sprite sprite; 
{ // Render Texture 
    if (!texture.create(800, 600, true)) { 
     std::cerr << "Failed to create RenderTexture" << std::endl; 
    } 
    if (!texture.setActive(true)) { 
     std::cerr << "Failed to activate texture" << std::endl; 
    } 
    sprite.setTexture(texture.getTexture()); 

    glViewport(0, 0, 800, 600); // <-- Required 
    glCheckError(); 

    if (!texture.setActive(false)) { 
     std::cerr << "Failed to deactivate texture" << std::endl; 
    } 
} 

Und jetzt die Dinge funktionieren.