OpenGL отримує контур декількох об'єктів, що перекриваються


10

У мене просто була ідея для моєї поточної гри, зробленої з opengl в c ++: я хотів би мати великий контур (5-6 пікселів) на декількох об'єктах, що перекриваються, коли гравець щось виграє.

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

Це те, що я хочу отримати:

введіть тут опис зображення

Будь-які ідеї?


Використовуйте фільтр для виявлення країв, заповнюйте краї товстими кольоровими лініями, потім витягуйте відтворені зображення фігур і накладайте поверх шару кольорових ліній?
Стрілецький ніндзя

що ви маєте на увазі під фільтром для виявлення краю? шейдер? фільтр для обробки зображень? як opencv (надайте текстуру, застосуйте фільтр до текстури, відсуньте змінену текстуру)?
nkint

Я поняття не маю; Я не дуже добре розбираюся в 3d-рендерінгу для початку.
Стрілецький ніндзя

у вас є якийсь приклад буфера трафарету на зразок цього? Я думаю, що використання буфера трафарету було б більш чистим способом, але я не в змозі зробити якийсь буфер трафарету
nkint

Відповіді:


4
  1. Увімкніть і очистіть буфер трафарету.
  2. Намалюйте об'єкти, встановивши буфер трафарету. Об'єкти можуть бути напівпрозорими тощо.
  3. Тепер встановіть режим трафарету, щоб записувати лише пікселі, де трафарет не встановлений.
  4. І знову намалюйте кожен об'єкт, злегка намальований вгору, у бажаному кольоровому кольорі та без текстур.
  5. Вимкнути буфер трафарету.

Ось код, адаптований з деякого коду трафарету webGL:

// drawing will set stencil stencil
    gl.enable(gl.STENCIL_TEST);
    gl.stencilFunc(gl.ALWAYS,1,1);
    gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE);
    gl.stencilMask(1);
    gl.clearStencil(0);
    gl.clear(gl.STENCIL_BUFFER_BIT);
// draw objects
for(var object in objects)
  objects[object].draw();
// set stencil mode to only draw those not previous drawn
    gl.stencilFunc(gl.EQUAL,0,1);
    gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP);
    gl.stencilMask(0x00);
// draw object halo
for(var object in objects)
  objects[object].drawHalo(1.1,red); // each mesh should be individually scaled e.g. by 1.1
// done
    gl.disable(gl.STENCIL_TEST);

Я думаю, що я використовував цей підхід в іграх на RTS, щоб малювати ореоли навколо вибраних одиниць, але це було дуже давно, і я не пам'ятаю, чи є якісь прийоми і всі нюанси.


у вас є якийсь приклад буфера трафарету на зразок цього? Я думаю, що використання буфера трафарету було б більш чистим способом, але я не в змозі зробити якийсь буфер трафарету
nkint

7
Зауважте, що об'єкти відображення, дещо зменшені вгору, не призведуть до рівномірної товщини лінії. Далі краї будуть тоншими. Якщо ви враховуєте це під час масштабування об'єктів, довгі предмети, що тягнуться на відстань, матимуть неоднакову товщину. Для цього є трохи більше, щоб лінії були красивими і рівними.
Шон Міддлітч

2
Краще, ніж просто масштабувати об’єкти, - це написати вершинний шейдер, який зміщує кожну вершину на невелику відстань уздовж її звичайної. Це досить добре працює для гладких об'єктів, але створює тріщини на жорстких краях. Ви можете спробувати створити сітку з альтернативним набором нормалів, які згладжені скрізь, і побачити, де це потрапляє.
Натан Рід

2

Почніть з пошуку всіх груп об’єктів, де група об’єктів - це сукупність об'єктів, які перекриваються. Стандартне виявлення зіткнень повинно зробити цю роботу. Призначте кожній групі унікальний колір. Будь-який колір зробив би.

Надайте всі свої об'єкти суцільними кольорами, використовуючи груповий колір, текстуру.

Створіть нову контуру текстури з тими ж розмірами, що й ціль візуалізації. Перегляньте кожен тексель цілі візуалізації та визначте, чи він відрізняється кольором від будь-яких навколишніх текселів. Якщо це так, змініть відповідний текстур текстури контуру на потрібний колір лінії.

Нарешті, візьміть цю контурну текстуру та візьміть її на верхню частину зображення, яке ви хочете намалювати на екрані (можна, звичайно, зробити це одночасно з виявленням ребер у фрагменті шейдера і уникнути створення текстури краю в першому місце).

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

Фрагмент шейдера для виявлення цього краю може виглядати приблизно так;

precision mediump float;

uniform sampler2D s_texture;

varying vec2 v_texCoord;

void main()
{
    gl_FragColor = vec4(0.0);

    vec4 baseColor = texture2D(s_texture, v_texCoord);
    gl_FragColor += baseColor - texture2D(s_texture, top);
    gl_FragColor += baseColor - texture2D(s_texture, topRight);
    gl_FragColor += baseColor - texture2D(s_texture, right);
    gl_FragColor += baseColor - texture2D(s_texture, bottomRight);
    gl_FragColor += baseColor - texture2D(s_texture, bottom);
    gl_FragColor += baseColor - texture2D(s_texture, bottomLeft);
    gl_FragColor += baseColor - texture2D(s_texture, left);
    gl_FragColor += baseColor - texture2D(s_texture, topLeft);
}

Там, де друге значення тексту2D шукає, є 2d координатою відносно v_texCoord. Ви застосували б це, відображаючи першу ціль візуалізації як текстуру на повноекранному квадратику. Це схоже на те, як ви застосували блякані ефекти на весь екран, такі як розмиття у газі.

Причина використовувати першу ціль візуалізації суцільними кольорами - це просто переконатися, що між різними об'єктами, які перекриваються, немає сприйманого краю. Якщо ви просто виконали виявлення ребер на екрані зображення, ви, ймовірно, виявите, що він виявляє і краї в перекриттях (якщо припустимо, що об'єкти мають різні кольори / текстури / освітлення).


2
Вибачте, але що ви маєте на увазі під "Сканувати через кожен тексель"? a для циклу, хоча кожен піксель? на процесорі? тож це щось на кшталт: візуалізуйте суцільним кольором текстуру, перенесіть зображення на процесор, зробіть сканування, знову вставте їх у текстуру? чи робити це в шейдері?
nkint

Переважно робити це в шейдері, надаючи повноекранний квадроцикл, використовуючи ціль візуалізації як текстуру, аналогічно ефекту розмиття після обробки, але ви можете змусити його працювати на процесорі спочатку за допомогою циклу for, просто щоб побачити якщо це працює досить добре
OriginalDaemon
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.