2012-05-18 5 views
9

J'ai créé une classe qui rend les images vidéo (sur Mac) à un objet framebuffer personnalisé. En entrée, j'ai une texture YUV et j'ai créé avec succès un fragment shader qui prend en entrée 3 textures de rectangle (une pour les plans Y, U et V chacun, dont les données sont téléchargées par glTexSubImage2D en utilisant GL_TEXTURE_RECTANGLE_ARB, GL_LUMINANCE et GL_UNSIGNED_BYTE) , avant le rendu, j'ai mis les textures actives à trois unités de texture différentes (0, 1 et 2) et lier une texture pour chacune, et pour des raisons de performance, j'ai utilisé GL_APPLE_client_storage et GL_APPLE_texture_range. Puis je l'ai rendu en utilisant glUseProgram (myProg), glBegin (GL_QUADS) ... glEnd(). Cela a bien fonctionné, et j'ai obtenu le résultat attendu (mis à part un effet de scintillement, ce qui est dû au fait que j'ai utilisé deux contextes GL différents sur deux threads différents, et je suppose qu'ils se pénètrent l'un l'autre façon à un certain moment [c'est le sujet d'une autre question plus tard]). Quoi qu'il en soit, j'ai décidé d'améliorer encore mon code en ajoutant un vertex shader, de sorte que je puisse sauter le glBegin/glEnd - que je lis est obsolète et devrait être évité de toute façon.Rendu de texture rectangle avec GLSL

Alors comme étape suivante, je crée deux objets tampons, l'un pour les sommets et une pour les coordonnées de texture:

 const GLsizeiptr posSize = 4 * 4 * sizeof(GLfloat); 
     const GLfloat posData[] = 
     { 
      -1.0f, -1.0f, -1.0f, 1.0f, 
      1.0f, -1.0f, -1.0f, 1.0f, 
      1.0f, 1.0f, -1.0f, 1.0f, 
      -1.0f, 1.0f, -1.0f, 1.0f 
     }; 

     const GLsizeiptr texCoordSize = 4 * 2 * sizeof(GLfloat); 
     const GLfloat texCoordData[] = 
     { 
      0.0, 0.0, 
      1.0, 0.0, 
      1.0, 1.0, 
      0.0, 1.0 
     }; 

    glGenBuffers(1, &m_vertexBuffer); 
    glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer); 
    glBufferData(GL_ARRAY_BUFFER, posSize, posData, GL_STATIC_DRAW); 

    glGenBuffers(1, &m_texCoordBuffer); 
    glBindBuffer(GL_ARRAY_BUFFER, m_texCoordBuffer); 
    glBufferData(GL_ARRAY_BUFFER, texCoordSize, texCoordData, GL_STATIC_DRAW); 

Puis après le chargement des shaders je tente de récupérer les emplacements des attributs du sommet shader:

 m_attributeTexCoord = glGetAttribLocation(m_shaderProgram, "texCoord"); 
     m_attributePos = glGetAttribLocation(m_shaderProgram, "position"); 

qui me donne 0 pour texCoord et 1 pour la position, ce qui semble bien.

Après avoir obtenu les attributs que j'appelle également

 glEnableVertexAttribArray(m_attributePos); 
     glEnableVertexAttribArray(m_attributeTexCoord); 

(je fais qu'une seule fois, ou doit-il être fait avant chaque glVertexAttribPointer et glDrawArrays? Doit-il être fait par unité de texture? Ou ? alors que mon shader est activé avec glProgram Ou puis-je faire juste partout)

Après que j'ai changé le code de rendu pour remplacer le glBegin/glEnd:

 glActiveTexture(GL_TEXTURE0); 
     glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texID_Y); 

     glActiveTexture(GL_TEXTURE1); 
     glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texID_U); 

     glActiveTexture(GL_TEXTURE2); 
     glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texID_V); 

     glUseProgram(myShaderProgID); 

     // new method with shaders and buffers 
     glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer); 
     glVertexAttribPointer(m_attributePos, 4, GL_FLOAT, GL_FALSE, 0, NULL); 
     glBindBuffer(GL_ARRAY_BUFFER, m_texCoordBuffer); 
     glVertexAttribPointer(m_attributeTexCoord, 2, GL_FLOAT, GL_FALSE, 0, NULL); 
     glDrawArrays(GL_QUADS, 0, 4); 

     glUseProgram(0); 

Mais depuis que j'ai changé le code, je n'ai toujours qu'un écran noir comme résultat. Donc, je suppose qu'il me manque quelques étapes simples, peut-être un peu de glenable/glDisable ou de régler certaines choses correctement - mais mais comme je l'ai dit je suis nouveau à cela, donc je n'ai pas vraiment eu une idée. À titre de référence, voici le vertex shader:

#version 110 
attribute vec2 texCoord; 
attribute vec4 position; 

// the tex coords for the fragment shader 
varying vec2 texCoordY; 
varying vec2 texCoordUV; 

//the shader entry point is the main method 
void main() 
{ 
    texCoordY = texCoord; 
    texCoordUV = texCoordY * 0.5; // U and V are only half the size of Y texture 
    gl_Position = gl_ModelViewProjectionMatrix * position; 
} 

Je pense que je manque quelque chose évidente ici, ou tout simplement ne pas avoir assez profonde compréhension des processus en cours ici encore. J'ai aussi essayé d'utiliser OpenGLShaderBuilder, ce qui m'a aidé à obtenir le code original pour le fragment shader (c'est pourquoi je ne l'ai pas posté ici), mais depuis l'ajout du vertex shader il ne me donne pas de sortie non plus (se demandait comment il pourrait savoir comment produire la sortie, s'il ne connaît pas les attributs position/texCoord de toute façon?)

+1

Pour les rectangles de texture, les coordonnées ne sont pas censées être normalisées, mais vous semblez passer des coordonnées normalisées. – harold

+0

Oh donc pour le texCoordData [] au lieu de 0.0, 1.0 etc. Je passe par exemple 1920.0, 1080.0 (c'est-à-dire la taille réelle de la trame vidéo)? – Bjoern

+0

L'écran noir de la mort est si commun dans les graphiques.Je présume que vous avez essayé de changer la couleur claire juste pour vous assurer que vous dessinez réellement quelque chose? Si vous êtes *, alors c'est un problème de shader, sinon, problème de tableau de vertex. – imallett

Répondre

2

Je n'ai pas étudié de près chaque ligne, mais je pense que votre logique est la plupart du temps correcte. Ce que je vois manquant est glEnableVertexAttribArray. Vous devez activer les deux attributs de sommet avant l'appel de glDrawArrays.

+0

Merci pour votre réponse rapide, et désolé à ce sujet, mais je le fais déjà, mais j'ai oublié de le mentionner dans le message ci-dessus (éditera maintenant), et non, cela ne m'a pas vraiment aidé – Bjoern

+0

Ok, car il tourne J'ai appelé glEnableVertexAttribArray au mauvais endroit. Avant que je l'appelle après avoir obtenu les emplacements des attributs, alors maintenant je l'ai changé pour être appelé sur chaque image, et cela fonctionne finalement. Mais je ne comprends pas pourquoi j'ai besoin d'appeler ça chaque image, je pensais qu'elle se souviendrait que c'était activé? – Bjoern

+0

@Bjoern il devrait s'en souvenir sans avoir à être appelé à chaque image, pourriez-vous le désactiver quelque part? – Tim