Рисование контура пересекающихся кругов - PullRequest
10 голосов
/ 20 сентября 2011

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

Они будут перекрываться, однако я хочу нарисовать внешнюю форму. Я знаю, что это, вероятно, потребовало бы, чтобы я работал там, где они пересекаются, и каким-то образом формировал общую форму для рисования. Проблема в том, что некоторые пункты могут даже не коснуться других! Так что мне тоже нужно это уладить.

Я попытался проиллюстрировать, что я имею в виду просто:

enter image description here

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

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

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

Это может быть больше математическим вопросом, я не ищу фрагменты кода, а на самом деле, как работать с этими формами. Я просто не могу думать о том, как это сделать!

***** Редактировать: с решением, которое я придумал, надеюсь, может помочь кому-то еще!

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

Так что код мудрый, у меня теперь есть это:

private void stencilCircleAroundStars()
{
    //Lets try and draw something here using stencil
    glColorMask(false, false, false, false); //Disable colour mask
    glEnable(GL_STENCIL_TEST); // Enable Stencil Buffer For "marking" the outer circle
    glDisable(GL_DEPTH_TEST);// Disable Depth Testing

    for (Object value : stars.values())
    {
        Star star = (Star)value;

        glStencilFunc(GL_ALWAYS, 1, 1); // Always Passes, 1 Bit Plane, 1 As Mask
        glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // We Set The Stencil Buffer To 1 Where We Draw Any Polygon

        //Draw the large circle
        starOb.location.copy(star.location);
        starOb.setScale(2000);
        starOb.draw();
    }

    for (Object value : stars.values())
    {
        Star star = (Star)value;
        //Now we change the functions and remove a slightly smaller circle from buffer.
        glStencilFunc(GL_ALWAYS, 0, 0); // Always passes, 0 bit plane, 0 as mask;
        glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // We Set The Stencil Buffer To 0 Where We Draw Any Polygon
        starOb.location.copy(star.location);
        starOb.setScale(1900);
        starOb.draw();
    }

    //Now we enable the colour
    glColorMask(true, true, true, true);
    glStencilFunc(GL_EQUAL, 1, 1); // We Draw Only Where The Stencil Is 1
    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // Don't Change The Stencil Buffer

    glColor4f(0.5f, 1.0f, 0.5f, 0.5f);
    for (Object value : stars.values())
    {
        Star star = (Star)value;
        starOb.location.copy(star.location);
        starOb.setScale(2000);
        starOb.draw();
    }

    //Now we are done .. disable
    glDisable(GL_STENCIL_TEST);  
}

Мои точки по сути являются сущностями, называемыми "звездами" для целей моей программы, и StarOb - это коллекция квадов, которые я загрузил из файла, которые образуют красивый гладкий круг.

Я отключаю цветовую маску и прохожу цикл один раз, рисуя самый большой кружок в буфере трафарета и устанавливая значение 1. Затем я снова зацикливаюсь, рисуя меньший масштабированный круг в буфере трафарета, но на этот раз устанавливая значение of 0. Это должно оставить границу вокруг любой звезды, которая не касается других звезд и будет эффективно удаляться там, где они перекрываются.

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

Если вы действительно хотели его увидеть, вот видео о том, как заработать несколько увеличивающихся баллов: Видео о нем

Вот некачественная версия того, как это получилось (фон не был нарисован во время тестирования):

Overlapping circles with centre not drawn due to stencil

Ответы [ 2 ]

6 голосов
/ 21 сентября 2011

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

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

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

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

3 голосов
/ 20 сентября 2011

Два прохода:

  1. Нарисуйте все контуры вашего круга с помощью GL_LINES или GL_LINE_LOOP. Убедитесь, что вы установили glLineWidth() на 3 или выше.
  2. Нарисуйте заполненные круги (GL_TRIANGLE_STRIP может быть полезно) с вашим цветом фона и таким же радиусом, что и круги из шага 1.

Заполненные кружки на шаге 2 перезапишут все пиксели контура с шага 1, но только там, где они перекрываются. Это оставляет вас с непересекающимися контурами нетронутыми.

Если вам нужен более широкий диапазон ширины контура (т. Е. Больше, чем ~ 10, что большинство реализаций OpenGL допускают glLineWidth()), вам следует повторно использовать средство визуализации закрашенного круга, начиная с шага 2 в шаге 1, за исключением большего радиуса.

...