Plusieurs textures dans GLSL - une seule fonctionne

Mon problème est d'obtenir plus d'une texture accessible dans un shader GLSL. Voici ce que je fais:

Shader:

uniform sampler2D sampler0;
uniform sampler2D sampler1;
uniform float blend;
void main( void )
{
    vec2 coords = gl_TexCoord[0];
    vec4 col = texture2D(sampler0, coords);
    vec4 col2 = texture2D(sampler1, coords);
    if (blend > 0.5){
        gl_FragColor = col;
    } else {
        gl_FragColor = col2;
    }
};

Donc, je choisis simplement entre les deux valeurs de couleur basées sur une variable uniforme. Assez Simple (c'est un test), mais au lieu du comportement attendu, je reçois tout noir quand blend .

Code OpenGL:

m_sampler0location = m_shader.FindUniform("sampler0");
m_sampler1location = m_shader.FindUniform("sampler1");
m_blendlocation = m_shader.FindUniform("blend");

glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
m_extensions.glUniform1iARB(m_sampler0location, 0);
glBindTexture(GL_TEXTURE_2D, Texture0.Handle);  
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
m_extensions.glUniform1iARB(m_sampler1location, 1);
glBindTexture(GL_TEXTURE_2D, Texture1.Handle);
glBegin(GL_QUADS);
    //lower left
    glTexCoord2f(0, 0);
    glVertex2f(-1.0, -1.0);
    //upper left
    glTexCoord2f(0, maxCoords0.t);
    glVertex2f(-1.0, 1.0);
    //upper right
    glTexCoord2f(maxCoords0.s, maxCoords0.t);
    glVertex2f(1.0, 1.0);
    //lower right
    glTexCoord2f(maxCoords0.s, 0);
    glVertex2f(1.0, -1.0);
glEnd()

Le shader est compilé et lié avant tout cela. Tous les contrôles de santé mentale dans ce processus indiquent que ça va OK. Comme je l'ai dit, la valeur de col dans le programme shader reflète des fragments d'une texture; la valeur de col2 est noire. La texture affichée est la dernière texture active-si je change le dernier glBindTexture pour lier Texture0.Handle, la texture change. fixé selon la réponse de Bahbar.

En l'état, la scène rend tout noir, même si j'ajoute quelque chose comme gl_FragColor.r = blend; comme dernière ligne du shader. Mais, si je commente l'appel glActiveTexture(GL_TEXTURE1);, le shader fonctionne à nouveau, et la même texture apparaît dans sampler0 et sampler1.

Ce qui se passe? La ligne en question, glActiveTexture(GL_TEXTURE1);, semble fonctionner très bien, comme en témoigne une ultérieure glGetIntegerv(GL_ACTIVE_TEXTURE, &anint). Pourquoi ça casse tout si horriblement? J'ai déjà essayé de mettre à niveau mes pilotes d'affichage.

21
demandé sur genpfault 2010-08-25 22:54:59

5 réponses

Voici un exemple basique de GLUT (écrit sur OS X, adaptez au besoin) qui génère deux textures en damier, charge un shader avec deux échantillonneurs et les combine en les teintant chacune (une Rouge, une bleue) et en les mélangeant. Voyez si cela fonctionne pour vous:

#include <stdio.h>
#include <stdlib.h>

#include <GLUT/glut.h>
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>

#define kTextureDim 64

GLuint t1;
GLuint t2;

/* adapted from the red book */
GLuint makeCheckTex() {
    GLubyte image[kTextureDim][kTextureDim][4]; // RGBA storage

    for (int i = 0; i < kTextureDim; i++) {
        for (int j = 0; j < kTextureDim; j++) {
            int c = ((((i & 0x8) == 0) ^ ((j & 0x8)) == 0))*255;
            image[i][j][0]  = (GLubyte)c;
            image[i][j][1]  = (GLubyte)c;
            image[i][j][2]  = (GLubyte)c;
            image[i][j][3]  = (GLubyte)255;
        }
    }

    GLuint texName;
    glGenTextures(1, &texName);    
    glBindTexture(GL_TEXTURE_2D, texName);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureDim, kTextureDim, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);

    return texName;
}

void loadShader() {
#define STRINGIFY(A) #A

    const GLchar* source = STRINGIFY(

                                     uniform sampler2D tex1;
                                     uniform sampler2D tex2;

                                     void main() {
                                         vec4 s1 = texture2D(tex1, gl_TexCoord[0].st);
                                         vec4 s2 = texture2D(tex2, gl_TexCoord[0].st + vec2(0.0625, 0.0625));
                                         gl_FragColor = mix(vec4(1, s1.g, s1.b, 0.5), vec4(s2.r, s2.g, 1, 0.5), 0.5);
                                     }

                                     );

    GLuint program = glCreateProgram();
    GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(shader, 1, &source, NULL);
    glCompileShader(shader);

    GLint logLength;
    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar* log = (GLchar*)malloc(logLength);
        glGetShaderInfoLog(shader, logLength, &logLength, log);
        printf("Shader compile log:\n%s\n", log);
        free(log);
    }

    glAttachShader(program, shader);  
    glLinkProgram(program);

    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar* log = (GLchar*)malloc(logLength);
        glGetProgramInfoLog(program, logLength, &logLength, log);
        printf("Program link log:\n%s\n", log);
        free(log);
    }

    GLuint t1Location = glGetUniformLocation(program, "tex1");
    GLuint t2Location = glGetUniformLocation(program, "tex2");

    glUniform1i(t1Location, 0);
    glUniform1i(t2Location, 1);

    glUseProgram(program);
}


