Украина, Киев |
Рендеринг вращающихся кубов в DirectX
Создание вращающегося куба
Смоделируем куб, показанный на рисунке
У нашего куба будет 6 граней. Для представления каждой грани двумя треугольниками потребуется всего 12 треугольников, каждый из которых будет описываться 3 вершинами. Итого, для полного описания куба нужно задать координаты 36 вершин для аппроксимирующих треугольников.
- В панели Solution Explorer вызовите контекстное меню для файла Form1.cs и выполните команду View Code
- В верхней части рабочей области редактора раскройте правый список Members и позиционируйтесь на функции vb_Created(), которую перепишите следующим образом
void vb_Created(object sender, EventArgs e) { // Определить внутреннюю ссылку на вершинный буфер VertexBuffer buffer = (VertexBuffer)sender; // Явное приведение типов // Создать локальный массив структур непреобразованных координат CustomVertex.PositionColored[] verts = new CustomVertex.PositionColored[36]; // Задать параметры аппроксимирующих треугольников // Порядок обхода вершин для лицевой стороны правый // (по часовой стрелке), для невидимой - левый // // Задняя грань: треугольник 2-0-1 (невидимая сторона - обход левый) verts[0] = new CustomVertex.PositionColored(1.0F, 1.0F, 1.0F, Color.Red.ToArgb()); verts[1] = new CustomVertex.PositionColored(-1.0F, 1.0F, 1.0F, Color.Red.ToArgb()); verts[2] = new CustomVertex.PositionColored(-1.0F, -1.0F, 1.0F, Color.Red.ToArgb()); // Задняя грань: треугольник 2-1-3 (невидимая сторона - обход левый) verts[3] = new CustomVertex.PositionColored(1.0F, 1.0F, 1.0F, Color.Red.ToArgb()); verts[4] = new CustomVertex.PositionColored(-1.0F, -1.0F, 1.0F, Color.Red.ToArgb()); verts[5] = new CustomVertex.PositionColored(1.0F, -1.0F, 1.0F, Color.Red.ToArgb()); // // Передняя грань: треугольник 5-6-4 (лицевая сторона - обход правый) verts[6] = new CustomVertex.PositionColored(1.0F, 1.0F, -1.0F, Color.Blue.ToArgb()); verts[7] = new CustomVertex.PositionColored(-1.0F, -1.0F, -1.0F, Color.Blue.ToArgb()); verts[8] = new CustomVertex.PositionColored(-1.0F, 1.0F, -1.0F, Color.Blue.ToArgb()); // Передняя грань: треугольник 5-7-6 (лицевая сторона - обход правый) verts[9] = new CustomVertex.PositionColored(1.0F, 1.0F, -1.0F, Color.Blue.ToArgb()); verts[10] = new CustomVertex.PositionColored(1.0F, -1.0F, -1.0F, Color.Blue.ToArgb()); verts[11] = new CustomVertex.PositionColored(-1.0F, -1.0F, -1.0F, Color.Blue.ToArgb()); // // Верхняя грань: треугольник 0-5-4 (лицевая сторона - обход правый) verts[12] = new CustomVertex.PositionColored(-1.0F, 1.0F, 1.0F, Color.Yellow.ToArgb()); verts[13] = new CustomVertex.PositionColored(1.0F, 1.0F, -1.0F, Color.Yellow.ToArgb()); verts[14] = new CustomVertex.PositionColored(-1.0F, 1.0F, -1.0F, Color.Yellow.ToArgb()); // Верхняя грань: треугольник 0-2-5 (лицевая сторона - обход правый) verts[15] = new CustomVertex.PositionColored(-1.0F, 1.0F, 1.0F, Color.Yellow.ToArgb()); verts[16] = new CustomVertex.PositionColored(1.0F, 1.0F, 1.0F, Color.Yellow.ToArgb()); verts[17] = new CustomVertex.PositionColored(1.0F, 1.0F, -1.0F, Color.Yellow.ToArgb()); // // Нижняя грань: треугольник 1-6-7 (невидимая сторона - обход левый) verts[18] = new CustomVertex.PositionColored(-1.0F, -1.0F, 1.0F, Color.Black.ToArgb()); verts[19] = new CustomVertex.PositionColored(-1.0F, -1.0F, -1.0F, Color.Black.ToArgb()); verts[20] = new CustomVertex.PositionColored(1.0F, -1.0F, -1.0F, Color.Black.ToArgb()); // Нижняя грань: треугольник 1-7-3 (невидимая сторона - обход левый) verts[21] = new CustomVertex.PositionColored(-1.0F, -1.0F, 1.0F, Color.Black.ToArgb()); verts[22] = new CustomVertex.PositionColored(1.0F, -1.0F, -1.0F, Color.Black.ToArgb()); verts[23] = new CustomVertex.PositionColored(1.0F, -1.0F, 1.0F, Color.Black.ToArgb()); // // Левая грань: треугольник 0-6-1 (невидимая сторона - обход левый) verts[24] = new CustomVertex.PositionColored(-1.0F, 1.0F, 1.0F, Color.Gray.ToArgb()); verts[25] = new CustomVertex.PositionColored(-1.0F, -1.0F, -1.0F, Color.Gray.ToArgb()); verts[26] = new CustomVertex.PositionColored(-1.0F, -1.0F, 1.0F, Color.Gray.ToArgb()); // Левая грань: треугольник 0-4-6 (невидимая сторона - обход левый) verts[27] = new CustomVertex.PositionColored(-1.0F, 1.0F, 1.0F, Color.Gray.ToArgb()); verts[28] = new CustomVertex.PositionColored(-1.0F, 1.0F, -1.0F, Color.Gray.ToArgb()); verts[29] = new CustomVertex.PositionColored(-1.0F, -1.0F, -1.0F, Color.Gray.ToArgb()); // // Правая грань: треугольник 2-3-7 (лицевая сторона - обход правый) verts[30] = new CustomVertex.PositionColored(1.0F, 1.0F, 1.0F, Color.Green.ToArgb()); verts[31] = new CustomVertex.PositionColored(1.0F, -1.0F, 1.0F, Color.Green.ToArgb()); verts[32] = new CustomVertex.PositionColored(1.0F, -1.0F, -1.0F, Color.Green.ToArgb()); // Правая грань: треугольник 2-7-5 (лицевая сторона - обход правый) verts[33] = new CustomVertex.PositionColored(1.0F, 1.0F, 1.0F, Color.Green.ToArgb()); verts[34] = new CustomVertex.PositionColored(1.0F, -1.0F, -1.0F, Color.Green.ToArgb()); verts[35] = new CustomVertex.PositionColored(1.0F, 1.0F, -1.0F, Color.Green.ToArgb()); // Заполнить вершинный буфер данными треугольников buffer.SetData(verts, 0, LockFlags.None); }Листинг 12.3. Задание вершин аппроксимирующих треугольников в функции vb_Created()
Координаты вершин треугольников заданы в соответствии с рисунком. Теперь нужно привести в соответствие новой задачи и остальной код программы.
- Через раскрывающийся список Members найдите в функции InitializeGraphics() код создания вершинного буфера и измените количество вершин аппроксимирующих треугольников с 3 на 36
// Создать вершинный буфер vb = new VertexBuffer(typeof(CustomVertex.PositionColored), 36, device, Usage.Dynamic | Usage.WriteOnly, CustomVertex.PositionColored.Format, Pool.Default);Листинг 12.4. Изменить количество вершин в вершинном буфере
Мы моделируем объемную фигуру и нам не нужно делать видимой обратную сторону каждой плоской грани, как это было с треугольником, поэтому отключим эту возможность Direct3D.
- Найдите функцию SetupCamera() и закомментируйте в ней следующий код
// Не скрывать обратную сторону плоской фигуры // device.RenderState.CullMode = Cull.None;Листинг 12.5. Скрывать по умолчанию обратную сторону каждой грани куба
Изменим характер вращения куба, чтобы получить более эффективную картинку.
- Найдите в конце функции SetupCamera() секцию кода преобразования координат объекта и замените его на следующую
// Преобразование пространства для произвольных поворотов /* device.Transform.World = Matrix.RotationAxis( new Vector3(angle / ((float)Math.PI * 2.0F), angle / ((float)Math.PI * 4.0F), angle / ((float)Math.PI * 6.0F)), angle / (float)Math.PI); */ device.Transform.World = Matrix.RotationYawPitchRoll( angle / (float)Math.PI, angle / (float)Math.PI * 2.0F, angle / (float)Math.PI); angle += 0.1F;Листинг 12.6. Изменяем характер вращения куба в функции SetupCamera()
Здесь мы применили для поворота куба статический метод RotationYawPitchRoll() структуры Microsoft.DirectX.Matrix
RotationYawPitchRoll(float yaw, float pitch, float roll)
где yaw -отклонение, pitch -шаг, roll -поворот.
Мы рисуем в данном приложении 12 примитивов-треугольников, поэтому нужно установить это количество в функции рисования DrawPrimitives() устройства.
- Найдите в методе OnPaint() секцию кода " Сформировать сцену..." и установите в ней нужную размерность примитивов рисования
// Сформировать сцену с учетом параметров // "положение-нормаль-цвет" device.BeginScene(); // Установить формат обработки вершин при отображении device.VertexFormat = CustomVertex.PositionColored.Format; // Нарисовать треугольник по данным из буфера device.SetStreamSource(0, vb, 0); device.DrawPrimitives(PrimitiveType.TriangleList, 0, 12); device.EndScene();Листинг 12.7. Новое количество отображаемых треугольных примитивов в функции OnPaint()
- Постройте приложение и убедитесь, что рисуется вращающийся куб с цветными гранями