Вот функция, в которой я вызываю все свои операции рисования. Я также компилирую шейдеры, встроенные в функцию. Он правильно отображает четырехугольник, когда я просто использую цвета для каждой вершины, но текстуры вообще не хотят работать.
Вот код:
void doGL2() {
glTranslatef(0.f, 0.f, 0.f);
const GLchar* vertShader[] = { R"glsl(
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexPos;
out vec3 col;
out vec2 texturePos;
void main()
{
gl_Position = vec4(aPos, 1.0);
col = aColor;
texturePos = aTexPos;
}
)glsl" };
const GLchar* fragShader[] = { R"glsl(
#version 330 core
out vec4 FragColor;
in vec3 col;
in vec2 texturePos;
uniform sampler2D t;
uniform vec2 iResolution;
void main()
{
vec2 uv = gl_FragCoord.xy / iResolution;
//FragColor = vec4(iResolution, 1., 1.);
FragColor = mix(vec4(col, 1.0f), texture(t, gl_FragCoord.xy / vec2(1200., 675.)), 1.);
}
)glsl" };
vShader2 = glCreateShader(GL_VERTEX_SHADER);
fShader2 = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vShader2, 1, vertShader, NULL);
glCompileShader(vShader2);
GLint success;
GLchar infoLog[1024];
glGetShaderiv(vShader2, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vShader2, 1024, NULL, infoLog);
throw std::runtime_error("\noh no vert\n");
}
glShaderSource(fShader2, 1, fragShader, NULL);
glCompileShader(fShader2);
glGetShaderiv(fShader2, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fShader2, 1024, NULL, infoLog);
throw std::runtime_error("\noh no frag\n");
}
shaderProgram2 = glCreateProgram();
glAttachShader(shaderProgram2, vShader2);
glAttachShader(shaderProgram2, fShader2);
glLinkProgram(shaderProgram2);
GLfloat screen[2] = { 1200.0f, 675.0f };
glUseProgram(shaderProgram2);
glUniform2fv(glGetUniformLocation(shaderProgram2, "iResolution"), 2, screen);
glUniform1i(glGetUniformLocation(shaderProgram2, "t"), 10);
//not sure if I should do this on cleanup or now
glDeleteShader(vShader2);
glDeleteShader(fShader2);
//lets make a temporary test texture
int width, height, channels;
unsigned char* data = stbi_load("tex2.jpg", &width, &height, &channels, 0);
GLuint tempT = 1;
glActiveTexture(GL_TEXTURE10);
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &tempT);
glBindTexture(GL_TEXTURE_2D, tempT);
// set texture options
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
stbi_image_free(data);
GLfloat vertices[] = {
// positions // colors // texture positions
0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom left
1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f // top right
,
0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom left
0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top left
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f // top right
};
glGenVertexArrays(1, &VAO2);
glGenBuffers(1, &VBO2);
glBindVertexArray(VAO2);
glBindBuffer(GL_ARRAY_BUFFER, VBO2);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//positions
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
//colors
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
//texture positions
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
float initTime = glutGet(GLUT_ELAPSED_TIME);
float prevTime = initTime;
float dt = 0.0f;
while (prevTime - initTime < 1000.0f) {
dt = (glutGet(GLUT_ELAPSED_TIME) - prevTime) / 1000.0f;
prevTime = glutGet(GLUT_ELAPSED_TIME);
glClearColor(1.f, 1.f, 1.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(VAO2);
glBindTexture(GL_TEXTURE_2D, tempT);
glDrawArrays(GL_TRIANGLES, 0, 6);
SwapBuffers(GetDC(w));
glFlush();
}
}
По какой-то причине, когда я вместо этого привязываю текстуру к GL_TEXTURE0
, она отображает текстуру.
Редактировать:
Я делаю дальнейшее редактирование, так как содержание моего исходного вопроса не решает проблему должным образом. Кажется, я не могу привязать любую текстуру к любой текстуре, кроме GL_TEXTURE0
. Я видел другие форумы с этой проблемой, но все ответы на эти проблемы касаются других проблем, которых здесь нет. Как видите, я пытаюсь привязать эту текстуру к GL_TEXTURE10
, однако на выходе все черное. Однако, когда я привязываюсь к GL_TEXTURE0
, текстура отображается нормально. Я изменил код, чтобы отразить ответ Rabbid, поскольку это действительно были ошибки, но не ошибки, которые повлияли на эту проблему; код актуален, отражая текущую проблему.
Кроме того, я напечатал tempT
, и он всегда возвращается как 1, что означает, что он каждый раз привязывается к GL_TEXTURE0
, несмотря на то, что я вызываю glActiveTexture()
.
tempT
не указывает на текстурный блок! Вы должны установить текстурный блок перед привязкой текстуры (до glBindTexture
), но это не имеет никакого эффекта. glGenTextures
.
Я добавил несколько предложений к ответу.
Если вы не генерируете мип-карты (с glGenerateMipmap
), важно установить GL_TEXTURE_MIN_FILTER
. Поскольку фильтр по умолчанию — GL_NEAREST_MIPMAP_LINEAR
, текстура будет иметь статус «Mipmap Incomplete», если вы не измените функцию минимизации на GL_NEAREST
или GL_LINEAR
.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
Кроме того, вместо (1, 1) необходимо указать размер изображения (with
, height
):
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
Не гарантируется, что stbi_load
создаст текстуру с 4 цветовыми каналами. Заставьте stbi_load
генерировать изображение с 4 цветовыми каналами, явно передав 4 последнему параметру:
unsigned char* data = stbi_load("tex2.jpg", &width, &height, &channels, 0);
unsigned char* data = stbi_load("tex2.jpg", &width, &height, &channels, 4);
Если вы используете шейдерную программу, вам не нужно включать текстурирование. Используется ли текстура или нет, решается в шейдерной программе. glEnable(GL_TEXTURE_2D);
— это устаревший OpenGL, удалите его.
Помимо того, что ваш код работает нормально, я его протестировал. Однако количество текстурных блоков ограничено. Убедитесь, что вы используете текстурный блок в пределах досягаемости вашей системы. Вы можете получить количество текстурных блоков с помощью GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
. например.:
int max_units;
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_units);
std::cout << "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS " << max_units << std::endl;
Also, I printed
tempT
and it always returns as 1, meaning it is binding to GL_TEXTURE0 every time despite what I call inglActiveTexture()
.
Блок текстуры не имеет ничего общего с идентификатором объекта текстуры. Значение tempT
не указывает на текстурный блок, в котором текстура будет привязана. Вы должны установить текстурный блок перед привязкой текстуры с помощью glBindTexture
, но это не влияет на glGenTextures
. Вы можете привязать текстуру к нескольким текстурным модулям или к разным текстурным модулям в разное время. Блок текстуры — это точка привязки между объектом текстуры и юниформом сэмплера текстуры.
Если вы хотите использовать текстуру в шейдерной программе, вам необходимо убедиться, что текстура привязана к текстурному модулю, и этот модуль настроен на равномерный сэмплер текстуры.
Я предлагаю установить текстурный блок перед привязкой текстуры и использовать его для рисования объекта:
GLint t_location = glGetUniformLocation(shaderProgram2, "t")
glUseProgram(shaderProgram2);
glUniform1i(t_location, 10);
glActiveTexture(GL_TEXTURE10);
glBindTexture(GL_TEXTURE_2D, tempT);
glDrawArrays(GL_TRIANGLES, 0, 6);
@BradenYonano Я добавил в ответ несколько новых предложений.
Итак, если идентификатор текстуры, в данном случае tempT
, не является текстурным блоком, то я не должен передавать идентификатор текстуры в юниформ-сэмплер в шейдере, тогда правильно? Если это так, то как мне связать единицу с идентификатором текстуры, например, если бы у меня было 100 текстур? Мой код работает с этими изменениями, но только потому, что у меня есть 1 текстура. Мне просто интересно, что бы я передал в униформу, если я не могу передать идентификатор текстуры.
@BradenYonano "как связать единицу с идентификатором текстуры, например, если бы у меня было 100 текстур" — Вы не можете использовать 100 разных текстур в одном шейдере одновременно. (ГП не может кэшировать все эти текстуры сразу и обрабатывать их с хорошей производительностью). Вы должны использовать GL_TEXTURE_2D_ARRAY
или атлас текстур.
Итак, у меня есть код для работы со 128 текстурами, которые я использую (я визуализирую текст), но он довольно медленный, так как символов становится все больше. Я считаю, что на этот вопрос был дан полный ответ. Спасибо за ваше понимание!
Других проблем с вашим кодом нет, я его проверил. Какая у вас система? Это исходный код? В какой среде вы запускаете код?