Почему координата текстуры 1.0 выходит за край текстуры?

Я выполняю поиск цвета, используя текстуру, чтобы применить эффект к изображению. Мой поиск представляет собой карту градиента, использующую яркость фрагмента первой текстуры, а затем ищущую ее на второй текстуре. Вторая текстура имеет размер 256x256 с горизонтальными градиентами и несколькими различными градиентами сверху вниз. Итак, 32 горизонтальные полосы высотой по 8 пикселей каждая. Мой поиск по x — это яркость, по y — это градиент, и я нацеливаюсь на центр полосы, чтобы избежать пересечения.

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

 lowp vec4 source = texture2D(u_textureSampler, v_fragmentTexCoord0);
 float luminance = 1.0 - dot(source.rgb, W);
 lowp vec2 texPos;
 texPos.x = clamp(luminance, 0.0, 1.0);
 // the y value selects which gradient to use by supplying a T value
 // this would be more efficient in the vertex shader
 texPos.y = clamp(u_value4, 0.0, 1.0);

 lowp vec4 newColor1 = texture2D(u_textureSampler2, texPos);

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

В конце концов я подумал, что это может иметь какое-то отношение к моей исходной текстуре или способу ее загрузки. В итоге я исправил это, добавив:

    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

Итак.. ПОЧЕМУ?

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

Если мои textPos.x и .y зажаты до 0-1... как он вытягивает образец за край?

Кроме того, нужно ли использовать указанный выше вызов зажима при создании текстуры или я могу вызвать его, когда собираюсь использовать текстуру?


person badweasel    schedule 23.09.2013    source источник


Ответы (1)


Это правильное поведение сэмплера текстуры.

Позвольте мне объяснить это. Когда вы используете текстуры с выборкой GL_LINEAR, GPU будет брать средний цвет пикселя, смешанный с соседними пикселями (поэтому вы не видите пикселизацию, как в режиме GL_NEAREST — вместо этого пиксели размыты). А в режиме GL_REPEAT координаты текстуры будут переходить от 0 к 1 и наоборот, сливаясь с соседними пикселями (т.е. в крайних координатах будет сливаться с противоположной стороной текстуры). GL_CLAMP_TO_EDGE предотвращает такое поведение наложения, и пиксели не будут смешиваться с пикселями на противоположной стороне текстуры.

Надеюсь, мое объяснение понятно.

person keaukraine    schedule 23.09.2013
comment
То есть невозможно зажать внутри шейдера, если вы находитесь в GL_LINEAR? Его надо зажимать вызовом opengl? А как насчет вызова glTexParameteri? Можно ли это сделать, когда вы связываете текстуру, чтобы использовать ее, или это нужно делать при загрузке текстуры? - person badweasel; 24.09.2013
comment
@badweasel Вы можете реализовать ограничение в шейдере, что GL_CLAMP_TO_EDGE на самом деле ограничивает диапазон координат до [0+0,5/texSize,1- 0,5/texSize]. Это вызывает выборку в точном центре текселей, поэтому интерполяция с использованием соседних текселей никогда не выполняется. - person Andon M. Coleman; 09.05.2014
comment
@badweasel Эта специальная гарантия, конечно, применяется только при выборке краевых текселей, отсюда и название. - person Andon M. Coleman; 09.05.2014
comment
@Андон, надо будет попробовать. Мои эксперименты показали, что текст 1.0 с gl_repeat интерполируется с текстом a на противоположной стороне. - person badweasel; 09.05.2014
comment
@badweasel: Это правильно, и именно поэтому вы не хотите использовать 1.0. Значение 1.0 фактически находится точно на краю вашей текстуры. Он равноудален от центра первого и последнего текселей в вашей текстуре, поэтому при интерполяции они оба будут иметь одинаковый вес. GL_CLAMP_TO_EDGE перемещает координату 1.0 так, чтобы она ссылалась на центр последнего текселя, поэтому во время интерполяции последний тексель имеет вес 1.0, так что это единственное, что показывает вверх. - person Andon M. Coleman; 09.05.2014