void init()
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_FLAT);

    t1 = makeCheckTex();
    t2 = makeCheckTex();

    loadShader();
}


void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    glActiveTexture(GL_TEXTURE0);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, t1);

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, t2);

    glBegin(GL_QUADS);
    //lower left
    glTexCoord2f(0, 0);
    glVertex2f(-1.0, -1.0);
    //upper left
    glTexCoord2f(0, 1.0);
    glVertex2f(-1.0, 1.0);
    //upper right
    glTexCoord2f(1.0, 1.0);
    glVertex2f(1.0, 1.0);
    //lower right
    glTexCoord2f(1.0, 0);
    glVertex2f(1.0, -1.0);
    glEnd();

    glutSwapBuffers();
}


void reshape(int w, int h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-2, 2, -2, 2, -2, 2);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}


int main(int argc, char **argv)
{
    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA);

    glutInitWindowSize(512, 512);
    glutInitWindowPosition(0, 0);

    glutCreateWindow("GLSL Texture Blending");

    glutReshapeFunc(reshape);
    glutDisplayFunc(display);
    glutIdleFunc(display);

    init();

    glutMainLoop();
    return 0;
}

Espérons que le résultat ressemblera à ceci (vous pouvez commenter l'appel glUseProgram pour voir la première texture dessinée sans le shader): le texte d'alt

23
répondu bosmacs 2013-08-21 13:33:34

Juste pour aider d'autres personnes qui pourraient être intéressées à utiliser plusieurs textures et se sentiront désespérées après des jours à chercher une réponse. J'ai trouvé que vous devez appeler

glUseProgram(program);

GLuint t1Location = glGetUniformLocation(program, "tex1");
GLuint t2Location = glGetUniformLocation(program, "tex2");

glUniform1i(t1Location, 0);
glUniform1i(t2Location, 1);

Dans cet ordre pour que cela fonctionne (glUseProgram est la dernière instruction pour 99% de l'exemple de code que j'ai trouvé en ligne). Maintenant, ce n'est peut-être que le cas pour moi et n'affecte personne d'autre sur Terre, mais juste au cas où je pensais partager.

10
répondu Jérémy Riviere 2014-03-28 12:23:31

Réponse assez tardive, mais pour toute personne rencontrant cela-j'ai rencontré le même problème et après un court bidouillage, j'ai réalisé que l'appel de glActiveTexture(GL_TEXTURE0) résout le problème. Il semble que quelque chose sur la ligne soit confus si l'Unité de texture active n'est pas "réinitialisée" à zéro. Cepourrait être un comportement dépendant du système; j'exécute Archlinux 64 bits avec Mesa 8.0.4.

8
répondu John 2012-10-01 13:12:56

Lors de la compilation de votre shader à tester, j'ai trouvé deux erreurs:

  1. coords doit être affectée à la partie st du composant 4 gl_TexCoord, par exemple

    vec2 coords = gl_TexCoord[0].st;
    
  2. Le shader ne doit pas se terminer par un point-virgule.

Vérifiez-vous n'importe où dans votre programme principal que shader compile correctement? Vous pouvez regarder la GL_COMPILE_STATUS par glGetShader et glGetShaderInfoLog.

2
répondu bosmacs 2010-08-27 01:57:09

Il semble que votre appel glActiveTexture ne fonctionne pas. Êtes-vous sûr de configurer le pointeur de fonction correctement ?

Vérifiez en appelant glGetIntegerv(GL_ACTIVE_TEXTURE, &anint) après avoir appelé votre glacitivetexture (GL_TEXTURE1).

Aussi glEnable(GL_TEXTURE_2D) ne sont pas utiles. Le shader lui-même spécifie les unités de texture à utiliser et la cible de chaque unité à "activer".


Modifier pour ajouter:

Eh Bien, votre nouvelle situation est particulière. Le fait que vous ne pouvez même pas montrer le rouge est bizarre, en particulier (Eh bien, Avez-vous défini alpha à 1 juste pour s'assurer ?).

Cela dit, vous devez restaurer GL_TEXTURE0 en tant que glActiveTexture après avoir défini L'Unité de texture 1 (c'est-à-dire après l'appel glBindTexture).

0
répondu Bahbar 2010-08-26 07:23:18