2016-09-30 4 views
1

Ich habe ein Programm mit zwei Texturen: eine aus einem Video und eine aus einem Bild.OpenGL Pass Textur zum Programm: einmal oder bei jedem Rendering?

Muss ich die Bildtextur bei jedem Rendering an das Programm übergeben, oder kann ich es nur einmal machen? dh kann ich tun

glActiveTexture(GLenum(GL_TEXTURE1)) 
glBindTexture(GLenum(GL_TEXTURE_2D), texture.id) 
glUniform1i(textureLocation, 1) 

nur einmal? Ich glaubte das, aber in meinem Experiment funktioniert das ok, wenn keine Videotextur involviert ist, aber sobald ich die Videotextur anfüge, die ich bei jedem Renderingpass anhefte (seit es sich ändert), ist der einzige Weg das Bild zu bekommen um den obigen Code bei jedem Wiedergabebild auszuführen.

Antwort

2

Lassen Sie uns sezieren, was Sie tun, einschließlich einiger unnötiger Sachen, und was der GL tut.

Zunächst einmal ist keiner der C-Style-Umwandlungen, die Sie in Ihrem Code tun, notwendig. Verwenden Sie einfach GL_TEXTURE_2D und so weiter statt GLenum(GL_TEXTURE_2D).

glActiveTexture(GL_TEXTURE0 + i), wo i im Bereich [0, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1] wählt die gegenwärtig aktive Textureinheit. Befehle, die den Status der Textureinheit ändern, wirken sich auf die Einheit i aus, solange Sie glActiveTexture nicht mit einer anderen gültigen Einheiten-ID aufrufen.

Sobald Sie glBindTexture(target, name) mit der aktuellen aktiven Textureinheit nennen i wird der Zustand der Textureinheit geändert name für die angegebenen target zu beziehen, wenn es mit dem entsprechenden Sampler in einem Shader-Abtastung (dh name könnte gebunden sein zu TEXTURE_2D und das entsprechende Beispiel müsste ein sampler2D sein). Sie können nur ein Texturobjekt an ein bestimmtes Ziel für die gerade aktive Textureinheit binden. Wenn Sie also zwei 2D-Texturen in Ihrem Shader testen möchten, müssen Sie zwei Textureinheiten verwenden.

Aus dem oben genannten sollte es offensichtlich sein, was tut.

Also, wenn Sie zwei 2D-Texturen haben Sie in einem Shader probieren müssen, müssen Sie zwei Textureinheiten und zwei Sampler, die jeweils eine bestimmte Einheit zuzurechnen sind:

GLuint regularTextureName = 0; 
GLunit videoTextureName = 0; 

GLint regularTextureSamplerLocation = ...; 
GLint videoTextureSamplerLocation = ...; 

GLenum regularTextureUnit = 0; 
GLenum videoTextureUnit = 1; 

// setup texture objects and shaders ... 

// make successfully linked shader program current and query 
// locations, or better yet, assign locations explicitly in 
// the shader (see below) ... 

glActiveTexture(GL_TEXTURE0 + regularTextureUnit); 
glBindTexture(GL_TEXTURE_2D, regularTextureName); 
glUniform(regularTextureSamplerLocation, regularTextureUnit); 

glActiveTexture(GL_TEXTURE0 + videoTextureUnit); 
glBindTexture(GL_TEXTURE_2D, videoTextureName); 
glUniform(videoTextureSampleLocation, videoTextureUnit); 

Ihr Fragment-Shader, wo ich davon ausgehen, Sie werden die Probenahme durchführen, müssten die entsprechenden Probenehmer haben:

layout(binding = 0) uniform sampler2D regularTextureSampler; 
layout(binding = 1) uniform sampler2D videoTextureSampler; 

