Как манипулировать текстурным контентом на лету? - PullRequest
22 голосов
/ 08 октября 2010

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

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

Есть ли эффективная техника для чего-то подобного? Я пытаюсь понять, что нужно сделать, и насколько тяжелой будет операция.

Сейчас единственное, что я могу придумать, - это искать содержимое текстуры в зависимости от того, где оно было затронуто, копировать данные пикселей и смешивать существующие данные пикселей при движении пальца. Затем периодически перезагружайте текстуру с помощью glTexImage2D, чтобы получить этот эффект.

Ответы [ 3 ]

31 голосов
/ 22 мая 2012

Существует как минимум два принципиально разных подхода:

1.Обновить пиксели (я полагаю, это то, что вы имеете в виду в вопросе)

Наиболее эффективный метод изменения пикселей в текстуре называется Render-to-Texture и может быть выполнен в OpenGL / OpenGL ES.через FBOs .В настольном OpenGL вы можете использовать объекты пиксельного буфера ( PBOs ) для манипулирования пиксельными данными непосредственно в графическом процессоре (но OpenGL ES пока не поддерживает это).

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

Вы говорите, что хотите, чтобы она работала с OpenGL ES, поэтому я предлагаю сделать следующие шаги:

  • замените glTexImage2D () на glTexSubImage2D () - если вы наберете достаточную производительность, вот и все, просто позвольте;
  • реализуйте рендеринг в текстуру с FBO и шейдерами - это потребует гораздо больше работы для переписывания вашегокод, но даст еще лучшую производительность.

Для FBO код может выглядеть следующим образом:

// setup FBO
glGenFramebuffers( 1, &FFrameBuffer );
glBindFramebuffer( GL_FRAMEBUFFER, FFrameBuffer );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, YourTextureID, 0 );
glBindFramebuffer( GL_FRAMEBUFFER, 0 );

// render to FBO
glBindFramebuffer( GL_FRAMEBUFFER, FFrameBuffer );
glViewport( 0, 0, YourTextureWidth, YourTextureHeight );
your rendering code goes here - it will draw directly into the texture
glBindFramebuffer( GL_FRAMEBUFFER, 0 );

// cleanup
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glDeleteFramebuffers( 1, &FFrameBuffer );

Имейте в виду, что не все пиксельные форматы могут быть отображены.RGB / RGBA обычно в порядке.

2.Обновить геометрию

Вы также можете изменить геометрию объекта, на который наложена ваша текстура.Геометрия должна быть достаточно мозаичной, чтобы обеспечить плавное взаимодействие и предотвратить появление артефактов.Деформация геометрии может быть выполнена разными методами: параметрические поверхности, NURBS, патчи.

2 голосов
/ 22 мая 2012

Модифицировать цель рендеринга текстуры с помощью FBO сложно, но довольно просто.

Итак, имеем:

  1. TW за пределами буфера TH (связанный с текстурой) - мы называем это Dest
  2. Новый "массив пикселей", текстура IW by IH - мы называем это Src
  3. Желание поместить (IW x IH) текстуру в положение (TX, TY) в текстуру Dest

Хитрость, чтобы "положить" Src в Dest - это

  1. Свяжите сгенерированный FBO как цель рендеринга
  2. Используйте фиктивный 4-вершинный квад с тривиальными координатами вершин (TX, TY), (TX + IW, Y), (TX + IW, TY + IH), (TX, TY + IH) и текстурными координатами (0 , 0), (1,0), (1,1), (0,1)
  3. Привязка тривиального пиксельного шейдера, который считывает текстуру Src, привязанную к первому текстурному блоку, и выводит ее на «экран» (a.k.a. render target, Dest)
  4. Визуализация четырехугольника
  5. Отвязать FBO

Для правильного рендеринга Src вы должны использовать ортографическую проекцию и преобразование камеры идентификации.

Координаты (TX, TY) и (IW, IH) в моем 4-шаговом решении должны быть разделены на TW и TH соответственно, чтобы правильно отобразить размер буфера кадров [0..1, 0..1]. Чтобы избежать этих делений в шейдере, вы можете просто использовать соответствующую орфографическую проекцию для области просмотра [0..TW, 0..TH].

Надеюсь, это решит проблемы с FBO.

2 голосов
/ 22 ноября 2010

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

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

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

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);

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

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

...