2016-05-06 15 views
10

Мне нужно нарисовать список фигур, и я использую Direct2D. Я получаю список фигур из файла. Список сортируется, и порядок элементов внутри файла представляет порядок, в котором будут нарисованы эти фигуры. Итак, если, например, файл указывает два прямоугольника в одном и том же положении и с одинаковыми размерами, будет видна только вторая (поскольку первая будет перезаписана).Direct2D Depth Buffer

Учитывая мой список форм я proceede его чертеж следующим образом:

list<Shape> shapes; 

for (const auto& shape : shapes) 
    shape.draw(); 

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

Я прочитал, что Direct3D поддерживает буфер глубины (или z-buffer), который задает для каждого пикселя его z-координату, так что будут рисоваться только «видимые» пиксели (ближе к зрителю), независимо от порядка, в котором фигуры рисуются. И когда я читаю файл, у меня есть информация о глубине каждой фигуры.

Есть ли способ использовать буфер глубины в Direct2D или подобный метод, который позволяет мне использовать несколько потоков для рисования моих фигур?

+0

Я не уверен непосредственно в 'Direct2D', но обычно вы назначаете форму' z', сортируете по этой координате и затем визуализируете соответственно, тем самым реализуя простой Z-буфер. – rhughes

+2

@rhughes Мне не нужно их сортировать, так как они уже отсортированы, когда я читаю файл. Кроме того, использование этого метода предотвращает использование нескольких потоков. – Nick

+0

Я имею в виду сортировку по z-координате. Вам не нужно отображать их на отдельных потоках. Сначала визуализируйте фигуру с наименьшим z-cood, а затем проделайте свой путь к фигуре с наивысшим z-координатом. – rhughes

ответ

4

Есть ли способ использовать глубину буфер в Direct2D или аналогичный метод , который позволяет мне использовать несколько потоков для рисования фигур ?

Ответ здесь нет. Хотя библиотека Direct2D построена поверх Direct3D, она не предоставляет пользователю такую ​​функцию через API, поскольку примитивы, которые вы можете рисовать, описываются только двумерными координатами.Последний примитив, который вы рисуете для цели рендеринга, становится видимым, поэтому не проводится глубокое тестирование. Кроме того, буфер глубины в Direct3D не имеет большого отношения к многопоточности на стороне процессора.

Также обратите внимание, что даже если вы выдаете команды рисования с использованием нескольких потоков, они будут сериализованы драйвером Direct3D и выполняться последовательно. Некоторые новые графические API, такие как Direct3D 12 и Vulkan, предоставляют многопоточные драйверы, которые позволяют эффективно использовать различный контент из разных потоков, но они имеют более высокую сложность.

Итак, в конце концов, если вы придерживаетесь Direct2D, у вас останется возможность рисовать каждую фигуру последовательно с помощью одного потока.

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

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

Следующий код следует рассматривать как псевдокод, он предназначен только для демонстрации идеи.

#define RECTANGLE 0 
#define TEXT  1 
#define TRIANGLE 2 
//etc 

typedef struct { 
    int type; //We have a type field 
    Rect bounds_rect; //Bounds rect 
    Rect coordinates; //Coordinates, which count vary according to shape type 
    //Probably you have many other fields here 
} Shape; 

//We have all shapes in a vector 
std::vector<Shape> shapes; 

Итерация всех форм.

for (int i=1; i<shapes.size; i++) { 
    if(shape[i].type != RECTANGLE) { 
    //We will not perform testing if the current shape is not rectangle. 
    continue; 
    } 

    for(int j=0; j<i; j++) { 
    if(isOccluded(&shape[j], &shape[i])) { 
     //shape[j] is totally invisible, so remove it from 'shapes' list 
    } 
    } 
} 

тестирование Occlusion что-то вроде этого

bool isOccluded(Shape *a, Shape *b) { 
    return (a.bounds_rect.left > b.coordinates.left && a.bounds_rect.right < b.coordinates.right && 
      a.bounds_rect.top > b.coordinates.to && a.bounds_rect.bottom < b.coordinates.bottom); 
} 

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

0

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

Я не слышал об использовании буфера глубины в D2D, поскольку он несколько бессмыслен; все нарисовано на одну плоскость в D2D, как может быть что-то впереди или за чем-то еще? API может поддержать его, но я сомневаюсь в этом, поскольку он не имеет абстрактного смысла. Глубина информация по каждой форме это только для того, чтобы сделать его по существу в которой у вас уже есть

Вместо того, что вы могли бы сделать, разделить и выделить ваши формы для ваших потоков, сохраняя при этом порядок, т.е.

t1 { shape1, shape2, shape3 } = shape123 
t2 { shape4, shape5, shape6 } = shape456 
... 

И нарисуйте фигуры на новый объект (но не на backbuffer), в зависимости от вашего класса формы вы, возможно, сможете представить результат как форму. Это оставит вас с t различными формами, которые все еще в порядке, но были вычислены параллельно. Вы можете затем постепенно составить свой окончательный результат, опираясь на результатах в порядке, то есть

t1 { shape123, shape456, shape789 } 
t2 { shape101112, shape131415 } 

t1 { shape123456789, shape101112131415 } = final shape 

Теперь у вас есть окончательная форма, вы можете просто нарисовать, что как обычный

+0

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

+0

Вы можете нарисовать каждую «сформованную форму» на объект текстуры, а затем объединить текстуры, как показано выше, с конечным результатом на квадрат, это позволит вам представить любой примитив (будь то текст или геометрия или даже другие изображения) в общей форме , Это может потребовать некоторого вникания в d3d, однако я не уверен, однако обширный d2d – Madden