2014-12-15 16 views
5

Ich habe implementiert CPU-Code, der eine projizierte Textur in eine größere Textur auf einem 3D-Objekt, "Abziehbild Backen" kopiert, wenn Sie so wollen, aber jetzt muss ich es auf der GPU implementieren. Um dies zu tun, hoffe ich, Compute Shader zu verwenden, da es ziemlich schwierig ist, einen FBO in meinem aktuellen Setup hinzuzufügen. https://stackoverflow.com/a/27124029/2579996Compute Shader schreibe auf Textur

Die Textur, die geschrieben wird:

Example image from my current implementation

Diese Frage ist mehr darüber, wie Shadern Compute zu verwenden, sondern für alle Interessierten, die Idee auf eine Antwort basiert ich von Benutzer jozxyqk bekam, hier zu sehen -zu ist in meinem Code _texture genannt, während das projizierte ein _textureProj

Einfache Compute Shader

ist
const char *csSrc[] = { 
    "#version 440\n", 
    "layout (binding = 0, rgba32f) uniform image2D destTex;\ 
    layout (local_size_x = 16, local_size_y = 16) in;\ 
    void main() {\ 
      ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);\ 
      imageStore(destTex, storePos, vec4(0.0,0.0,1.0,1.0));\ 
    }" 
}; 

Wie Sie sehen, möchte ich derzeit nur die Textur auf eine beliebige (blaue) Farbe aktualisiert haben.

Update-Funktion

void updateTex(){ 
    glUseProgram(_computeShader); 
    const GLint location = glGetUniformLocation(_computeShader, "destTex"); 
    if (location == -1){ 
     printf("Could not locate uniform location for texture in CS"); 
    } 
    // bind texture 
    glUniform1i(location, 0); 
    glBindImageTexture(0, *_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); 
    // ^second param returns the GLint id - that im sure of. 

    glDispatchCompute(_texture->width()/16, _texture->height()/16, 1); 
    glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); 

    glUseProgram(0); 
    printOpenGLError(); // reports no errors. 
} 

Problem Wenn ich die updateTex() außerhalb meines Hauptprogramm-Objekt aufrufen siehe i Null Wirkung, während, wenn ich sie in ihrem Umfang nennen etwa so:

glUseProgram(_id); // vert, frag shader pipe 
    updateTex(); 
    // Pass uniforms to shader 
    // bind _textureProj & _texture (latter is the one im trying to update) 
glUseProgram(0); 

Dann beim Rendern sehe ich das:

FRAGE: Ich stelle fest, dass die Update-Methode innerhalb des Haupt-Programmobjekt Umfang Einstellung ist nicht der richtige Weg, es zu tun, aber es ist der einzige Weg, um alle visuellen Ergebnisse zu erhalten. Es scheint mir, dass, was passiert ist, dass es den fragmentshader ziemlich beseitigt und zu screenspace ...

Was kann ich tun, damit dieses richtig funktioniert? (Mein Hauptaugenmerk ist in der Lage zu schreiben alles zu der Textur & Update)

Bitte lassen Sie mich wissen, wenn mehr Code Buchung benötigt.

+0

Ich bin nicht sicher, was Sie mit "Hauptprogramm Objektumfang" meinen. Was macht '_programObject-> activate();' do? – GuyRT

+0

Ist Ihr "Hauptprogrammumfang" auf einem separaten Thread? OpenGL funktioniert nicht richtig/überhaupt nicht, wenn Sie zwischen Threads telefonieren. –

+0

@GuyRT - Oh, tut mir leid, vielleicht habe ich dort den falschen Begriff benutzt. Was _programObject-> activate() im Wesentlichen ist, dass es glUseProgram (id) aufruft, wo id GLint ist, werde ich meine Frage bearbeiten. – mike

Antwort

1

Ich glaube in diesem Fall ein FBO wäre einfacher und schneller, und würde stattdessen empfehlen. Aber die Frage selbst ist immer noch recht gültig.

Ich bin überrascht, eine Kugel zu sehen, vorausgesetzt, Sie schreiben blau auf die gesamte Textur (abzüglich aller Kantenbits, wenn die Texturgröße kein Vielfaches von 16 ist). Ich denke, das ist Code aus anderen Quellen.

Wie auch immer, es scheint, dass Ihr Hauptproblem in der Lage ist, in die Textur von einem Compute Shader außerhalb des Setup-Codes für das normale Rendern zu schreiben. Ich vermute, das hängt damit zusammen, wie Sie Ihre destTex Bild binden.Ich bin nicht sicher, was Ihre TexUnit und activate Methoden tun, aber eine GL Textur zu einer Bildeinheit zu binden, dies tun:

int imageUnitIndex = 0; //something unique 
int uniformLocation = glGetUniformLocation(...); 
glUniform1i(uniformLocation, imageUnitIndex); //program must be active 
glBindImageTexture(imageUnitIndex, textureHandle, ...); 

siehe:

Schließlich, wie Sie image2D verwenden, so ist GL_SHADER_IMAGE_ACCESS_BARRIER_BIT die Barriere zu verwenden. GL_SHADER_STORAGE_BARRIER_BIT ist für storage buffer objects.

+0

Vielen Dank für eine schnelle Antwort. Ich habe tatsächlich versucht, es explizit zu tun (bearbeitet meinen Beitrag zu dem, was Sie vorschlagen). Ich war nicht ganz sicher über das Format, aber beim Überprüfen, seine GL_RGB, die scheint nicht von der Load/Store-Methode unterstützt wird. Also, da ich mit GL_RGBA32F keinen Fehler erhalte, gehe ich davon aus, dass es der richtige Weg ist. Außerdem sehen Sie jetzt, dass ich explizit mit dem Layout-Qualifikationsmerkmal an 0 gebunden bin - funktioniert immer noch nicht. Ich vermute, dass es entweder mit dem Format zu tun hat (sollte es sein), oder es gibt einen fehlenden Schritt, wie die Textur geladen ist oder so. – mike

+0

Fortsetzung: zu sehen, es sieht aus wie ich eine 'Lehrbuch' Implementierung gemacht habe, so werde ich versuchen, wieder mit FBO (und posten Fragen zu dem im anderen Thread), aber ich werde diesen Code behalten, kommentiert. Lassen Sie mich wissen, ob ich noch mehr Code hier posten sollte, gerade jetzt bin ich ein bisschen ahnungslos, warum es nicht tut, was es soll. Vielleicht lasse ich den Code weg, lass es mich wissen (und danke!). – mike

+0

Oh, und noch etwas: Der Grund, warum wir die "blaue" Sphäre sehen, ist nur, weil ich die 'updateTex()' Methode innerhalb der 'glUseProgram()' Aufrufe einfüge - dh - es sieht so aus, als ob sie den Fragment Shader entfernt. Ich weiß jetzt, dass die Farbe auf dem projizierten Vert Shader 'vec4 position' basiert, weshalb die Blaulaufzeit und die Farbe je nach Projektorwinkel und Oberfläche geändert wird - völlig falsch, aber das ist die einzige Möglichkeit, die ich sehe mit dem Compute Shader ... :( – mike