Введение в DirectX
Рисование плоского треугольника
Сцена и рендеринг являются ключевыми понятиями в Direct3D. Сцена - прямая аналогия любых театральных подмостков, на которых мы видим статические и движущиеся объекты, совершающие различные действия. Все то, что отображается на экране монитора - это и есть сцена. Процесс представления сцены на дисплее носит название рендеринг, благодаря которому происходит визуализация.
Механизм формирования сцены и рендеринг довольно сложный процесс, состоящий из ряда последовательных операций. Он напоминает некий абстрактный конвейер, визуализирующий графику на экране. Проходя через графический конвейер, информация подвергается трем последовательным стадиям преобразования:
- Стадия тесселяции - происходит отбор граней объекта, т.е. разбиение модели на элементарные примитивы, такие как полигоны.
- Стадия геометрических преобразований - включает в себя большой комплекс по преобразованию вершин с помощью матриц, установке материала, расчета освещения объекта. При этом может быть использован фиксированный или программируемый графический конвейер. Фиксированный конвейер использует массу повторяющихся операций по преобразованию объекта. Программируемый конвейер построен на работе с вершинными шейдерами.
- Стадия растеризации - производит представление объекта на пиксельном уровне. Здесь могут применяться пиксельные шейдеры.
После прохождения объектом всех трех стадий готовая модель помещается в буфер кадра и выводится на экран.
Основным объектом, используемым в трехмерной графике, является треугольник. Он же служит элементарным полигоном, с помощью которого можно изображать любые фигуры. Для его рисования нужно сформировать данные, описывающие треугольник, затем вызвать метод рисования.
Управляемый DirectX имеет встроенную конструкцию для обработки треугольников. Существует класс вершин Microsoft.DirectX.Direct3D. CustomVertex, который размещает используемые в Direct3D различные сборки вершин в формате CustomVertex. Структура вершинного формата содержит данные в понятном для Direct3D виде.
На данном этапе будем использовать для нашего треугольника структуру Microsoft.DirectX.Direct3D.CustomVertex. TransformedColored - преобразование цветов. Эта структура сообщает Direct3D, что наш треугольник не требует никаких преобразований, например, вращения и перемещения, поскольку мы будем устанавливать его положение посредством экранных координат. Данная структура включает цветовые параметры для каждой вершины треугольника.
protected override void OnPaint(PaintEventArgs e) { // Очистить цветом клиентскую область формы device.Clear(ClearFlags.Target, System.Drawing.Color.CornflowerBlue, 1.0F, 0); // Содать массив структур преобразованных координат CustomVertex.TransformedColored[] verts = new CustomVertex.TransformedColored[3]; // Задать параметры треугольника verts[0].SetPosition(new Vector4(this.ClientSize.Width / 2.0F, 50.0F, 0.5F, 1.0F)); verts[0].Color = System.Drawing.Color.Aqua.ToArgb(); verts[1].SetPosition(new Vector4(this.ClientSize.Width - this.ClientSize.Width / 5.0F, this.ClientSize.Height - this.ClientSize.Height / 5.0F, 0.5F, 1.0F)); verts[1].Color = System.Drawing.Color.Black.ToArgb(); verts[2].SetPosition(new Vector4(this.ClientSize.Width / 5.0F, this.ClientSize.Height - this.ClientSize.Height / 5.0F, 0.5F, 1.0F)); verts[2].Color = System.Drawing.Color.Purple.ToArgb(); // Сформировать сцену device.BeginScene(); device.VertexFormat = CustomVertex.TransformedColored.Format; device.DrawUserPrimitives(PrimitiveType.TriangleList, 1, verts); device.EndScene(); // Перерисовать device.Present(); // Вызвать обработчики, подписавшиеся на событие Paint // base.OnPaint(e); }Листинг 10.6. Код задания параметров и рисования треугольника в методе
Вначале мы создаем массив структур для хранения трех точек треугольника. Используя структуру Vector4, мы устанавливаем координаты вершин треугольника относительно левого верхнего угла клиентской области формы, а также цвет каждой вершины.
Затем мы применяем методы формирования сцены и рендеринг. Команда BeginScene() уведомляет Direct3D о том, что мы собираемся что-то нарисовать и определяет его готовность к этому. Далее мы сообщаем, что именно хотим нарисовать. Свойство VertexFormat созданного устройства устанавливает режим непрограммируемого конвейера в преобразованном цветном вершинном формате.
Метод DrawUserPrimitives() определяет место, где размещается рисунок. Его парметры означают следующее:
- Первый параметр - это тип примитива, который мы планируем нарисовать. Существуют различные примитивы, которые нам доступны, но сейчас мы используем набор треугольников TriangleList.
- Второй параметр - число примитивов (треугольников), которые мы хотим нарисовать. Оно равно общему числу вершин объекта, разделенному на число вершин примитива. В данном случае один объект с тремя вершинами отображается треугольным примитивом (объект треугольник аппроксимируется примитивом треугольник).
- Третий параметр определяет данные, описывающие отображаемый объект (в данном случае координаты и цвет вершин треугольника).
Последняя команда EndScene() сообщает приложению Direct3D об окончании процедуры рисования. Эта команда должна присутствовать всегда, если использовалась команда BeginScene().
- Постройте приложение и должен получиться такой результат
- Поэкспериментируйте с заданием новых цветов вершин фигуры. Direct3D автоматически меняет градиенты цвета, позволяющие обеспечить цветовой плавный переход от одной вершины к другой.
Если поизменять размеры формы, то можно заметить, что при уменьшении величины окна изображение не перерисовывается. Причина в том, что Windows не рассматиривает уменьшение размера окна как случай, когда необходимо перерисовать целое окно. Она считает, что просто закрылась часть информации, которая была отображена, а остальная часть осталась целой. Для того, чтобы заставить окно перерисовываться непрерывно, даже если оно не разрушено, надо в метод OnPaint() добавить оператор принудительной перерисовки.
-
Добавьте
в самый конец метода OnPaint() вызов метода
this.Invalidate();
наследуемого формой от класса System.Windows.Forms. Control
- Запустите приложение и посокрушайтесь увиденным
Может показаться, что мы сломали приложение, поскольку теперь мы видим главным образом пустой экран и мерцающий на нем треугольник. После каждого нового принудительного перерисовывания окна вызывается новая его перерисовка. То есть сообщение о разрушении окна генерируется непрерывно. Ну и пусть перерисовывается, лишь бы не мерцало. Устраним эффект мерцания изменением стиля окна. Для этого
- Добавьте в конструктор формы следующий код
public Form1() { InitializeComponent(); // Устраняем мерцание окна при бесконечной перерисовке this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true); }Листинг 10.7. Изменение стиля окна в конструкторе формы
В установке стиля формы предполагается, что окно будет игнорировать все внешние сообщения Windows о перерисовке и полное закрашивание будет происходить внутри самого объекта формы, а также, что окно должно быть непрозрачным.
- Запустите приложение и убедитесь, что мерцание прекратилось, хотя окно при этом продолжает бесконечно перерисовываться
- Поизменяйте размеры окна
Мы видим, что при изменении размеров окна треугольник деформируется, поскольку привязан к параметрам окна. Ниже мы построим треугольник в мировых координатах, без привязки к окну, и он будет сохранять свои пропорции при изменении окна.
Создание трехмерного треугольника
Созданное нами приложение не является трехмерным. Оно отображает только плоский цветной треугольник, нарисованный внутри окна. Его можно было бы создать гораздо проще с помощью графического интерфейса GDI (Graphics Device Interface). Но мы хотим создать реалистичный объект в трехмерном пространстве, который с помощью GDI создать невозможно.
Когда мы формировали данные нашего треугольника, мы использовали структуру CustomVertex. TransformedColored, называемую преобразованными координатами (transformed coordinates). Эти координаты лежат в пространстве экрана и легко определяются из свойств формы. Но можно использовать непреобразованные координаты (структура CustomVertex. PositionColored ), которые и описывают наибольшую часть сцены и используются в современных 3D -играх.
Для применения непреобразованных координат нужно позиционировать каждую вершину объекта не в экранных координатах, а в абсолютном пространстве мировых координат ( внешних координат). Можно представить внешнее пространство, как бесконечное трехмерное Декартово пространство, в любом месте которого мы можем размещать наши объекты.