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

Использование Mesh-объектов в DirectX

Аннотация: Создание Mesh-объекта. Добавление материалов и освещения. Использование более реалистичного освещения. Загрузка Mesh-объектов из внешних файлов.

Файлы к лабораторной работе Вы можете скачать здесь.

Для сложных объектов нерационально задавать их координаты и индексы в программном коде. Разумнее с помощью специальных инструментов заранее подготовить данные объекта в отдельном файле, а управление этими данными организуется приложением. Внешний файл с данными графического объекта в управляемом DirectX обычно называют X-файлом по его расширению.

В управляемом DirectX есть класс Microsoft.DirectX.Direct3D.Mesh, который находится в библиотеке Microsoft.Directx.Direct3DX. Этот класс обеспечивает загрузку и управление X-файлами. Программные экземпляры этого класса с загруженными из файлов графическими данными называются Mesh-объектами.

Объекты Mesh могут использоваться для сохранения любого типа графических данных, но в основном используются для формирования сложных моделей. Технология Mesh увеличивает эффективность рендеринга отображаемых объектов за счет встроенных в класс Mesh методов. Все Mesh -объекты имеют вершинный и индексный буферы, а также буфер атрибутов.

Попробуем вначале применить Mesh -объект для рисования 9 вращающихся кубов, чтобы ознакомиться с возможностью его применения. В дальнейшем Mesh -объекты будем использовать для рендеринга более сложных фигур.

Создание заготовки приложения

  • Выберите каталог для размещения нового проекта и создайте пустой проект C# с именем RenderMesh

  • Выполните команду меню Project/Add Reference и добавьте к проекту ссылки на следующие библиотечные сборки .NET
    • System.dll
    • System.Drawing.dll
    • System.Windows.Forms.dll
    • Microsoft.DirectX.dll
    • Microsoft.DirectX.Direct3D.dll
    • Microsoft.Directx.Direct3DX.dll

Примечание. В трех последних сборках выбирайте более свежие версии.

Здесь мы добавили ссылку на новую библиотеку, расширяющую DirectX и содержащую класс Mesh.

  • Добавьте к проекту файл Form3.cs из лабораторной работы №13 - RenderBest, выполнив команду Project/Add Existing Item

  • В панели Solution Explorer переименуйте файл Form3.cs на Form1.cs
  • Вызовите комбинацией клавиш Ctrl-H окно замены, настройте его в соответствии со снимком и замените все вхождения Form3 на Form1 для всего проекта, щелкнув на кнопке Replace All. Точно также выполните замену пространств имен с RenderBest на RenderMesh, чтобы все соответствовало между собой


Обратите внимание, что мы не добавляем в проект using -директиву для новой библиотеки Microsoft.Directx.Direct3DX.dll, потому что она расширяющая и в ней используется пространство имен Microsoft.DirectX.Direct3D, которое уже подключено в нашем проекте.


  • Отключите в приложении консольное окно через команду меню Project/RenderMesh Properties, установив во вкладке Application опцию Output type в значение Windows Application
  • Постройте проект, чтобы убедиться в работоспособности данной заготовки. Результат должен соответствовать варианту Form3 лабораторной работы №13

Теперь мы уберем из полученной заготовки все лишнее, что не понадобится при использовании Mesh -объектов. Учитывая, что Mesh -объект имеет свои встроенные вершинный и индексный буферы и сам определяет свойства формата вершин, удалим соответствующий код из заготовки приложения. Далее мы будем приводить секции кода, выделенные красным цветом, именно их необходимо удалять из заготовки приложения. Для быстрого позиционирования пользуйтесь раскрывающимся списком Members редактора оболочки.

  • Найдите в коде класса Form1 описание ссылочных переменных вершинного и индексного буфера и удалите их
private Device device = null;
    private VertexBuffer vb = null;
    private IndexBuffer ib = null;
Листинг 14.1. Удаление ссылочных переменных вершинного и индексного буфера
  • Отредактируйте функцию InitializeGraphics(), удалив из нее код, связанный с вершинным и индексным буфером
