Опубликован: 13.07.2010 | Уровень: специалист | Доступ: платный
Самостоятельная работа 12:

Рендеринг вращающихся кубов в 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()
  • Постройте приложение и убедитесь, что рисуется вращающийся куб с цветными гранями


Александр Очеретяный
Александр Очеретяный
Украина, Киев
Анастасия Балыбердина
Анастасия Балыбердина
Украина, Киев, НТУУ КПИ