Отразить текстуры, загруженные с помощью SDL_image и используемые в OpenGL

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

Я нашел два способа исправить это:

Измените текстуру после ее загрузки

Преимущество: выполняется только один раз для каждой текстуры.

Недостаток: используется ЦП, что замедляет загрузку каждой текстуры.

Применить поворот на 180° по осям Y и Z при рендеринге

Преимущество: использование сверхбыстрых функций.

Недостаток: необходимо выполнять несколько раз за кадр.

Есть ли другой способ перевернуть текстуры после того, как они были загружены с помощью SDL_Image? И если нет, то какой метод обычно используется?


person Heckel    schedule 26.06.2015    source источник
comment
Как насчет хранения изображений в источнике OpenGL?   -  person datenwolf    schedule 27.06.2015
comment
Вы имеете в виду использование чего-то другого, кроме SDL_image? У вас есть что порекомендовать?   -  person Heckel    schedule 27.06.2015
comment
Нет, я имею в виду, что сами файлы уже сохранены в правильной ориентации. О, и на самом деле очень просто реализовать загрузчик изображений таким образом, чтобы он загружал изображения с правильным порядком строк развертки. Это сделают загрузчики изображений, ориентированные на OpenGL.   -  person datenwolf    schedule 27.06.2015


Ответы (2)


Есть куча вариантов. Некоторые, которые приходят на ум:

Изменить исходные активы

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

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

Перевернуть во время загрузки изображения

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

Это хорошее решение. Накладные расходы минимальны, так как вы все равно выполняете перелистывание, когда касаетесь данных. Один из распространенных подходов заключается в том, что вы читаете данные построчно и сохраняете в текстуре в обратном порядке, используя glTexSubImage2D().

Переключение между загрузкой и первым использованием

Вы можете создать перевернутую копию текстуры после ее загрузки. Типичным способом сделать это было бы рисование четырехугольника размером с экран, сэмплирование исходной текстуры и рендеринг в FBO, который имеет результирующую перевернутую текстуру в качестве цели рендеринга. Или, что более элегантно, используйте glBlitFramebuffer().

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

Применение преобразования к координатам текстуры

Вы можете применить преобразование к координатам текстуры в вершинном или фрагментном шейдере. Вы говорите о поворотах в своем вопросе, но необходимое преобразование на самом деле тривиально. Вы просто сопоставляете y координаты текстуры с 1.0 - y и оставляете x без изменений.

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

Инвертировать координаты текстуры

Это похоже на предыдущий вариант, но вместо того, чтобы инвертировать координаты текстуры в шейдере, вы уже указываете их инвертированными в данных атрибута вершины.

Это часто тривиально сделать. Например, очень часто для текстурирования четырехугольников используются текстурные координаты (0, 0), (1, 0), (0, 1), (1, 1) для 4 углов. Вместо этого вы просто заменяете 0 на 1 и 1 на 0 во вторых компонентах координат текстуры.

Или скажем, вы загружаете модель, содержащую координаты текстуры из файла. Вы просто заменяете каждое y в координатах текстуры на 1.0f - y во время чтения и перед сохранением координат текстуры для последующего рендеринга.

ИМХО, это часто лучшее решение. Это очень просто сделать и в основном не имеет штрафа за производительность.

person Reto Koradi    schedule 27.06.2015
comment
Говоря с точки зрения разработки программного обеспечения, управляемого данными, вы никогда не должны требовать, чтобы код диктовал изменение данных. Это плохая практика, и в профессиональной среде художникам потребуется предоставлять инвертированные текстуры для всего, что увеличивает их рабочую нагрузку. Переворачивание или иное изменение координат текстуры отрицательно сказывается на надежности приложения. Хотя это шаг в правильном направлении. Единственным реалистичным вариантом является устранение ограничения, заключающегося в том, что изображения переворачиваются при загрузке или перед первым использованием, выполняя замену строки для строки. - person Ian Young; 13.04.2017

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

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

Изменение координат текстуры — это хакерство, несмотря на простоту использования. Что произойдет, если на более позднем этапе вы решите использовать другую библиотеку изображений, которая не переворачивает изображение? Теперь ваше изображение будет снова инвертировано во время рендеринга.

Вместо этого решите проблему в источнике и переверните изображение во время загрузки или перед первым использованием (я выступаю за загрузку, так как ее можно интегрировать в код, загружающий изображение через SDL_Image, и, следовательно, ее легче поддерживать).

Чтобы перевернуть изображение, я опубликую простой псевдокод, иллюстрирующий, как это сделать:

function flip_image( char* bytes, int width, int height, int bytes_per_pixel):

char buffer[bytes_per_pixel*width]

for ( i = 0 -> height/2 ) loop
    offset = bytes + bytes_per_pixel*width * i
    copy row (offset -> offset + bytes_per_pixel*width) -> buffer
    offset2 bytes + bytes_per_pixel * height * width;
    copy row (offset2 -> offset2 + bytes_per_pixel*width) ->  (offset -> offset + bytes_per_pixel*width)
    copy row(buffer -> buffer + width * bytes_per_pixel ) -> offset
end loop

Вот наглядная иллюстрация одной итерации этого цикла кода:

перестановка строк

  1. Скопировать текущую строку N в буфер
  2. Копировать строку (строки - N) в строку N
  3. Копировать буфер в строку (строки - N)
  4. Увеличивайте N и повторяйте до тех пор, пока N == строк/2

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

Следует также отметить, что если загруженное изображение не имеет ширины, равной степени двойки, SDL_Image дополняет его. Поэтому «ширина», передаваемая функции, должна быть шагом изображения, а не его шириной.

person Ian Young    schedule 13.04.2017
comment
Я считаю, что код здесь делает то, что вы делаете, просто более четко: stackoverflow.com/a/65817254/8715 - person AntonioCS; 19.04.2021