Есть ли эффективный \ простой способ нарисовать вогнутый многоугольник в Direct3d

StackOverflow https://stackoverflow.com/questions/91202

  •  01-07-2019
  •  | 
  •  

Вопрос

Я пытаюсь нарисовать многоугольник, используя c # и directx

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

Я могу загрузить точки и нарисовать выпуклую фигуру, используя trianglefan и drawuserprimitives.

Это, очевидно, приводит к неверным результатам, когда многоугольник очень вогнутый (каковым он может быть).

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

Кто-нибудь может указать мне на простой в использовании ресурс \ учебник \ алгоритм, который может мне помочь?

Это было полезно?

Решение

Direct3D может рисовать только треугольники (ну, он также может рисовать линии и точки, но это не главное).Итак, если вы хотите нарисовать любую фигуру, более сложную, чем треугольник, вам нужно нарисовать множество соприкасающихся треугольников, равных этой форме.

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

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

В прошлом я уже пользовался кодом Рэтклиффа;очень простой и хорошо работает.У VTerrain есть мертвая ссылка на него;код можно найти здесь.Это C ++, но перенос его на C # должен быть простым.

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

Другие советы

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

Есть пара кодов, которые могут вам помочь:

Библиотека GPC.Очень проста в использовании, но вам может не понравиться ее лицензия:

http://www.cs.man.ac.uk /~toby/alan/software/gpc.html

Существует также треугольник:

http://www.cs.cmu.edu /~quake/triangle.html

И КУЛАК:

http://www.cosy.sbg.ac.at /~held/projects/triang/triang.html

Другим (и моим предпочтительным) вариантом было бы использовать GLU tesselator.Вы можете загрузить и использовать библиотеку GLU из программ DirectX просто отлично.Для его использования не нужен контекст OpenGL, и он предустановлен на всех компьютерах с Windows.Если вам нужен исходный код, вы можете удалить код триангуляции из эталонной реализации SGI.Я сделал это однажды, и это заняло у меня всего пару часов.

Пока что речь идет о триангуляции.Есть и другой способ:Вы можете использовать трафаретные приемы.

Общий алгоритм выглядит следующим образом:

  1. Отключите запись по цвету и глубине.Включите запись по трафарету и настройте буфер трафарета таким образом, чтобы он инвертировал текущее значение трафарета.Достаточно одного кусочка трафарета.О, ваш буфер трафарета тоже должен быть очищен.

  2. Выберите случайную точку на экране.Подойдет любой.Назовите эту точку своим Якорем.

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

  4. После того как вы нарисуете все эти треугольники, отключите stencil write, включите stencil test и color-write и нарисуйте полноэкранный четырехугольник по вашему выбору.Это заполнит только пиксели внутри вашего выпуклого многоугольника.

Хорошей идеей будет поместить якорь в середину многоугольника и просто нарисовать прямоугольник размером с границу вашего многоугольника.Это немного экономит время заполнения.

Кстати, техника трафарета работает и для самопересекающихся полигонов.

Надеюсь, это поможет, Нильс

Если вы можете использовать буфер трафарета, сделать это будет несложно.Вот общий алгоритм:

Clear the stencil buffer to 1.
Pick an arbitrary vertex v0, probably somewhere near the polygon to reduce floating-point errors.
For each vertex v[i] of the polygon in clockwise order:
    let s be the segment v[i]->v[i+1] (where i+1 will wrap to 0 when the last vertex is reached)
    if v0 is to the "right" of s:
        draw a triangle defined by s, v[i], v[i+1] that adds 1 to the stencil buffer
    else
        draw a triangle defined by s, v[i], v[i+1] that subtracts 1 from the stencil buffer
end for
fill the screen with the desired color/texture, testing for stencil buffer values >= 2.

Под "правом на s" я подразумеваю с точки зрения кого-то, стоящего на v [i] и обращенного лицом к v [i+ 1].Это можно протестировать, используя перекрестный продукт:

крест (v0 - v[i], v[i+1] - v[i]) > 0

Я просто должен был сделать это для проекта.Самый простой алгоритм, который я нашел, называется "Обрезание ушей".Отличная статья об этом есть здесь: TriangulationByEarClipping.pdf

Мне потребовалось около 250 строк кода на c ++ и 4 часа, чтобы реализовать его версию методом перебора.Другие алгоритмы обладают большей производительностью, но этот был прост в реализации и понимании.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top