Как правильно масштабировать текстуру в opengl? - PullRequest
0 голосов
/ 30 декабря 2018

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

Я подумал, что мог бы просто создать текстуру из массива с плавающей точкой, например:

float values[4] {
    0.f, 1.f,
    0.f, 1.f
}

// gen texture
unsigned int texId;
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);

// set filter and wrap
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

// copy values
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, 2, 2, 0, GL_RED, GL_FLOAT, values);

И нарисуйте его:

float vertices[8] {
    -1.f, -1.f, 0.f, 0.f,
     1.f, -1.f, 1.f, 0.f,
     1.f,  1.f, 1.f, 1.f,
    -1.f,  1.f, 0.f, 1.f
}

// generate vertex buffer, vertex buffer layout and vertex array

unsigned int[6] indices {
    0, 1, 2,
    2, 3, 1
}

// generate index buffer

// bind everything

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);

Где связанный вершинный шейдер выглядит так:

#version 330 core

layout(location=0) in vec2 in_position;
layout(location=1) in vec2 in_texCoords;

out vec2 texCoords;

void main() {
    gl_Position = vec4(in_position, 0.f, 1.f);
    texCoords = in_texCoords;
}

А фрагментный шейдер выглядит так:

#version 330 core

layout(location = 0) out vec4 out_color;

in vec2 texCoords;

uniform sampler2D u_gradient;

void main() {
    float red = texture(u_gradient, texCoords).r;
    out_color = vec4(red, 0.f, 0.f, 1.f);
}

После этогоЯ ожидаю получить цветовой градиент слева направо (от черного к красному) по всему окну.Однако, что я получаю, так это градиент от 1/4 до 3/4 окна в направлении x и y (см. Изображение ниже).Я также отметил, что упаковка повторения здесь не применима, поскольку то, что я получаю, выглядит как зеркальное повторение.

Результат:

IМы поиграли с фрагментным шейдером, используя фиксированные значения вместо texCoords, и выяснили, что диапазон от .25 до .75 по оси x представляет весь градиент (.25 отображает 0 для красного и .75 к 1).

Изменение количества «шагов», передаваемых в качестве значений в текстуру (например, массив 4x4), не изменило результаты.

Я также пытался использовать изображение в качестве текстуры (загружается с помощью stb_image, разрешение 1920x1080), которая прекрасно работает и распространяется по всему экрану.

Для пояснения: почему у texCoords диапазон градиента составляет от 0,25 до 0,75, а не от 0 до 1, и как я могу это исправить(кроме настройки самого texCoords)?

1 Ответ

0 голосов
/ 30 декабря 2018

Предположим, у вас есть текстура 2x2

Текстура 2x2

Если эта текстура обернутана сетке из фрагментов 6x6 центр текселя находится точно на текселе в середине ячейки 3x3 квадрата 6x6:

6x6 quad

Цвет остальных фрагментов зависит от параметров текстуры - см. glTexParameter.

Поскольку текстура увеличенаGL_TEXTURE_MAG_FILTER является значимым.

Если оно равно GL_NEAREST, то цвет фрагментов соответствует цвету одного из ближайших текселей к координатам текстуры фрагмента:

Если это GL_LINEAR, то цвет интерполируется средневзвешенным значением 4 пикселей, которые находятся ближе всего к координатам текстуры.

интерполяция на границах четырехугольника 6x6 зависит от параметров обтекания GL_TEXTURE_WRAP_S и GL_TEXTURE_WRAP_T.

Если параметры GL_REPEAT (что по умолчаниюult), текстура обрабатывается как бесконечная текстура, а интерполяция интерполяции цвета на границах учитывает тексели на противоположной стороне текстуры.Используется для бесшовных текстур и листов:

Если это GL_CLAMP_TO_EDGE, то интерполированный цвет на границах привязывается к цветутексели на границе текстуры:


Примените параметр обтекания текстуры GL_CLAMP_TO_EDGE к объекту текстуры,

float values[4] { 0.f, 1.f, 0.f, 1.f };

unsigned int texId;
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);

// set filter and wrap
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

// copy values
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, 2, 2, 0, GL_RED, GL_FLOAT, values);

, чтобы получить следующий градиент:

...