Texturspeicher über Shader aktualisieren?

8

Was der Titel sagt. Ist es möglich, eine Textur über einen glsl-Shader zu aktualisieren? Etwas wie :

//Read
vec4 Pixel = texture2D(TextureID,gl_TexCoord[TextureIndex].st);

//Write to texture memory ?
vec4 NewPixel = Pixel + vec4(0.0,0.0,0.0,AlphaPatch);

// ?? How to write back to texture memory ??
texture2D(TextureID,gl_TexCoord[TextureIndex].st) = NewPixel; 

??

user1010005
quelle

Antworten:

6

Sie möchten eine Textur an einen Shader binden und dann in diese Textur rendern. Ich könnte kilometerlange Dokumentationsspezifikationen von OpenGL durchspucken, aber ich werde das Gefühl geben, das mir mein Bauch gibt:

Ich denke nicht, dass das möglich ist.

Was ich jedoch weiß, ist möglich, dass Sie ein Frame Buffer Object (FBO) erstellen und darauf rendern. Zunächst müssen Sie einen FBO generieren und ihm eine Textur mit derselben Größe wie die zu aktualisierende hinzufügen.

GLuint fbo_handle, fbo_texture_handle;

GLuint texture_width = GetTextureWidth();
GLuint texture_height = GetTextureWidth();

// generate texture

glGenTextures(1, &fbo_texture_handle);
glBindTexture(GL_TEXTURE_2D, fbo_texture_handle);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texture_width, texture_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);

// generate framebuffer

glGenFrameBuffers(1, &fbo_handle);
glBindFrameBuffer(GL_FRAMEBUFFER, fbo_handle);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_texture_handle, 0);

GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
{
    LOG_ERROR("Could not validate framebuffer);
}

glBindFramebuffer(GL_FRAMEBUFFER, 0);

Wenn Sie Ihre Textur aktualisieren möchten, müssen Sie die folgenden Schritte ausführen.

Zuerst fügen Sie den FBO hinzu:

glBindFramebuffer(GL_FRAMEBUFFER, fbo_handle);

glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0, 0, texture_width, texture_height);

Jetzt können Sie ein Vollbild-Quad mit einem Shader rendern, der die aktualisierte Farbe ausgibt:

vec4 frag_texture = texture2D(TextureID, gl_TexCoord[TextureIndex].st);

vec4 frag_updated = frag_texture + vec4(0.0, 0.0, 0.0, AlphaPatch);

gl_FragData[0] = frag_updated;

Und dann müssen Sie den resultierenden Framebuffer in die ursprüngliche Textur kopieren.

glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_handle);
glBindTexture(GL_TEXTURE_2D, original_texture_handle);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texture_width, texture_height);

glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);

glPopAttrib();

Sie sollten jedoch Folgendes berücksichtigen:

  • Wie oft aktualisieren Sie diese Textur?
  • Wenn Sie es nicht bei jedem Frame aktualisieren müssen, ist diese Methode die Geschwindigkeitsstrafe wert?
  • Können Sie mehrere Versionen dieser Textur generieren und zwischen ihnen wechseln?
  • Gibt es einen anderen Weg, um den gleichen Effekt zu erzielen?
Ritter666
quelle
Wow, vielen Dank für die Hilfe! Und um Ihre Fragen zu beantworten: 1. Ich habe eine spezielle Textur für meinen Helden, die ich jedes Mal aktualisieren muss, wenn eine Kollision auftritt (mit Blutflecken und anderen Dingen). 2. Aufgrund der Art des Spiels wirst du ständig getroffen oder berührst Dinge voller Schmutz (Schlamm), so dass ich diese Textur sehr häufig aktualisieren muss ... 3. So mache ich es jetzt und bin nicht zufrieden damit es (ich brauche dynamische Textur Patching) 4. Weiß nicht: o
user1010005
4
Aha! Nun, das hilft bei der Feinabstimmung meiner Antwort. Was Sie wahrscheinlich suchen, ist Multi-Texturierung. Sie haben eine Textur für Ihren Spielcharakter und Sie haben eine Textur, die Schmutz und Blut und so weiter zeigt. In einem Shader können Sie sie kombinieren, um den gewünschten Effekt zu erzielen. Dies ist viel billiger als das kontinuierliche Rendern in ein Bildpufferobjekt und das Kopieren des Ergebnisses in eine Textur.
Knight666
Nochmals vielen Dank. Ich bin nicht ganz sicher, was Sie mit Multi-Texturierung meinen, aber ich werde versuchen, auf Stackexchange zu suchen :))
user1010005
4

Wenn Ihre Hardware dies unterstützt, können Sie mit der Erweiterung GL_ARB_shader_image_load_store in eine Textur schreiben.

elFarto
quelle
1
Ich kann Ihnen jetzt sagen, dass meine NVIDIA GeForce GTS 250 OpenGL 3.3.0 unterstützt, aber nicht GL_EXT_shader_image_load_store. Das heißt, Ihre Antwort ist wahrscheinlich richtig, aber auf dem Gebiet noch nicht praktikabel. Saugt. :(
Knight666
1
Ja, es sieht so aus, als ob Sie eine GeForce 400-Serie oder höher für die Unterstützung benötigen (es ist eine GL4 / DX11-Funktion).
ElFarto