OpenGL получить схему нескольких перекрывающихся объектов

10

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

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

Вот что я хочу получить:

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

Любые идеи?

nkint
источник
Использовать фильтр обнаружения краев, закрасить края жирными цветными линиями, затем извлечь извлеченные изображения фигур и наложить поверх слоя цветных линий?
Дробовик ниндзя
что вы имеете в виду с помощью фильтра обнаружения кромок? шейдер? фильтр обработки изображений? как 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

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

Визуализируйте все ваши объекты как сплошные цвета, используя групповой цвет, в текстуру.

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

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

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

Фрагментный шейдер для обнаружения края может выглядеть следующим образом;

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);
}

Где второе значение в texture2D искать - это 2d координата относительно v_texCoord. Вы примените это, визуализируя первую цель рендеринга как текстуру на полноэкранном квадре. Это похоже на то, как вы применили бы эффекты размытия на весь экран, такие как размытие по Гассу.

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

OriginalDaemon
источник
2
извините, но что вы имеете в виду под "Сканирование через каждый текст"? цикл за каждый пиксель? в процессоре? так это что-то вроде: рендеринг со сплошным цветом на текстуру, передача изображения на процессор, сканирование, помещение их снова в текстуру? или сделать это в шейдере?
nkint
Желательно делать это в шейдере, визуализируя полноэкранный четырехугольник с использованием цели рендеринга в качестве текстуры, аналогично эффекту размытия после обработки, но вы можете сначала заставить его работать с процессором с помощью цикла for, просто чтобы увидеть если это работает достаточно хорошо.
OriginalDaemon