public void InitializeGraphics()
        {
            // Создание объекта и настройка параметров представления
            // Создать объект параметров представления
            PresentParameters presentParams = new PresentParameters();
            // Установить оконный режим
            presentParams.Windowed = true;
            // Сбрасывать содержимое буфера, если он не готов к представлению
            presentParams.SwapEffect = SwapEffect.Discard;
    
            // Настройка буфера глубины для параметров устройства
            presentParams.EnableAutoDepthStencil = true;
            presentParams.AutoDepthStencilFormat =
                Microsoft.DirectX.Direct3D.DepthFormat.D16;
    
            // Создать объект устройства и сохранить ссылку на него
            device = new Device(0, DeviceType.Hardware, this,
                CreateFlags.SoftwareVertexProcessing, presentParams);
    
            // Создать вершинный буфер
            vb = new VertexBuffer(typeof(CustomVertex.PositionColored),
                                  8,
                                  device,
                                  Usage.Dynamic | Usage.WriteOnly,
                                  CustomVertex.PositionColored.Format,
                                  Pool.Default);
    
            // Регистрация события Created вершинного буфера
            vb.Created += new EventHandler(vb_Created);
    
            // Принудительный вызов создания треугольника 
            // и заполнения вершинного буфера при первом 
            // создании формы
            vb_Created(vb, null);
    
            // Создать индексный буфер для координат вершин куба
            ib = new IndexBuffer(typeof(short),
                                 indices.Length,
                                 device,
                                 Usage.WriteOnly,
                                 Pool.Default);
    
            // Регистрация события Created индексного буфера
            // Код написать вручную (для создания обработчика)!!!
            ib.Created += new EventHandler(ib_Created);
    
            // Принудительный вызов обработчика при первом запуске
            ib_Created(ib, null);
        }
Листинг 14.2. Корректировка функции InitializeGraphics()
  • Удалите целиком функцию vb_Created() -обработчик события повторного заполнения вершинного буфера
void vb_Created(object sender, EventArgs e)
        {
            // Определить внутреннюю ссылку на вершинный буфер
            VertexBuffer buffer = (VertexBuffer)sender; // Явное приведение типов
    
            // Создать локальный массив структур непреобразованных координат
            CustomVertex.PositionColored[] verts = 
                new CustomVertex.PositionColored[8];
    
            // Задать параметры вершин куба в соответствии с рисунком
            //
            verts[0] = new CustomVertex.PositionColored(-1.0F, 1.0F, 1.0F, Color.Purple.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.Blue.ToArgb());
            verts[3] = new CustomVertex.PositionColored(1.0F, -1.0F, 1.0F, Color.Yellow.ToArgb());
            verts[4] = new CustomVertex.PositionColored(-1.0F, 1.0F, -1.0F, Color.Gold.ToArgb());
            verts[5] = new CustomVertex.PositionColored(1.0F, 1.0F, -1.0F, Color.Green.ToArgb());
            verts[6] = new CustomVertex.PositionColored(-1.0F, -1.0F, -1.0F, Color.Black.ToArgb());
            verts[7] = new CustomVertex.PositionColored(1.0F, -1.0F, -1.0F, Color.WhiteSmoke.ToArgb());
    
            // Заполнить вершинный буфер данными треугольников
            buffer.SetData(verts, 0, LockFlags.None);
        }
Листинг 14.3. Удаление функции vb_Created()
  • Удалите код создание массива индексов вершин треугольных примитивов
// Определение индексного массива вершин треугольных примитивов
        private static readonly short[] indices = {
            2,0,1,// Задняя грань:    треугольник 2-0-1 (невидимая сторона - обход левый)
            2,1,3,// Задняя грань:    треугольник 2-1-3 (невидимая сторона - обход левый)
            5,6,4,// Передняя грань:  треугольник 5-6-4 (лицевая сторона - обход правый)
            5,7,6,// Передняя грань:  треугольник 5-7-6 (лицевая сторона - обход правый)
            0,5,4,// Верхняя грань:   треугольник 0-5-4 (лицевая сторона - обход правый)
            0,2,5,// Верхняя грань:   треугольник 0-2-5 (лицевая сторона - обход правый)
            1,6,7,// Нижняя грань:    треугольник 1-6-7 (невидимая сторона - обход левый)
            1,7,3,// Нижняя грань:    треугольник 1-7-3 (невидимая сторона - обход левый)
            0,6,1,// Левая грань:     треугольник 0-6-1 (невидимая сторона - обход левый)
            0,4,6,// Левая грань:     треугольник 0-4-6 (невидимая сторона - обход левый)
            2,3,7,// Правая грань:    треугольник 2-3-7 (лицевая сторона - обход правый)
            2,7,5 // Правая грань:    треугольник 2-7-5 (лицевая сторона - обход правый)
    };
