OpenGL:Как реализовать инструмент «ластик»?
-
08-07-2019 - |
Вопрос
Я работаю над игрой для iPhone, в которой используется механика рисования/рисования, и у меня возникают проблемы с попыткой создать инструмент, который стирал бы уже нарисованные объекты.
Основная проблема заключается в том, что рисуемый фон представляет собой не сплошной цвет, а статичное изображение или анимацию.Я пробовал использовать различные варианты смешивания и логические операции при рисовании, но ничего не помогало.Я новичок в OpenGL, поэтому, должно быть, что-то упускаю.
Какие-нибудь советы?
РЕДАКТИРОВАТЬ:Чтобы дать немного больше информации, я использую текстуры для своих кистей и использую glVertexPointer() и glDrawArrays() для их рендеринга.Например:
glBindTexture(GL_TEXTURE_2D, circleBrush);
glVertexPointer(3, GL_FLOAT, 0, verts);
glTexCoordPointer(2, GL_FLOAT, 0, coords);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
РЕДАКТИРОВАТЬ 2:К сожалению, буферы трафаретов недоступны на iPhone.:(
РЕДАКТИРОВАТЬ 3:Объекты фреймбуфера доступны на iPhone, и я выбрал именно этот путь.Я еще не реализовал это полностью, но пока похоже, что все работает так, как я хотел.Всем спасибо!
Решение
Нарисуйте полноэкранный текстурированный квад поверх вашей сцены. Когда пользователь рисует мазок кисти, используйте glTexSubImage2D
, чтобы обновить текстуру. Р>
glReadPixels / glDrawPixels работает медленно.
Использование FrameBufferObjects еще лучше, но я сомневаюсь, что это расширение доступно на iPhone (опять же, я точно не знаю, так что, возможно, попробуйте). FBO позволяют рисовать непосредственно в текстуру, как если бы это был другой контекст рендеринга.
Другие советы
Трафаретный буфер - лучший способ подойти к этому наверняка ... Вы сэкономите время, ресурсы процессора и потенциальные проблемы ..., они доступны на Iphone, вам просто нужно создать поверхность OpenGlES 2.0 (не gles 1.0 или 1.1).
//Turn off writing to the Color Buffer and Depth Buffer
//We want to draw to the Stencil Buffer only
glColorMask(false, false, false, false);
glDepthMask(false);
//Enable the Stencil Buffer
glEnable(GL_STENCIL_TEST);
//Set 1 into the stencil buffer
glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
//CALL YOUR DRAWING METHOD HERE
//Turn on Color Buffer and Depth Buffer
glColorMask(true, true, true, true);
glDepthMask(true);
//Only write to the Stencil Buffer where 1 is set
glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
//Keep the content of the Stencil Buffer
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
//CALL OUR DRAWING METHOD AGAIN
Найти этот пример: http://www.opengl.org/resources/code/samples /glut_examples/examples/stenciltst.c р>
Вот визуальный результат: http://www.opengl.org/resources/code/samples /glut_examples/examples/stenciltst.jpg р>
Я внедрил такой же инструмент ластика с этим на Android и iPhone, и он работает как шарм!
Удачи! Р>
Ура!
Вы не предоставляете много информации, но я предполагаю, что вы храните все, что они "рисуют" в буфер и затем рисуем его на экране следующим образом:
glWindowPos2i(X, Y);
glDrawPixels(drawing->Width, drawing->Height, drawing->Format,
GL_UNSIGNED_BYTE, drawing->ImageData);
С рисунком > ImageData является буфером. Что вы можете сделать, так это создать отдельный фоновый буфер и нарисовать его первым. Затем инструмент стирания просто уберет буфер рисования (повернув все значения, включая альфа, вверх).
Чтобы это решение работало, вам нужно включить смешивание и отключить проверку глубины .
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glWindowPos2i(X, Y);
//background never changes
glDrawPixels(background->Width, background->Height, background->Format,
GL_UNSIGNED_BYTE, background->ImageData);
glWindowPos2i(X, Y);
glDrawPixels(drawing->Width, drawing->Height, drawing->Format,
GL_UNSIGNED_BYTE, drawing->ImageData);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
Это то, что вы ищете?
Для этой операции вы можете использовать буфер трафарета.Буфер трафарета — это специальный буфер, который хранит информацию для каждого пикселя, аналогично буферу глубины.В отличие от буфера глубины, вы сами решаете, как изменяется буфер трафарета во время рисования и как это влияет на решение рисовать в буфере цвета или нет.Для этого вы можете установить определенные состояния перед любой операцией рисования.Вот что ты делаешь:
В то время, когда пользователи стираются, нарисуйте область «стерто» в буфер трафарета (используя трафарет, см. Ниже).Вы можете использовать любую функцию рисования GL для этого.
В каждом проходе рендеринга сначала нарисуйте фон (если вы хотите, вы можете использовать здесь отрицательный тест на трафарет, чтобы только нарисовать «стертную» часть фона - может повысить производительность).
Затем включите тест трафарета для всех других операций на рисовании.Затем OpenGL будет привлекать только «неэразированные» области.
Функция, определяющая, как буфер трафарета должен влиять на рисование (или нет):glStencilFunc()
Функция, определяющая влияние рисования на сам буфер трафарета:глСтенцилОп()
Дальнейшее объяснение, а также аргументы в пользу этого:http://www.opengl.org/resources/code/samples/sig99/advanced99/notes/node117.html
Использование режима glBlendFunc (GL_ONE, GL_ZERO) может быть полезным.