· Гостей: 1
· Пользователей: 0
· Всего пользователей: 7,142
· Новый пользователь: Sarahseato
|
|
|
Урок 8. Как рисовать точки, линии и другие 3D примитивы |
|
Урок 8. Как рисовать точки, линии и другие 3D примитивы.
В этом уроке мы рассмотрим, как можно нарисовать простейшие примитивы (точки, линии, треугольники). Это дословный перевод статьи из MSDN - How To: Draw Points, Lines, and Other 3D Primitives.
В XNA Framework, 3D примитив это специальный тип 3D объекта, который определяет, как графическое устройство интерпретирует вершины в вершинном буфере. Мы приведем пример, как использовать точки, линии и треугольники, являющиеся основой рисования на самом низком уровне.
Пометка – для простейшей отрисовки примитивов, кроме координат, вам необходимо создать экземпляр объекта BasicEffect а так же несколько матриц трансформации. Ссылки по теме - How To: Use BasicEffect, и на нашем сайте - Как рисовать простые 3D-объекты с помощью BasicEffect.
Исходный код примера можно загрузить с сайта 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()
1
2
3
4
5
6
7
8
9
10
11
12
|
viewMatrix = Matrix.CreateLookAt(
new Vector3(0.0f, 0.0f, 1.0f),
Vector3.Zero,
Vector3.Up
);
projectionMatrix = Matrix.CreateOrthographicOffCenter(
0,
(float)GraphicsDevice.Viewport.Width,
(float)GraphicsDevice.Viewport.Height,
0,
1.0f, 1000.0f);
|
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 = new short[(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-ми точек.
lineListIndices = new short[14]{ 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7 };
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 = new short[points];
// заполняем индексы последовательно соеденяя одну точку за другой
for (int i = 0; i < points; i++)
{
lineStripIndices[i] = (short)(i);
}
|
Или так –
lineStripIndices = new short[8]{ 0, 1, 2, 3, 4, 5, 6, 7 };
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 = new short[(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 точки у нас образуют один треугольник, причем в каждом треугольнике есть общие вершины с соседним. Ниже аналог этого кода –
triangleListIndices = new short[18]{ 0, 1, 2, 2, 1, 3, 2, 3, 4, 4, 3, 5, 4, 5, 6, 6, 5, 7 };
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 = new short[points];
// заполняем индексы
for (int i = 0; i < points; i++)
{
triangleStripIndices[i] = (short)i;
}
|
В лентах, треугольники полседовательно соеденены между собой, так что индесов нам нужно меньше – каждый полседующий треугольник использыет две вершины предидущего треугольника. Это самый эффетивный способ вывда треугольников.
Аналог кода создания индексов –
triangleStripIndices = new short[8]{ 0, 1, 2, 3, 4, 5, 6, 7 };
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;
|
В этом коде мы так же с начала меняем цвет вершин перед отрисовкой.
В заключение приведем схему индексации различных примитивов (еще называют топологией примитивов)
|
Пожалуйста, залогиньтесь для добавления комментария.
|
|
|
Забыли пароль? Запросите новый здесь.
|
Вы должны авторизироваться, чтобы добавить сообщение.
|
|