Листинг 14.4. Удаление индексного массива вершин треугольных примитивов
  • Удалите функцию ib_Created() -обработчик события повторного заполнения индексного буфера
// Обработчик события повторного заполнения индексного буфера
        void ib_Created(object sender, EventArgs e)
        {
            IndexBuffer buffer = (IndexBuffer)sender;
            buffer.SetData(indices, 0, LockFlags.None);
        }
Листинг 14.5. Удаление обработчика повторного заполнения индексного буфера

Объект Mesh сам следит за восстановлением вершинного, индексного буферов и формата вершин всякий раз, когда объект подвергается рендерингу.

  • Удалите из функции DrawCubes() код рисования трех дополнительных кубов
private void DrawCubes()
        {
            //
            // Средний ряд
            //
            //........................................................
            // Дополнительные кубы
            device.Transform.World = Matrix.RotationYawPitchRoll(
                angle / (float)Math.PI,
                angle / (float)Math.PI * 2.0f,
                angle / (float)Math.PI / 4.0f) *
                Matrix.Translation(
                    0.0f,
                    (float)Math.Cos(angle),
                    (float)Math.Sin(angle));
            device.DrawIndexedPrimitives(
                PrimitiveType.TriangleList, 0, 0, 8, 0, indices.Length / 3);
    
            device.Transform.World = Matrix.RotationYawPitchRoll(
                angle / (float)Math.PI,
                angle / (float)Math.PI / 2.0f,
                angle / (float)Math.PI * 4.0f) *
                Matrix.Translation(
                    4.0f,
                    (float)Math.Sin(angle),
                    (float)Math.Cos(angle));
            device.DrawIndexedPrimitives(
                PrimitiveType.TriangleList, 0, 0, 8, 0, indices.Length / 3);
    
            device.Transform.World = Matrix.RotationYawPitchRoll(
                angle / (float)Math.PI,
                angle / (float)Math.PI * 2.0f,
                angle / (float)Math.PI / 2.0f) *
                Matrix.Translation(
                -4.0f,
                (float)Math.Cos(angle),
                (float)Math.Sin(angle));
            device.DrawIndexedPrimitives(
                PrimitiveType.TriangleList, 0, 0, 8, 0, indices.Length / 3);
    
            if (flagRotate)
                angle += 0.02F;
        }
Листинг 14.6. Удаление кода рисования трех дополнительных кубов
  • Удалите в функции OnPaint() секцию кода, подключающую к устройству вершинный и индексный буферы
protected override void OnPaint(PaintEventArgs e)
        {
            // Очистить цветом клиентскую область формы
            device.Clear(ClearFlags.Target 
                | ClearFlags.ZBuffer,
                System.Drawing.Color.CornflowerBlue,
                1.0F, 0);
    
            // Вызов нашей функции установки камеры
            SetupCamera();
    
            // Сформировать сцену с учетом параметров 
            // "положение-нормаль-цвет"
            device.BeginScene();
            // Установить формат обработки вершин при отображении
            device.VertexFormat = CustomVertex.PositionColored.Format;
            // Нарисовать треугольник по данным из буфера
            device.SetStreamSource(0, vb, 0);
            device.Indices = ib;
            DrawCubes();
            device.EndScene();
    
            // Показать буфер кадра 
            device.Present();
    
            // Принудительно перерисовать
            this.Invalidate();
        }
Листинг 14.7. Удаление из функции OnPaint() подключения буферов vb и ib

Теперь пришла пора добавить код, реализующий Mesh -технологию.

Иван Циферблат
Иван Циферблат
Россия, Таганрог, 36, 2000