netlib.narod.ru | < Назад | Оглавление | Далее > |
Весь код, написанный нами до сих пор, занимался визуализацией примитивов одного типа, называемого список треугольников. Однако, есть и другие типы примитивов, которые мы можем рисовать. Все они описаны в приведенном ниже списке:
PointList — название говорит само за себя, данные будут визуализироваться как набор точек (рис. 4.1). Этот тип нельзя использовать при рисовании индексируемых примитивов (об этом мы поговорим чуть позже).
Рис. 4.1. Список точек
LineList — визуализирует каждую пару вершин как отдельную линию (рис. 4.2). При использовании этого типа примитивов вы должны передать четное количество вершин (как минимум, две).
Рис. 4.2. Список линий
LineStrip — Визуализирует вершины как одну ломаную линию (рис. 4.3). После первого сегмента линии, для рисования которого используются две первые вершины, каждый последующий сегмент рисуется путем соединения конечной точки предыдущего сегмента со следующей в списке вершиной. Для данного типа примитива вы должны передать не менее двух вершин.
Рис. 4.3. Ломаная линия
TriangleList — это тот тип примитивов, который мы использовали до сих пор. Каждая группа из трех вершин визуализируется как отдельный изолированный треугольник (рис. 4.4). Отбрасывание невидимых граней управляется через режимы визуализации.
Рис. 4.4. Набор треугольников
TriangleStrip — Полоса треугольников, в которой каждый треугольник после первого рисуется с использованием двух вершин предыдущего треугольника и одной новой (рис. 4.5). Режим отбрасывания невидимых граней автоматически меняется на противоположный для всех четных треугольников. Причина этого в том, что треугольник использует две вершины предыдущего, из-за чего порядок обхода вершин изменяется на противоположный. Данный тип примитивов наиболее часто используется для сложных трехмерных объектов.
Рис. 4.5. Полоса треугольников
TriangleFan — Веер треугольников во многом похож на полосу треугольников, но каждый треугольник использует одну и ту же начальную вершину (рис. 4.6).
Рис. 4.6. Веер треугольников
Мы можем использовать одни и те же данные вершин для рисования любого типа примитивов. Direct3D будет по разному интерпретировать данные вершин в зависимости от того, какой тип примитива мы указали при рисовании. Давайте быстро напишем фрагмент кода, рисующий различные типы примитивов.
Находящийся на CD-ROM пример является прямым наследником первого примера работы с буфером вершин, который мы создали в главе 3. Здесь мы отметим сделанные в коде изменения. Поскольку данный код не предусматривает перемещения вершин, из метода SetupCamera убрано мировое преобразование и все ссылки на закрытую переменную angle. Добавлена следующая константа:
private const int NumberItems = 12;
Число 12 было выбрано произвольно, но с учетом ряда ограничений. Большое количество вершин загромождает экран; при этом нам надо, чтобы количество вершин было четным и делилось на три. Это требуется для корректного рисования типов примитивов LineList и TriangleList. Затем мы модифицируем код создания буфера вершин и функцию OnVertexBufferCreate, как показано в листинге 4.1.
vb = new VertexBuffer(typeof(CustomVertex.PositionColored), NumberItems, device, Usage.Dynamic | Usage.WriteOnly, CustomVertex.PositionColored.Format, Pool.Default); // Создание списка вершин для заданного количества элементов CustomVertex.PositionColored[] verts = new CustomVertex.PositionColored[NumberItems]; // Выбор случайного местоположения вершины в радиусе 5 единиц. for(int i = 0; i < NumberItems; i++) { float xPos = (float)(Rnd.NextDouble() * 5.0f) - (float)(Rnd.NextDouble() * 5.0f); float yPos = (float)(Rnd.NextDouble() * 5.0f) - (float)(Rnd.NextDouble() * 5.0f); float zPos = (float)(Rnd.NextDouble() * 5.0f) - (float)(Rnd.NextDouble() * 5.0f); verts[i].Position = new Vector3(xPos, yPos, zPos); verts[i].Color = RandomColor.ToArgb(); } buffer.SetData(verts, 0, LockFlags.None);
Здесь нет ничего волшебного. Мы модифицировали наш буфер вершин, чтобы в нем хранилось необходимое количество вершин (заданное нашей константой NumberItems). Мы также изменили функцию создания вершин, чтобы она формировала заданное количество размещенных случайным образом вершин. Определения Rnd и RandomColor вы найдете в полном исходном коде примера на CD-ROM.
Теперь надо изменить вызов функции рисования. Проще всего показать различие между разными типами примитивов — написать код, который будет показывать все их один за другим. Давайте сделаем так, чтобы каждый тип примитива код показывал две секунды. Для этого проще всего проверять текущее время и сравнивать его со временем запуска. Добавьте в раздел объявлений следующие переменные:
private bool needRecreate = false; // Информация о времени private static readonly int InitialTickCount = System.Environment.TickCount;
Логическая переменная позволяет заново создавать наш буфер вершин в начале каждого «цикла», чтобы не рассматривать снова и снова одни и те же вершины. Замените в коде единственный вызов DrawPrimitive на содержимое листинга 4.2.
// Решаем, какой тип примитивов рисовать int index = ((System.Environment.TickCount - InitialTickCount) / 2000) % 6; switch (index) { case 0: // Точки device.DrawPrimitives(PrimitiveType.PointList, 0, NumberItems); if (needRecreate) { // После рисования примитивов создаем новый набор OnVertexBufferCreate(vb, null); needRecreate = false; } break; case 1: // Список линий device.DrawPrimitives(PrimitiveType.LineList, 0, NumberItems / 2); needRecreate = true; break; case 2: // Ломаная линия device.DrawPrimitives(PrimitiveType.LineStrip, 0, NumberItems - 1); break; case 3: // Список треугольников device.DrawPrimitives(PrimitiveType.TriangleList, 0, NumberItems / 3); break; case 4: // Полоса треугольников device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, NumberItems - 2); break; case 5: // Веер треугольников device.DrawPrimitives(PrimitiveType.TriangleFan, 0, NumberItems - 2); break; }
Этот фрагмент кода самодокументируемый. В зависимости от того, какой именно тип примитива нам нужен в данном цикле, мы вызываем DrawPrimitives с указанием соответствующего типа. Обратите внимание, что для списка точек мы просто используем в качестве счетчика примитивов количество вершин, рисуя одну точку для каждой вершины. LineList и TriangleList рисуют изолированные примитивы, поэтому в вызове DrawPrimitives для этих типов указывается количество вершин, деленое на число вершин в отдельном примитиве данного типа: две или три, соответственно. В примитиве LineStrip каждая вершина, кроме первой, используется как начальная точка и как конечная точка предыдущей линии, поэтому количество рисуемых примитивов на единицу меньше количества вершин. TriangleStrip и TriangleFan ведут себя также, но поскольку в треугольнике три вершины, две из которых используются совместно со следующим примитивом, из количества вершин мы вычитаем два.
Запущенное приложение сначала покажет вам набор визуализированных точек, а следом — несколько изолированных линий. Затем эти линии будут соединены в одну ломаную линию, а потом превратятся в набор изолированных треугольников. И, наконец, треугольники станут совместно использовать вершины, превратившись сначала в полосу, а потом в веер. Вы можете заметить, что «точки» маленькие и их трудно увидеть. Вы можете искусственно «масштабировать» точки, установив режим визуализации. Добавьте к вашей функции SetupCamera следующую строку, чтобы каждая точка была увеличена в три раза по сравнению с ее обычным размером:
device.RenderState.PointSize = 3.0f;
Вы увидите, что точки стали крупнее, чем вначале. Можете поэкспериментировать с этим режимом визуализации. Теперь, когда мы научились корректно рисовать различные типы примитивов, давайте исследуем способ уменьшения объема памяти, занимаемого нашими данными.
netlib.narod.ru | < Назад | Оглавление | Далее > |