Und das ist es.Wenn beide Texturobjekte, die an die obigen Einheiten gebunden sind, korrekt eingerichtet sind, ist es egal, ob sich der Inhalt der Textur dynamisch vor jedem Fragment-Shader-Aufruf ändert - es gibt zahlreiche Szenarien, in denen dies üblich ist, z. Deferred Rendering oder ein anderer Render-to-Texture-Algorithmus, damit Sie mit einer Videotextur nicht gerade neue Wege gehen.

Zur Frage, wie oft Sie dies tun müssen: Sie müssen es tun, wenn Sie es tun müssen - ändern Sie nicht den Zustand, der nicht geändert werden muss. Wenn Sie die Bindungen der entsprechenden Textureinheit nie ändern, müssen Sie die Textur nicht neu binden. Richte sie einmal richtig ein und lass sie in Ruhe.

Dasselbe gilt für die Bindungen des Samplers: Wenn Sie keine anderen Texturobjekte mit Ihrem Shader testen, müssen Sie den Status des Shader-Programms überhaupt nicht ändern. Richte es einmal auf und lass es in Ruhe.

Kurz gesagt: Zustand nicht ändern, wenn nicht müssen.

EDIT: Ich bin nicht ganz sicher, ob dies der Fall ist oder nicht, aber wenn Sie teh gleichen Shader mit einem Sampler für beiden Texturen in getrennten Shader Anrufungen mit sind, würden Sie ändern müssen etwas, aber was denken sie, es ist so einfach wie im Stich gelassen der Sampler auf eine andere Textureinheit beziehen:

// same texture unit setup as before 
// shader program is current 

while (rendering) 
{ 
    glUniform(samplerLocation, regularTextureUnit); 
    // draw call sampling the regular texture 

    glUniform(samplerLocation, videoTextureUnit); 
    // draw call sampling teh video texture 
} 
+0

Dieses Aussehen ausgezeichnet, danke! – Guig

+0

(Ich brauche die C-artigen Umwandlungen, weil ich Swift schreibe und der Compiler sich beschwert, wenn ich das nicht tue) Ich weiß, dass es dumm ist. – Guig

+0

@Guig: Eigentlich mein schlechtes für die Annahme, du schreibst C oder C++ Code Dort. Solange du nicht Objective-C verwendest ...;) – thokra

0

Sie sollten die Textur vor jedem Zeichnen binden. Sie müssen den Standort nur einmal festlegen. Sie können auch Layout (Binding = 1) in Ihrem Shader-Code dafür machen. Die Standortuniform bleibt beim Programm. Die Texturbindung ist ein globaler GL-Zustand. Seien Sie auch vorsichtig bei ActiveTexture: Es ist ein globaler GL-Status.

Gute Praxis wäre:

  • Auf der Programmerstellung, einmal gesetzt Textur Lage (Uniform)
  • Auf Unentschieden: SetActive (i), Bind (i), Zeichnen, SetActive (i) Bind (0), SetActive (0)

Dann optimieren Sie später für redundante Aufrufe.

+0

Ihre Erklärung widerspricht mit itself.You müssen nicht die Textur vor jeder Ziehung Anruf binden, denn das ist ein globaler Zustand ist .Sie MÜSSEN mindestens einmal pro Programm einen einheitlichen Speicherort angeben, der von dieser Textur abgetastet werden muss. –

+0

@MichaelIvanov: Wie würdest du es besser erklären? Ich ging mit der begründeten Annahme, dass es mehr als ein Remis gibt, jede mit unterschiedlichen Texturen. Ich sehe keinen Widerspruch? Ich habe versucht, darauf hinzuweisen, dass der Ort pro Programm und verbindlich global ist. Und die einfachste (nicht die effizienteste) Art, mit dem globalen Zustand umzugehen, ist, sie einfach einzustellen. – starmole

+0

Ja, richtig, jetzt erscheint es mir vernünftiger;) Sie sagen: "Wenn wir bei jedem Zeichenaufruf eine andere Textur binden müssen, binden wir erneut, aber die Orte können nur einmal pro Programm gesetzt werden", richtig? –