Несколько текстур в GLSL - работает только одна - PullRequest
21 голосов
/ 25 августа 2010

Моя проблема заключается в получении более одной текстуры, доступной в шейдере GLSL. Вот что я делаю:

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;
    }
};

Итак, я просто выбираю между двумя значениями цвета на основе равномерной переменной. Достаточно просто (это тест), но вместо ожидаемого поведения я получаю все черное при смешении <= 0.5 </strike>.

код 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()

Шейдер компилируется и связывается перед всем этим. Все проверки работоспособности в этом процессе показывают, что все идет хорошо. Как я уже сказал, значение col в шейдерной программе отражает фрагменты текстуры; значение col2 является черным. Отображаемая текстура является последней активной текстурой - если я изменю последнюю glBindTexture на привязку Texture0.Handle, текстура изменится. Исправлено в соответствии с ответом Бахбара.

На самом деле сцена отображает весь черный, даже если я добавлю что-то вроде gl_FragColor.r = blend; в качестве последней строки шейдера. Но если я закомментирую вызов glActiveTexture(GL_TEXTURE1);, шейдер снова заработает, и одна и та же текстура появится и в sampler0, и в sampler1.

Что происходит? Строка, о которой идет речь, glActiveTexture(GL_TEXTURE1);, кажется, работает нормально, о чем свидетельствует последующий glGetIntegerv(GL_ACTIVE_TEXTURE, &anint). Почему это все так ужасно ломает? Я уже пытался обновить драйверы дисплея.

Ответы [ 5 ]

22 голосов
/ 27 августа 2010

Вот базовый пример GLUT (написанный на OS X, адаптируемый по мере необходимости), который генерирует две текстуры шахматной доски, загружает шейдер с двумя сэмплерами и объединяет их, окрашивая каждую (один красный, один синий) и смешивая.Посмотрите, работает ли это для вас:

#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;
}

Надеемся, что результат будет выглядеть примерно так (вы можете закомментировать вызов glUseProgram, чтобы увидеть первую текстуру, нарисованную без шейдера): alt text

11 голосов
/ 28 марта 2014

Просто чтобы помочь другим людям, которые могут быть заинтересованы в использовании нескольких текстур и будут чувствовать себя безнадежными после нескольких дней поиска ответа. Я обнаружил, что вам нужно позвонить

glUseProgram(program);

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

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

В таком порядке, чтобы он работал (glUseProgram - последняя инструкция для 99% примера кода, который я нашел в Интернете). Теперь это может быть только для меня и не повлиять ни на кого на Земле, но на тот случай, если я подумаю, что поделюсь.

8 голосов
/ 22 августа 2012

Довольно поздний ответ, но для любого, кто сталкивался с этим - я столкнулся с той же проблемой, и после недолгого осмотра я понял, что вызов glActiveTexture(GL_TEXTURE0) решает проблему.Кажется, что-то запутывается, если активный текстурный блок не «обнуляется».Это может быть зависимым от системы поведением;Я использую 64-битную версию Archlinux с Mesa 8.0.4.

2 голосов
/ 26 августа 2010

При компиляции вашего шейдера для тестирования я обнаружил две ошибки:

  1. coords должна быть назначена st часть 4-компонентного gl_TexCoord, например

    vec2 coords = gl_TexCoord[0].st;
    
  2. Шейдер не должен заканчиваться точкой с запятой.

Проверяете ли вы где-нибудь в своей основной программе, правильно ли компилируется шейдер?Вы можете посмотреть на GL_COMPILE_STATUS через glGetShader и glGetShaderInfoLog.

0 голосов
/ 25 августа 2010

Похоже, ваш glActiveTexture звонок не работает. Вы уверены, что правильно настроили указатель функции?

Проверьте, позвонив glGetIntegerv(GL_ACTIVE_TEXTURE, &anint) после вызова вашей glActiveTexture (GL_TEXTURE1).

Также glEnable(GL_TEXTURE_2D) не нужны. Сам шейдер определяет, какие текстурные блоки использовать, и какую цель каждого блока «включать».


Изменить, чтобы добавить:

Ну, твоя новая ситуация особенная. Тот факт, что вы не можете даже показать красный, странный, в частности (ну, вы установили альфа на 1, чтобы убедиться?).

Тем не менее, вы должны восстановить GL_TEXTURE0 как glActiveTexture после того, как вы закончите установку модуля текстуры 1 (т.е. после вызова glBindTexture).

...