В
XNA Framework, 3D примитив это специальный тип 3D объекта, который
определяет, как графическое устройство интерпретирует вершины в
вершинном буфере. Мы приведем пример, как использовать точки, линии и
треугольники, являющиеся основой рисования на самом низком уровне.
Исходный код примера можно загрузить с сайта Microsoft или с нашего сайта (отличается только русскими комментариями)
Рисуем точки
1. Нужно создать список 3D вершин, которые определяют рисуемые точки.
Следующий код создает 8 точек и сохраняет их в массиве VertexPositionColor[] pointList;
1 2 3 4 5 6 7 8 9 10
pointList =new VertexPositionColor[points]; for(int x =0; x < points /2; x++) { for(int y =0; y <2; y++) { pointList[(x *2)+ y]=new VertexPositionColor( new Vector3(x *100, y *100, 0), Color.White); } }
Визуально точки будут выглядеть так -
На
рисунке показаны 8 точек определяющих 6 треугольников нарисованных на
плоскости Z (z=0). Координаты первой точки = (0,0,0). Камера размещена
в точке (0,0,1) и смотрит на начало координат (0,0,0). Ортогональная
проекция задана двумя точками – верхняя-левая (0,0) и нижняя-правая
(800,600). Кроме этого мы используем дополнительную матрицу
трансформации, которая смещает наши точки к центру экрана. Следующий
код показывает создание 2-ух из 3-ех необходимых нам матриц. 3-яя
матрица (мировая) для смещения точек к центру экрана создается в методе
InitializeEffect()
2. Используя свойство GraphicsDevice.RenderState.PointSize установим размер выводимых точек.
В нашем примере размер равен 10. На экране вы увидите квадратные точки.
GraphicsDevice.RenderState.PointSize = 10;
3. Выводим точки на экран используя функцию
GraphicsDevice.DrawUserPrimitives(..) которая в качестве первого
аргумента принимает тип выводимого примитива - PrimitiveType.PointList.
Тип примитива определяет как данные в переданном массиве вершин будут
интерпретированы и показаны.
1 2 3 4 5
GraphicsDevice.DrawUserPrimitives<VertexPositionColor>( PrimitiveType.PointList, // тип примитива для отрисовки pointList, // массив точек 0, // индекс первой используемой вершины в массиве 8);// количество примитивов (точек)
Рисуем линии
1. В дополнение к списку 3D вершин точек нужно создать массив индексов для нумерации/индексации данных о вершинах.
Нижеприведенный код определяет индексы для серии линий
1 2 3 4 5 6 7 8 9 10
// массив индексов для линий lineListIndices =newshort[(points *2)-2]; // заполняем индексы for(int i =0; i < points -1; i++) { lineListIndices[i *2]=(short)(i); lineListIndices[(i *2)+1]=(short)(i +1); }
Другими словами, данный код равнозначен следующему и определяет
линии соеденяющие наши точки - pointList[0] и pointList[1],
pointList[1] и pointList[2], и так далее 7 линий между 8-ми точек.
2. Выводим линии на экран используя функцию
GraphicsDevice.DrawUserIndexedPrimitives (..) которая в качестве
первого аргумента принимает тип выводимого примитива - PrimitiveType.
LineList
1 2 3 4 5 6 7 8
GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionColor>( PrimitiveType.LineList, // тип примитива для отрисовки pointList, // массив точек 0, // смещение, добавляемое для каждого индекса в индексном буфере 8, // количество вершин lineListIndices, // индексный буфер соеденяющий наши точки по парам 0, // первый используемый индекс 7);// количество примитивов (линий)
Рисуем ленту линий (Line Strip)
1. Для определения ленты из линий нам понадобится новый массив индексов
в котором последовательно будут соеденены точки из массива вершин.
Для ленты нам понадобится в двое меньше индексов так как лента подразумевает последовательно соединенные примитивы (точки).
1 2 3 4 5 6 7 8 9
// массив индексов для линий lineStripIndices =newshort[points]; // заполняем индексы последовательно соеденяя одну точку за другой for(int i =0; i < points; i++) { lineStripIndices[i]=(short)(i); }
2. Выводим ленту линий на экран используя функцию
GraphicsDevice.DrawUserIndexedPrimitives (..) которая в качестве
первого аргумента принимает тип выводимого примитива - PrimitiveType.
LineStrip. Пометка – рисование лент обычно более эффективно чем
рисование списков - с точки зрения производительности, так как индексы
выводимых вершин содержат меньшее количество повторений.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
for(int i =0; i < pointList.Length; i++) pointList[i].Color= Color.Red; GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionColor>( PrimitiveType.LineStrip, // тип примитива для отрисовки pointList, // массив точек 0, // смещение, добавляемое для каждого индекса в индексном буфере 8, // количество вершин для отрисовки lineStripIndices, // массив индесов (последовательность точек) 0, // первый используемый индекс 7);// количество примитивов (линий) for(int i =0; i < pointList.Length; i++) pointList[i].Color= Color.White;
В этом примере мы сначала устанавливаем цвет точек в красный и
затем рисуем, после чего меняем цвет точек обратно. Ленты рисуются
красным цветом, а списки цветом по умолчанию – белым.
Рисуем треугольники
1. Создаем новый массив индексов, в котором будет пронумерованный
список треугольников, по 3 вершины на один треугольник. Массив вершин
не меняем.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
triangleListIndices =newshort[(width -1)*(height -1)*6]; for(int x =0; x < width -1; x++) { for(int y =0; y < height -1; y++) { triangleListIndices[(x + y *(width -1))*6]=(short)(2* x); triangleListIndices[(x + y *(width -1))*6+1]=(short)(2* x +1); triangleListIndices[(x + y *(width -1))*6+2]=(short)(2* x +2); triangleListIndices[(x + y *(width -1))*6+3]=(short)(2* x +2); triangleListIndices[(x + y *(width -1))*6+4]=(short)(2* x +1); triangleListIndices[(x + y *(width -1))*6+5]=(short)(2* x +3); } }
Этот код индексирует вершины так что каждые 3 точки у нас
образуют один треугольник, причем в каждом треугольнике есть общие
вершины с соседним. Ниже аналог этого кода –
2. Выводим список треугольников на экран используя функцию
GraphicsDevice.DrawUserIndexedPrimitives (..) которая в качестве
первого аргумента принимает тип выводимого примитива -
PrimitiveType.TriangleList
1 2 3 4 5 6 7 8 9
GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionColor>( PrimitiveType.TriangleList, // тип примитива для отрисовки pointList, // массив точек 0, // смещение, добавляемое для каждого индекса в индексном буфере 8, // количество вершин для отрисовки triangleListIndices, // массив индесов 0, // первый используемый индекс 6);// количество примитивов (треугольников)
Рисуем ленту из треугольников (TriangleStrip)
1. Для ленты из треугольников мы так же используем наш старый массив
вершин но создаем новый массив индексов в котором будут последовательно
соеденены точки в треугольники.
1 2 3 4 5 6 7 8
// массив индексов для треугольников triangleStripIndices =newshort[points]; // заполняем индексы for(int i =0; i < points; i++) { triangleStripIndices[i]=(short)i; }
В лентах, треугольники полседовательно соеденены между собой,
так что индесов нам нужно меньше – каждый полседующий треугольник
использыет две вершины предидущего треугольника. Это самый эффетивный
способ вывда треугольников.
2. Выводим ленту треугольников на экран используя функцию
GraphicsDevice.DrawUserIndexedPrimitives (..) которая в качестве
первого аргумента принимает тип выводимого примитива -
PrimitiveType.TriangleStrip
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
for(int i =0; i < pointList.Length; i++) pointList[i].Color= Color.Red; GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionColor>( PrimitiveType.TriangleStrip, // тип примитива для отрисовки pointList, // массив точек 0, // смещение, добавляемое для каждого индекса в индексном буфере 8, // количество вершин для отрисовки triangleStripIndices, // массив индесов 0, // первый используемый индекс 6);// количество примитивов (треугольников) for(int i =0; i < pointList.Length; i++) pointList[i].Color= Color.White;
В этом коде мы так же с начала меняем цвет вершин перед отрисовкой.
В заключение приведем схему индексации различных примитивов (еще называют топологией примитивов)