Несколько текстур в GLSL - работает только одна
Моя проблема - получить более одной текстуры, доступной в шейдере 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.
Код 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 ответов
Вот базовый пример 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
вызовите, чтобы увидеть первую текстуру, нарисованную без шейдера):
Просто чтобы помочь другим людям, которые могут быть заинтересованы в использовании нескольких текстур и будут чувствовать себя безнадежно после нескольких дней в поисках ответа. Я обнаружил, что вам нужно позвонить
glUseProgram(program);
GLuint t1Location = glGetUniformLocation(program, "tex1");
GLuint t2Location = glGetUniformLocation(program, "tex2");
glUniform1i(t1Location, 0);
glUniform1i(t2Location, 1);
В таком порядке, чтобы он работал (glUseProgram - последняя инструкция для 99% примера кода, который я нашел в Интернете). Теперь это может быть только для меня и не повлиять ни на кого на Земле, но на тот случай, если я подумаю, что поделюсь.
Довольно поздний ответ, но для любого, кто сталкивался с этим - я столкнулся с той же проблемой, и после недолгого поворота я понял, что звонить glActiveTexture(GL_TEXTURE0)
устраняет проблему Кажется, что-то запутывается, если активный текстурный блок не "обнуляется". Это может быть системно-зависимое поведение; Я использую 64-битную версию Archlinux с Mesa 8.0.4.
При компиляции вашего шейдера для тестирования я обнаружил две ошибки:
coords
должен быть назначенst
часть 4-х компонентнаяgl_TexCoord
например,vec2 coords = gl_TexCoord[0].st;
Шейдер не должен заканчиваться точкой с запятой.
Проверяете ли вы где-нибудь в своей основной программе, правильно ли компилируется шейдер? Вы можете посмотреть на GL_COMPILE_STATUS
с помощью glGetShader
а также glGetShaderInfoLog
,
Это звучит как твой glActiveTexture
звонок не работает. Вы уверены, что правильно настроили указатель функции?
Подтвердите, позвонив glGetIntegerv(GL_ACTIVE_TEXTURE, &anint)
после вызова вашей glActiveTexture(GL_TEXTURE1).
Также glEnable(GL_TEXTURE_2D)
не полезны. Сам шейдер определяет, какие текстурные блоки использовать, и какую цель каждого блока "включить".
Изменить, чтобы добавить:
Ну, твоя новая ситуация своеобразна. В частности, странно то, что вы даже не можете показать красный цвет (ну, вы просто установили альфа на 1, чтобы убедиться?).
Тем не менее, вы должны восстановить GL_TEXTURE0 как glActiveTexture
после того, как вы закончите установку блока текстуры 1 (т.е. после glBindTexture
вызов).