Файлы к лабораторной работе Вы можете скачать здесь.
Библиотека классов является расширением базовой
библиотеки . и представляет собой новую поддержку
современной технологии программирования, разработанной
DirectX DirectX DirectX 9.0 SDK Update ( Summer
2003 )
от Microsoft содержит большой набор готовых интерфейсов,
классов, функций, предоставляет возможность программисту разрабатывать
приложения, осуществляющие работу со звуком, сетью, трехмерной
графикой, видео и построен в виде набора компонентов. Все
компоненты пакета распределены по пространствам имен
| Пространство имен | Пояснения |
|---|---|
Microsoft. |
|
Microsoft. |
DirectDraw3D API объемная графика, также как вспомогательная
библиотека D3DX. |
Microsoft. |
Графика
позволяет рисовать на экране двухмерную графику, однако
этот компонент давно не обновлялся и его текущая версия
числится под номером 7 (,
который тоже может рисовать двухмерную графику. |
Microsoft. |
Обеспечивает работу приложения с сетью и основан на
своем |
Microsoft. |
Отвечают за музыку и звук, делая возможным воспроизведение
|
Microsoft. |
Пользовательский вход в DirectInput API. DirectInput обеспечивает
взаимодействие программы с устройствами ввода, а именно
с клавиатурой, мышью, джойстиком и рулем. Он обеспечивает
максимально возможную скорость в играх, работая напрямую
с аппаратным обеспечением компьютера в обход сервисов
операционной системы. Стандартные средства DirectInput, поскольку
заложенного в него потенциала хватит на несколько ближайших
лет. |
Microsoft. |
API простого звукового и видео воспроизведения. |
Microsoft. |
Простая диагностика API. |
Microsoft. |
|
Microsoft. |
Классы разрешения для |
Устанавливаемый пакет является расширением среды разработчика
(, поэтому прежде всего на вашем
компьютере должна быть эта среда.
Вставте
диск с пакетом DirectX и запустите программу
Выполните
пункт Install DirectX 9.0 SDK
Следуйте
инструкциям мастера установкиПакет установки возьмите у преподавателя или купите на рынке.
Далее мы будем создавать приложение на основе управляемого ( Managed
).
Выберите
папку размещения файлов проекта и создайте проект C# с
именем SimpleMedia
Удалите
ссылки на ненужные нам на данном этапе библиотеки
Используя
меню Project , выполните команду Add
Reference и добавьте
к проекту нужные нам ссылки на сборки пакета DirectX 
Откройте
файл Form1.cs в режиме View Code,
добавьте в начало файла ссылки на пространства имен только
что добавленных библиотек и закомментируйте ссылки на System.Data и System.Text//using System.Data;
//using System.Text;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
namespace SimpleMedia
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
}
Последний пункт действий является необязательным, но позволяет не классифицировать каждый раз объекты перед их использованием полными именами с префиксами пространств имен.
Для рисования графики на форме мы будем использовать компоненты,
расположенные в пространстве имен Microsoft.

Непосредственное выполнение всех графических операций осуществляется
классом (устройство). Условно можно представить, что
для программиста этот класс аналогичен графическому устройству
и
Существуют три перегруженных версии Microsoft.
public Device ( System.IntPtr lp )public Device ( System.Int32 adapter , Microsoft.DirectX .Direct3D .DeviceType deviceType, System.Windows.Forms.Control renderWindow, Microsoft.DirectX .Direct3D .CreateFlags behaviorFlags, Microsoft.DirectX .Direct3D .PresentParameters presentationParameters )public Device ( System.Int32 adapter ,
Microsoft.DirectX .Direct3D .DeviceType deviceType ,
System.IntPtr renderWindowHandle ,
Microsoft.DirectX .Direct3D .CreateFlags behaviorFlags ,
Microsoft.DirectX .Direct3D .PresentParameters presentationParameters )Пока мы будем использовать только вторую версию конструктора. Рассмотрим параметры этого конструктора:
adapter -
относится к тому физическому устройству, которое мы
хотим классифицировать. Каждое устройство в компьютере
имеет идентификатор adapter подразумевает установку устройства
по умолчанию.deviceType (тип устройства)
- сообщает приложению, какой тип устройства мы хотим создать.
Значением этого параметра является одно из полей структуры Microsoft.DirectX .Direct3D .DeviceTypeMicrosoft.DirectX .Direct3D .DeviceType.Hardware Microsoft.DirectX .Direct3D .DeviceType.Reference Microsoft.DirectX .Direct3D .DeviceType.SoftwareDeviceType.Hardware ,
подразумевающая использование аппаратного устройства.
Опция DeviceType.Reference позволяет
использовать дополнительное или эмулированное устройство
Direct3D
Realtime, но работающее чрезвычайно медленно. Эту опцию целесообразно
использовать для отладки программ или для проверки параметров
приложений, не поддерживаемых видеокартой разработчика.
Опция DeviceType.Software позволяет
использовать программный renderWindow связывает
окно с созданным устройством, назначая его в качестве окна рендеринга (выдачи
результата). Для этого параметра можно использовать форму,
панель или любой другой производный от класса Control класс.
На данном этапе мы будем использовать только формы.behaviorFlags (флажки
режимов) - используется для управления режимами устройства
после его создания. Может комбинироваться операцией поразрядного
сложения "|",
что позволяет установить множественные режимы работы устройства.
Некоторые из этих флажков являются взаимоисключающими.
Значения параметра определяются перечислением Microsoft.DirectX .Direct3D . CreateFlags:Microsoft.DirectX .Direct3D .CreateFlags.AdapterGroupDeviceMicrosoft.DirectX .Direct3D .CreateFlags.DisableDriverManagementMicrosoft.DirectX .Direct3D .CreateFlags.FpuPreserveMicrosoft.DirectX .Direct3D .CreateFlags.HardwareVertexProcessingMicrosoft.DirectX .Direct3D .CreateFlags.MixedVertexProcessingMicrosoft.DirectX .Direct3D .CreateFlags.MultiThreaded Microsoft.DirectX .Direct3D .CreateFlags.PureDeviceMicrosoft.DirectX .Direct3D .CreateFlags.SoftwareVertexProcessingSoftwareVertexProcessing,
передающий всю обработку вершин presentationParameters -
управляет Microsoft.DirectX .Direct3D .PresentParameters, имеющего,
в частности, свойстваMicrosoft.DirectX .Direct3D .PresentParameters.Windowed -
является false )
или в оконном режиме (значение true )Microsoft.DirectX .Direct3D .PresentParameters.SwapEffect -
используется для описания режима буферной подкачкиSwapEffect.Discard - сбрасывает
содержимое буфера, если он не готов к представлениюSwapEffect.Copy - сходно со
значением Flip ,
но требует от программиста SwapEffect.Flip - будет создан вторичный буфер
и произойдет копирование в него из первичного буфера
независимо от состояния последнегоSwapEffect.Discard .Теперь у нас достаточно информации для создания устройства в нашем проекте.
В
конец класса формы включите объявление ссылки на экземпляр
класса Device namespace SimpleMedia
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private Device device = null;
}
}
Добавьте
новую функцию-член в конец класса Form1 с именем InitializeGraphics(),
которую наполните следующим кодомpublic void InitializeGraphics()
{
// Создание объекта и настройка параметров представления
// Создать объект параметров представления
PresentParameters presentParams = new PresentParameters();
// Установить оконный режим
presentParams.Windowed = true;
// Сбрасывать содержимое буфера, если он не готов к представлению
presentParams.SwapEffect = SwapEffect.Discard;
// Создать объект устройства и сохранить ссылку на него
device = new Device(0, DeviceType.Hardware, this,
CreateFlags.SoftwareVertexProcessing, presentParams);
}
Нулевое значение параметра подразумевает установку
устройства по умолчанию. В результате мы создали фактическое
аппаратное устройство, в противоположность устройству, эмулированному
this, подразумевающее, что окном представления ( рендеринга )
будет текущее окно формы. Мы возложили вершинную обработку
на наш
Откройте
созданный мастером файл Program.cs и перепишите функцию Main() )
такstatic void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
using (Form1 frm = new Form1())
{
// Показать форму перед созданием движка
frm.Show();
// Создать и инициализировать графический движок
// нашей функцией
frm.InitializeGraphics();
// Войти в цикл сообщений
Application.Run(frm);
}
}
Здесь сначала мы добавили директиву using для
создания формы. Это гарантирует вызов сборщика мусора при
завершении приложения. Команда Show() визуализирует
форму прежде,
чем мы попытаемся создать наше графическое устройство.
Постройте
проект и убедитесь в отсутствии синтаксических ошибок.
Результатом вывода пока будет обычное окно формы пустого
проекта, будто-бы мы ничего не сделали. Дальше наша задача
- что нибудь отобразить на экране средствами DirectX .Форма наследует от класса System.Windows.Forms.Control метод OnPaint(), который можно переопределять
в форме. Этот метод диспетчеризует событие , генерируемое
операционной системой в тот момент, когда
нужно перерисовывать окно формы. Добавим этот метод в наш
код рендеринга (отображения). Нет смысла делать сейчас какие-то
сложные вещи, просто очистим окно и заполним его однородным
цветом.
В
конце класса Form1 начните набирать ключевое
слово override и в подсказчике кода выберите
метод OnPaint(), который заполните следующим
кодомprotected override void OnPaint(PaintEventArgs e)
{
// Очистить цветом клиентскую область формы
device.Clear(ClearFlags.Target,
System.Drawing.Color.CornflowerBlue,
1.0F, 0);
// Перерисовать
device.Present();
// Вызвать обработчики, подписавшиеся на событие Paint
// base.OnPaint(e);
}
Первый параметр метода определяет,
что именно мы хотим очистить. В данном примере это будет
текущее окно формы. Вторым параметром является цвет, используемый
при очистке нашего окна. После того, как устройство очищено,
нужно обновить состояние дисплея. Данную процедуру выполняет
метод представления Present(). Существует несколько перегружаемых
вариантов этого метода, наш вариант очищает всю область окна.
Постройте
приложение и убедитесь, что окно заливается васильковым
цветом
Но пока что мы не использовали мощные возможности .
То же самое можно было сделать, установив BackColor в конструкторе
программы. Теперь пришла пора что-нибудь нарисовать.
Сцена и рендеринг являются ключевыми понятиями в . Сцена - прямая аналогия любых театральных подмостков, на
которых мы видим статические и движущиеся объекты, совершающие
различные действия. Все то, что отображается на экране монитора
- это и есть сцена. Процесс представления сцены на
Механизм формирования сцены и рендеринг довольно сложный процесс, состоящий из ряда последовательных операций. Он напоминает некий абстрактный конвейер, визуализирующий графику на экране. Проходя через графический конвейер, информация подвергается трем последовательным стадиям преобразования:
После прохождения объектом всех трех стадий готовая модель
помещается в буфер
Основным объектом, используемым в трехмерной графике, является треугольник. Он же служит элементарным полигоном, с помощью которого можно изображать любые фигуры. Для его рисования нужно сформировать данные, описывающие треугольник, затем вызвать метод рисования.
Управляемый имеет встроенную конструкцию для обработки
треугольников. Существует класс вершин Microsoft.CustomVertex,
который размещает используемые в различные сборки
вершин в формате CustomVertex. Структура вершинного формата
содержит данные в понятном для виде.
На данном этапе будем использовать для нашего треугольника
структуру Microsoft.TransformedColored - преобразование цветов. Эта структура сообщает ,
что наш треугольник не требует никаких преобразований, например,
вращения и перемещения, поскольку мы будем устанавливать
его положение посредством экранных координат. Данная структура
включает цветовые параметры для каждой вершины треугольника.
Добавьте
к методу OnPaint() после вызова Clear () следующий код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);
}
Вначале мы создаем массив структур для хранения трех точек
треугольника. Используя структуру Vector4,
мы устанавливаем координаты вершин треугольника относительно
левого верхнего угла клиентской области формы, а также цвет
каждой вершины.
Затем мы применяем методы формирования сцены и рендеринг. Команда BeginScene() уведомляет о том, что мы собираемся
что-то нарисовать и определяет его готовность к этому. Далее
мы сообщаем, что именно хотим нарисовать. Свойство VertexFormat созданного устройства устанавливает режим непрограммируемого
конвейера в преобразованном цветном вершинном формате.
Метод DrawUserPrimitives() определяет место, где размещается
рисунок. Его парметры означают следующее:
TriangleList.Последняя команда EndScene() сообщает приложению об окончании процедуры рисования. Эта команда должна присутствовать
всегда, если использовалась команда BeginScene().
Постройте
приложение и должен получиться такой результат
Поэкспериментируйте
с заданием новых цветов вершин фигуры. Direct3D автоматически
меняет Если поизменять размеры формы, то можно заметить, что при
уменьшении величины окна изображение не перерисовывается.
Причина в том, что Windows не рассматиривает уменьшение размера
окна как случай, когда необходимо перерисовать целое окно.
Она считает, что просто закрылась часть информации, которая
была отображена, а остальная часть осталась целой. Для того,
чтобы заставить окно перерисовываться непрерывно, даже если
оно не разрушено, надо в метод OnPaint() добавить оператор
принудительной перерисовки.
Добавьте
в самый конец метода OnPaint() вызов методаthis.Invalidate();
наследуемого формой от класса System.Windows.Forms. Control
Запустите
приложение и посокрушайтесь увиденнымМожет показаться, что мы сломали приложение, поскольку теперь мы видим главным образом пустой экран и мерцающий на нем треугольник. После каждого нового принудительного перерисовывания окна вызывается новая его перерисовка. То есть сообщение о разрушении окна генерируется непрерывно. Ну и пусть перерисовывается, лишь бы не мерцало. Устраним эффект мерцания изменением стиля окна. Для этого
Добавьте
в конструктор формы следующий кодpublic Form1()
{
InitializeComponent();
// Устраняем мерцание окна при бесконечной перерисовке
this.SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.Opaque, true);
}
В установке стиля формы предполагается, что окно будет игнорировать все внешние сообщения Windows о перерисовке и полное закрашивание будет происходить внутри самого объекта формы, а также, что окно должно быть непрозрачным.
Запустите
приложение и убедитесь, что мерцание прекратилось, хотя
окно при этом продолжает бесконечно перерисовываться
Поизменяйте
размеры окнаМы видим, что при изменении размеров окна треугольник деформируется, поскольку привязан к параметрам окна. Ниже мы построим треугольник в мировых координатах, без привязки к окну, и он будет сохранять свои пропорции при изменении окна.
Созданное нами приложение не является трехмерным. Оно отображает
только плоский цветной треугольник, нарисованный внутри окна.
Его можно было бы создать гораздо проще с помощью графического
интерфейса GDI (
Когда мы формировали данные нашего треугольника, мы использовали
структуру CustomVertex. TransformedColored,
называемую преобразованными
координатами (PositionColored ), которые и описывают наибольшую
часть сцены и используются в современных -играх.
Для применения непреобразованных координат нужно позиционировать каждую вершину объекта не в экранных координатах, а в абсолютном пространстве мировых координат ( внешних координат). Можно представить внешнее пространство, как бесконечное трехмерное Декартово пространство, в любом месте которого мы можем размещать наши объекты.
Теперь модифицируем наше приложение и нарисуем непреобразованный
треугольник. Вначале нужно изменить данные нашего треугольника,
чтобы использовать один из типов непреобразованных вершинных
форматов. Для этого вновь зададим местоположение
и цвет вершин, а также новое свойство вершинного формата.
Внесите соответствующие изменения в функцию OnPaint() как
показано ниже
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();
*/
// Содать массив структур непреобразованных координат
CustomVertex.PositionColored[] verts = new
CustomVertex.PositionColored[3];
// Задать параметры треугольника
verts[0].SetPosition(new Vector3(0.0F, 1.0F, 1.0F));
verts[0].Color = System.Drawing.Color.Aqua.ToArgb();
verts[1].SetPosition(new Vector3(-1.0F, -1.0F, 1.0F));
verts[1].Color = System.Drawing.Color.Black.ToArgb();
verts[2].SetPosition(new Vector3(1.0F, -1.0F, 1.0F));
verts[2].Color = System.Drawing.Color.Purple.ToArgb();
// Сформировать сцену
device.BeginScene();
device.VertexFormat = CustomVertex.PositionColored.Format;
device.DrawUserPrimitives(PrimitiveType.TriangleList, 1, verts);
device.EndScene();
// Перерисовать
device.Present();
// Принудительно перерисовать
this.Invalidate();
// Вызвать обработчики, подписавшиеся на событие Paint
// base.OnPaint(e);
}
Мы сменили Vector3 вместо Microsoft.Vector4.
Элементы Microsoft.Vector3 структурируют видеокарту
непосредственно в координатах мирового пространства X, Y,
Z. Присваивая при формировании сцены свойству VertexFormat значение
CustomVertex. PositionColored.Format,
мы информируем непрограммируемый конвейер о том, что вершины
отображаемого объекта заданы в мировых координатах.
Теперь если запустить приложение, то треугольник отображаться
не будет. Проблема в том, располагая объект в мировом пространстве,
мы не дали никакой информации о том, как он должен
этот объект отображать. Нужно добавить в сцену камеру, которая
может определять и рассматривать наш объект. В преобразованных
координатах камера была не нужна, потому, что привязка к
экранным координатам однозначно определяла положение объекта.
Камера управляется с помощью двух различных линейных преобразований.
Каждое преобразование определяется матрицей размером 4x4,
которую можно переслать в . Преобразование PerspectiveFovLH()
структуры , которая создает

Приложения используют левую ситему координат естественным
образом. Для смены
Функция PerspectiveFovLH() имеет следующий синтаксис
public static Microsoft.DirectX.Matrix.PerspectiveFovLH( System.Single fieldOfViewY, // Угол зрения камеры System.Single aspectRatio, // Форматное соотношение сторон System.Single znearPlane, // Ближний план (по Z-координате) System.Single zfarPlane) // Дальний план (по Z-координате)
Преобразование

Заметим, что у структуры System. в
языке C# имеется .
Два прорисовывает
только те объекты, которые в мировых координатах попадают
внутрь усеченной
Кроме задания области
public static Microsoft.DirectX.Matrix.LookAtLH( Microsoft.DirectX.Vector3 cameraPosition, // Положение камеры Microsoft.DirectX.Vector3 cameraTarget, // Положение объекта Microsoft.DirectX.Vector3 cameraUpVector) // Направление камеры
Теперь у нас достаточно информации, чтобы отобразить объект во внешних координатах.
Добавьте
в класс Form1 новый метод SetupCamera() и
запакуйте в него следующий код// Установка камеры в сцену
private void SetupCamera()
{
//Создание перспективы
device.Transform.Projection = Matrix.PerspectiveFovLH(
(float)Math.PI / 4, // Угол зрения равен 45 градусов
// Форматное соотношение сторон
(float)this.ClientSize.Width / (float)this.ClientSize.Height,
1.0F, // Ближний план
100.0F); // Дальний план
//Добавление камеры
device.Transform.View = Matrix.LookAtLH(
new Vector3(0, 0, 5.0F), // Положение камеры
new Vector3(), // Положение объекта текущее
new Vector3(0, 1, 0)); // Направление камеры
}
Поместите
в методе OnPaint() класса Form1 сразу
после вызова метода очистки Clear () SetupCamera()protected override void OnPaint(PaintEventArgs e)
{
// Очистить цветом клиентскую область формы
device.Clear(ClearFlags.Target,
System.Drawing.Color.CornflowerBlue,
1.0F, 0);
// Вызов нашей функции установки камеры
SetupCamera();
...............................................
}
Запустите
приложение и должен получиться следующий результат
Мы получили наш первоначальный треугольник, но теперь он
окзался весь черный, хотя мы определили цвета вершин. Проблема
заключается в различии треугольника в преобразованных и непреобразованных
координатах. В непреобразованной среде по умолчанию
использует освещение, чтобы определить итоговый цвет писксела
каждого примитива в сцене. Поскольку мы не использовали никакого
освещения в нашей сцене, то все пикселы треугольника оказались
черными. Самый простой способ пока - вообще отключить возможность
использование источника света в нашей сцене, задав соответствующее
значение параметра состояния рендеринга.
Добавьте
в конец функции SetupCamera() код отключения освещения// Установка камеры в сцену
private void SetupCamera()
{
//Создание перспективы
device.Transform.Projection = Matrix.PerspectiveFovLH(
(float)Math.PI / 4, // Угол зрения равен 45 градусов
// Форматное соотношение сторон
(float)this.ClientSize.Width / (float)this.ClientSize.Height,
1.0F, // Ближний план
100.0F); // Дальний план
//Добавление камеры
device.Transform.View = Matrix.LookAtLH(
new Vector3(0, 0, 5.0F), // Положение камеры
new Vector3(), // Положение объекта текущее
new Vector3(0, 1, 0)); // Направление камеры
// Освещение не используем
device.RenderState.Lighting = false;
}
Запустите
приложение и должен получиться нормальный цветной треугольник
как раньше
Существует много состояний рендеринга, которые могут использоваться для управления различными сценами в конвейере рендеринга. На данном этапе мы выполнили немало действий, чтобы нарисовать объект в мировых координатах, а результат получился тот-же. Но теперь мы имеем треугольник в реальном трехмерном пространстве, а это предпочтительнее, чем просто рисунок в координатах экрана. Зато теперь мы можем, например, повращать треугольник.
Преобразование пространства используется в устройстве для преобразования объектов, нарисованных в пространстве
моделей, где каждая вершина определена относительно модели,
расположенной во внешнем пространстве. Преобразованием пространства
может быть любая комбинация перемещения, вращения и масштабирования.
Так как на данном этапе мы хотим вращать наш треугольник, то для этого мы выполним единственное преобразование. Каждое преобразование характеризуется своей матрицей. У матричного объекта может быть множество функций, позволяющих выполнять эти преобразования.
Добавьте
в конец функции SetupCamera() код, поворачивающий
треугольник на небольшой положительный (против часовой
стрелки) угол// Установка камеры в сцену
private void SetupCamera()
{
//Создание перспективы
device.Transform.Projection = Matrix.PerspectiveFovLH(
(float)Math.PI / 4, // Угол зрения равен 45 градусов
// Форматное соотношение сторон
(float)this.ClientSize.Width / (float)this.ClientSize.Height,
1.0F, // Ближний план
100.0F); // Дальний план
//Добавление камеры
device.Transform.View = Matrix.LookAtLH(
new Vector3(0, 0, 5.0F), // Положение камеры
new Vector3(), // Положение объекта текущее
new Vector3(0, 1, 0)); // Направление камеры
// Освещение не используем
device.RenderState.Lighting = false;
// Преобразование пространства для поворота треугольника относительно оси Z
device.Transform.World = Matrix.RotationZ((float)Math.PI / 6.0F);
}
Добавленный код сообщает о типе
используемого преобразования для каждого рисуемого объекта.
В данном случае это вращение объекта относительно оси Z.
Угол поворота задается строго в радианах. В библиотеке функций Direct3DX,
которую мы добавим позже к нашему проекту, существует вспомогательная
функция , преобразующая
привычные нам градусы в радианы.
Постройте
приложение. Экранный
вывод для постоянного поворота будет таким
Мы повернули объект на постоянный произвольный угол и он
непрерывно перерисовывается в этом неизменном положении в
окне формы, потому что мы непрерывно генерируем событие разрушение
окна вызовом в методе OnPaint(). Если менять
угол в методе RotationZ(), то треугольник будет непрерывно
вращаться.
Замените
RotationZ() на следующий код// Установка камеры в сцену
private void SetupCamera()
{
//Создание перспективы
device.Transform.Projection = Matrix.PerspectiveFovLH(
(float)Math.PI / 4, // Угол зрения равен 45 градусов
// Форматное соотношение сторон
(float)this.ClientSize.Width / (float)this.ClientSize.Height,
1.0F, // Ближний план
100.0F); // Дальний план
//Добавление камеры
device.Transform.View = Matrix.LookAtLH(
new Vector3(0, 0, 5.0F), // Положение камеры
new Vector3(), // Положение объекта текущее
new Vector3(0, 1, 0)); // Направление камеры
// Освещение не используем
device.RenderState.Lighting = false;
/*
// Преобразование пространства для поворота треугольника относительно оси Z
device.Transform.World = Matrix.RotationZ((float)Math.PI / 6.0F);
*/
// Преобразование пространства для непрерывного вращения треугольника
device.Transform.World = Matrix.RotationZ(
(System.Environment.TickCount / 450.0F) / (float)Math.PI);
}
Запустите
приложение и получите вращающийся треугольникВращение происходит из-за непрерывно увеличивающегося встроенного
в библиотеку счетчика System.TickCount.
Каждые 15 миллисекунд значение счетчика увеличивается, тем
самым периодически увеличивая угол вращения для новых перерисовок.
Учитывая, что клиентская область формы непрерывно перерисовывается,
мы можем сами организовать вращение объекта заданием своего
счетчика увеличения угла.
Добавьте
в класс Form1 поле angle для
хранения значений угла и измените вызов RotationZ() в
функции SetupCamera()private float angle = 0;// Закрытый член класса
// Установка камеры в сцену
private void SetupCamera()
{
//Создание перспективы
device.Transform.Projection = Matrix.PerspectiveFovLH(
(float)Math.PI / 4, // Угол зрения равен 45 градусов
// Форматное соотношение сторон
(float)this.ClientSize.Width / (float)this.ClientSize.Height,
1.0F, // Ближний план
100.0F); // Дальний план
//Добавление камеры
device.Transform.View = Matrix.LookAtLH(
new Vector3(0, 0, 5.0F), // Положение камеры
new Vector3(), // Положение объекта текущее
new Vector3(0, 1, 0)); // Направление камеры
// Освещение не используем
device.RenderState.Lighting = false;
/*
// Преобразование пространства для поворота треугольника относительно оси Z
device.Transform.World = Matrix.RotationZ((float)Math.PI / 6.0F);
// Преобразование пространства для непрерывного вращения треугольника
device.Transform.World = Matrix.RotationZ(
(System.Environment.TickCount / 450.0F) / (float)Math.PI);
*/
// Вращение с собственным счетчиком
device.Transform.World = Matrix.RotationZ(angle / (float)Math.PI);
angle += 0.1F;
}
Постройте
приложение и убедитесь, что треугольник вращаетсяПоследний способ, который мы применили для
Организуем вращение треугольника вокруг произвольно заданной оси.
Измените
процедуру преобразования пространства, чтобы код функции SetupCamera() стал таким// Установка камеры в сцену
private void SetupCamera()
{
//Создание перспективы
device.Transform.Projection = Matrix.PerspectiveFovLH(
(float)Math.PI / 4, // Угол зрения равен 45 градусов
// Форматное соотношение сторон
(float)this.ClientSize.Width / (float)this.ClientSize.Height,
1.0F, // Ближний план
100.0F); // Дальний план
//Добавление камеры
device.Transform.View = Matrix.LookAtLH(
new Vector3(0, 0, 5.0F), // Положение камеры
new Vector3(), // Положение объекта текущее
new Vector3(0, 1, 0)); // Направление камеры
// Освещение не используем
device.RenderState.Lighting = false;
/*
// Преобразование пространства для поворота треугольника относительно оси Z
device.Transform.World = Matrix.RotationZ((float)Math.PI / 6.0F);
// Преобразование пространства для непрерывного вращения треугольника
device.Transform.World = Matrix.RotationZ(
(System.Environment.TickCount / 450.0F) / (float)Math.PI);
// Вращение с собственным счетчиком
device.Transform.World = Matrix.RotationZ(angle / (float)Math.PI);
*/
// Преобразование пространства для произвольных поворотов
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);
angle += 0.1F;
}
В вызове функции RotationAxis() первый аргумент конструктора Vector3 устанавливает ориентацию оси вращения треугольника,
второй параметр - угол поворота вокруг этой оси. Угол поворота
мы задаем непрерывным увеличением счетчика при каждом обновлении
экрана, чем вызываем вращение треугольника.
Запустите
приложение с новым изменением кода и проверьте экранный
выводТреугольник вращается вокруг утановленной оси, но постоянно
исчезает, когда должен поворачиваться обратной стороной.
Это связано с порядком освещения невидимых поверхностей.
В данном случае по умолчанию считает, что отображается
объемная фигура, следовательно наш плоский треугольник является
только передней ее гранью, а обратная сторона должна быть
закрыта другой гранью, которой нет. Такой процесс называется Back (не отображать обратное).
Порядок отображения поверхностей определяется опциями параметра
состояния рендера CullMode, которые имеют
значения перечисления
Clockwise -
для вращения по часовой стрелкеCounterClockwise -
для вращения против часовой стрелкиNone -
отключить механизм
Отключите
в состоянии рендера механизм // Установка камеры в сцену
private void SetupCamera()
{
//Создание перспективы
device.Transform.Projection = Matrix.PerspectiveFovLH(
(float)Math.PI / 4, // Угол зрения равен 45 градусов
// Форматное соотношение сторон
(float)this.ClientSize.Width / (float)this.ClientSize.Height,
1.0F, // Ближний план
100.0F); // Дальний план
//Добавление камеры
device.Transform.View = Matrix.LookAtLH(
new Vector3(0, 0, 5.0F), // Положение камеры
new Vector3(), // Положение объекта текущее
new Vector3(0, 1, 0)); // Направление камеры
// Освещение не используем
device.RenderState.Lighting = false;
// Не скрывать обратную сторону плоской фигуры
device.RenderState.CullMode = Cull.None;
/*
// Преобразование пространства для поворота треугольника относительно оси Z
device.Transform.World = Matrix.RotationZ((float)Math.PI / 6.0F);
// Преобразование пространства для непрерывного вращения треугольника
device.Transform.World = Matrix.RotationZ(
(System.Environment.TickCount / 450.0F) / (float)Math.PI);
// Вращение с собственным счетчиком
device.Transform.World = Matrix.RotationZ(angle / (float)Math.PI);
*/
// Преобразование пространства для произвольных поворотов
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);
angle += 0.1F;
}
Запустите
приложение и убедитесь, что обратная сторона вращающегося
треугольника теперь не исчезаетЕсли попробовать в запущенном на данном этапе приложении
изменять размер окна формы, то в какие-то моменты треугольник
исчезает и не хочет прорисовываться, либо начинает изменять
размеры пропорционально размерам окна (попробуйте это!).
Приложение пытается сброситься или продолжить рендеринг
с тем же самым пространственным разрешением. В результате
изображение будет скопировано и вытянуто, чтобы заполнить
измененное окно.
Управляемый способен контролировать процедуру изменения
окна формы и автоматически перезапускать устройство при изменении
окна. Для этого устройство имеет событие Microsoft.DeviceResizing,
в обработчике которого можно сформировать код автоматического
сброса устройства.
Добавьте
в конец класса Form1 код регистрации и DeviceResizingpublic void InitializeGraphics()
{
// Создание объекта и настройка параметров представления
// Создать объект параметров представления
PresentParameters presentParams = new PresentParameters();
// Установить оконный режим
presentParams.Windowed = true;
// Сбрасывать содержимое буфера, если он не готов к представлению
presentParams.SwapEffect = SwapEffect.Discard;
// Создать объект устройства и сохранить ссылку на него
device = new Device(0, DeviceType.Hardware, this,
CreateFlags.SoftwareVertexProcessing, presentParams);
// Перехват события изменения формы для сброса устройства
device.DeviceResizing +=new CancelEventHandler(device_DeviceResizing);
}
// Обработчик события изменения формы для сброса устройства
private void device_DeviceResizing(object sender, CancelEventArgs e)
{
e.Cancel = true;
}
Запустите
приложение и максимизируйте окноМы видим, что у граней треугольника появились неровные края, что портит картину.
Уберите
только что добавленный код, потому что DirectX сам
отрабатывает по умолчанию процедуру изменения размеров
окна оптимальным образомРанее, после того, как мы перевели модель треугольника в
непреобразованные координаты, он стал черным и нам пришлось
временно отключить освещение. Теперь мы займемся настройками
источника света. Класс устройства имеет прикрепленный световой
массив, каждый член которого определяет различные свойства
света.
Первое, что нужно сделать - включить освещение. Для этого
необходимо либо явно установить флаг в
состояние true, либо просто убрать этот
код из функции SetupCamera(), учитывая, что устройство по умолчанию
настроено с включенным освещением.
Включите
свет, удалив или закомментировав соответствующую строку
в функции SetupCamera() (или просто установите
этот флаг Lighting в
значение true )Если сейчас запустить приложение, то треугольник опять станет черным. Настроим освещение в нашей сцене.
Добавьте
в метод OnPaint() формы перед формированием
сцены следующий кодprotected override void OnPaint(PaintEventArgs e)
{
// Очистить цветом клиентскую область формы
device.Clear(ClearFlags.Target,
System.Drawing.Color.CornflowerBlue,
1.0F, 0);
// Вызов нашей функции установки камеры
SetupCamera();
// Содать массив структур непреобразованных координат
CustomVertex.PositionColored[] verts = new
CustomVertex.PositionColored[3];
// Задать параметры треугольника
verts[0].SetPosition(new Vector3(0.0F, 1.0F, 1.0F));
verts[0].Color = System.Drawing.Color.Aqua.ToArgb();
verts[1].SetPosition(new Vector3(-1.0F, -1.0F, 1.0F));
verts[1].Color = System.Drawing.Color.Black.ToArgb();
verts[2].SetPosition(new Vector3(1.0F, -1.0F, 1.0F));
verts[2].Color = System.Drawing.Color.Purple.ToArgb();
// Настроить параметры света источника с номером 0
device.Lights[0].Type = LightType.Point; // Точечный источник
// По умолчанию (0,0,0) - источник в начале координат
device.Lights[0].Position = new Vector3();
// Свет диффузионный белый
device.Lights[0].Diffuse = System.Drawing.Color.White;
// Затухание света при удалении
device.Lights[0].Attenuation0 = 0.2f;
// Дальность освещения, поддерживаемая устройством
device.Lights[0].Range = 1000.0f;
// Принять настройки
device.Lights[0].Commit();
// Установить активным
device.Lights[0].Enabled = true;
// Сформировать сцену
device.BeginScene();
device.VertexFormat = CustomVertex.PositionColored.Format;
device.DrawUserPrimitives(PrimitiveType.TriangleList, 1, verts);
device.EndScene();
// Перерисовать
device.Present();
// Принудительно перерисовать
this.Invalidate();
// Вызвать обработчики, подписавшиеся на событие Paint
// base.OnPaint(e);
}
Вначале определяется, какой тип освещения мы хотим отобразить.
Мы выбрали точечный источник света (
Мы поместили по умолчанию источник в центр треугольника с координатами ( 0,0,0 ) с помощью конструктора Vector3() класса параметров. Мы установили диффузионный компонент осветителя в режим получения рассеянного белого света, чтобы поверхность нормально освещалась. Мы установили параметр затухания ( Attenuation0 ), определяющий изменение интенсивности света при удалении. Диапазон освещения ( Range ) - это максимальное расстояние, в пределах которого распространяется свет.
Запустите
приложение и убедитесь, что треугольник по прежнему остается
чернымПричина в том, что Direct3D не может освещать
объект, не имея
Добавьте
protected override void OnPaint(PaintEventArgs e)
{
// Очистить цветом клиентскую область формы
device.Clear(ClearFlags.Target,
System.Drawing.Color.CornflowerBlue,
1.0F, 0);
// Вызов нашей функции установки камеры
SetupCamera();
/*
// Создать массив структур непреобразованных координат
CustomVertex.PositionColored[] verts = new
CustomVertex.PositionColored[3];
*/
// Создать массив структур непреобразованных координат
// треугольника с возможностью определения нормали к нему
CustomVertex.PositionNormalColored[] verts = new
CustomVertex.PositionNormalColored[3];
// Задать параметры треугольника
verts[0].SetPosition(new Vector3(0.0F, 1.0F, 1.0F));
verts[0].Color = System.Drawing.Color.Aqua.ToArgb();
verts[1].SetPosition(new Vector3(-1.0F, -1.0F, 1.0F));
verts[1].Color = System.Drawing.Color.Black.ToArgb();
verts[2].SetPosition(new Vector3(1.0F, -1.0F, 1.0F));
verts[2].Color = System.Drawing.Color.Purple.ToArgb();
// Дополнить вершины параметрами нормалей
verts[0].SetNormal(new Vector3(0.0F, 0.0F, -1.0F));
verts[1].SetNormal(new Vector3(0.0F, 0.0F, -1.0F));
verts[2].SetNormal(new Vector3(0.0F, 0.0F, -1.0F));
// Настроить параметры света источника с номером 0
device.Lights[0].Type = LightType.Point; // Точечный источник
// По умолчанию (0,0,0) - источник в начале координат
device.Lights[0].Position = new Vector3();
// Свет диффузионный белый
device.Lights[0].Diffuse = System.Drawing.Color.White;
// Затухание света при удалении
device.Lights[0].Attenuation0 = 0.2f;
// Дальность освещения, поддерживаемая устройством
device.Lights[0].Range = 1000.0f;
// Принять настройки
device.Lights[0].Commit();
// Установить активным
device.Lights[0].Enabled = true;
// Сформировать сцену с учетом параметров
// "положение-нормаль-цвет"
device.BeginScene();
// Установить формат обработки вершин при отображении
// device.VertexFormat = CustomVertex.PositionColored.Format;
device.VertexFormat = CustomVertex.PositionNormalColored.Format;
// Нарисовать в буфере кадра треугольник по вершинам
device.DrawUserPrimitives(PrimitiveType.TriangleList, 1, verts);
device.EndScene();
// Показать буфер кадра
device.Present();
// Принудительно перерисовать
this.Invalidate();
// Вызвать обработчики, подписавшиеся на событие Paint
// base.OnPaint(e);
}
Мы создали массив вершин треугольника, способных хранить
информацию "положение-нормаль-цвет". К прежним параметрам
вершин треугольника и их цвета мы добавили еще для каждой
вершины параметры
Следует помнить,
что свет расчитывается применительно к вершине, поэтому
при использовании аппроксимирующих полигонов с малым количеством
вершин, освещение будет менее реалистичным. В таких случаях
применяют более совершенный метод освещения - попиксельное освещение.
Постройте
проект и полюбуйтесь на наше простое
Поизменяйте
размеры окна и убедитесь, что пропорции треугольника сохраняютсяДо сих пор мы поступали слишком расточительно по отношению
к временным затратам компьютера. Неизменные вершины треугольника
мы задавали каждый раз при обновлении экрана. А можно это
сделать один раз и для этого библиотека имеет
специальный класс VertexBuffer для создания
буфера хранения вершин объекта, чем мы и воспользуемся.
Класс Microsoft.VertexBuffer имеет
три перегрузки конструктора, которые можно использовать для
создания вершинного буфера
public VertexBuffer(System.IntPtr lp,
Microsoft.DirectX.Direct3D.Device device,
Microsoft.DirectX.Direct3D.Usage usage,
Microsoft.DirectX.Direct3D.VertexFormats vertexFormat,
Microsoft.DirectX.Direct3D.Pool pool)
public VertexBuffer(System.Type typeVertexType,
System.Int32 numVerts,
Microsoft.DirectX.Direct3D.Device device,
Microsoft.DirectX.Direct3D.Usage usage,
Microsoft.DirectX.Direct3D.VertexFormats vertexFormat,
Microsoft.DirectX.Direct3D.Pool pool)
public VertexBuffer(Microsoft.DirectX.Direct3D.Device device,
System.Int32 sizeOfBufferInBytes,
Microsoft.DirectX.Direct3D.Usage usage,
Microsoft.DirectX.Direct3D.VertexFormats vertexFormat,
Microsoft.DirectX.Direct3D.Pool pool)
Опишем каждый параметр:
lp - принимает указатель на
неуправляемый интерфейс IDirect3DvertexBuffer9 для
совместимости с вершинным буфером, созданным с помощью
неуправляемого внешнего источника. Управляемые приложения
не должны использовать эту device - устройство, которое
используется в Direct3D для создания вершинного
буфера.sizeOfBufferInBytes - задаваемый
параметр вершинного буфера в байтах. С таким параметром
буфер способен поддерживать любой тип вершин.typeVertexType - задается,
если мы хотим, чтобы буфер включал только один тип вершин.
Это может быть тип одной из CustomVertex, либо тип вершин,
определяемый пользователем. Данное значение не может быть
пустым.numVerts - максимальное количество
вершин, которые мы хотим сохранить в буфере. Это значение
должно быть большим нуля.usage - определяет, как этот
вершинный буфер может использоваться. При создании буфера
могут использоваться все значения этого параметра, за исключением
следующих значений перечисления:DoNotClip - используется для того,
чтобы исключить режим clipping (clipping состояния
рендера в значение false.Dynamic - используется для сообщения
приложению, что вершинный буфер требует использования
динамической памяти. Если этот флажок не определен,
вершинный буфер является статическим. Статические
вершины буфера обычно хранятся в видеопамяти, в то
время как динамические буферы хранятся в памяти AGR.
Выбор данной опции необходим для драйверов, чтобы
определить, где хранить данные.NPatches - сообщает, что данный
буфер используется для рисования N-patches .Points - сообщает, что данный
буфер используется для рисования точек.RTPatches - сообщает, что данный
буфер используется для рисования примитивов более
высокого порядка.SoftwareProcessing - сообщает,
что обработка вершин должна проводиться программным
обеспечением, в противном случае обработка ведется
WriteOnly - сообщает, что вершинный
буфер не будет считываться в случае, когда нет необходимости
считывать данные вершинного vertexFormat - перечисление
определяет формат вершин, которые будут сохранены в этом
буфере. Можно выбрать опцию Microsoft.None,
если требуется зарезервировать этот буфер.pool - определяет Managed -
ресурсы копируются автоматически в доступное устройство
памяти. При сбросе устройства ресурсы автоматически
в нем не восстанавливаются.Default -
данные располагаются либо в памяти AGP ,
либо в видеопамяти. Вершинные буферы, созданные в
этом SystemMemory -
данные вершинного буфера помещаются в системную память,
где являются недоступными для устройства.Scratch -
системный Далее мы воспользуемся второй из описанных перегрузок конструктора создания вершинного буфера (выделена).
Добавьте
к классу Form1 закрытое поле-ссылку на
вершинный буфер в дополнение к объявленной ранее переменной-ссылке
устройстваprivate Device device = null;
private VertexBuffer vb = null;
Вместо того, чтобы каждый раз при OnPaint() создавать
данные при отображении сцены, можно сделать это один раз.
Использование вершинного буфера позволяет в значительной
степени увеличить производительность операций отображения
рисунка.

Перенесите код
создания треугольника из OnPaint() в функцию InitializeGraphics() и
разместите его сразу после кода создания устройства, после
чего функция InitializeGraphics() должна
стать такойpublic void InitializeGraphics()
{
// Создание объекта и настройка параметров представления
// Создать объект параметров представления
PresentParameters presentParams = new PresentParameters();
// Установить оконный режим
presentParams.Windowed = true;
// Сбрасывать содержимое буфера, если он не готов к представлению
presentParams.SwapEffect = SwapEffect.Discard;
// Создать объект устройства и сохранить ссылку на него
device = new Device(0, DeviceType.Hardware, this,
CreateFlags.SoftwareVertexProcessing, presentParams);
// Создать вершинный буфер
vb = new VertexBuffer(typeof(CustomVertex.PositionNormalColored),
3,
device,
Usage.Dynamic | Usage.WriteOnly,
CustomVertex.PositionNormalColored.Format,
Pool.Default);
// Создать массив структур непреобразованных координат
// треугольника с возможностью определения нормали к нему
CustomVertex.PositionNormalColored[] verts = new
CustomVertex.PositionNormalColored[3];
// Задать параметры треугольника
verts[0].SetPosition(new Vector3(0.0F, 1.0F, 1.0F));
verts[0].Color = System.Drawing.Color.Aqua.ToArgb();
verts[1].SetPosition(new Vector3(-1.0F, -1.0F, 1.0F));
verts[1].Color = System.Drawing.Color.Black.ToArgb();
verts[2].SetPosition(new Vector3(1.0F, -1.0F, 1.0F));
verts[2].Color = System.Drawing.Color.Purple.ToArgb();
// Дополнить вершины параметрами нормалей
verts[0].SetNormal(new Vector3(0.0F, 0.0F, -1.0F));
verts[1].SetNormal(new Vector3(0.0F, 0.0F, -1.0F));
verts[2].SetNormal(new Vector3(0.0F, 0.0F, -1.0F));
// Заполнить вершинный буфер данными треугольника
vb.SetData(verts, 0, LockFlags.None);
}
В добавленном коде мы сначала создаем вершинный буфер для
хранения трех элементов массива структур verts.
Мы настраиваем вершинный буфер только на запись, определяем
его как динамический для хранения в заданном по умолчанию
OnPaint() коде.
Далее мы помещаем первым параметром список вершин треугольника
в вершинный буфер функцией SetData(). Второй
параметр задает смещение, с какой позиции нужно записывать
массив verts. Мы записываем все вершины,
поэтому задаем смещение равным нулю. Последний параметр определяет,
как мы хотим блокировать буфер на то время, пока данные записываются.
Мы сказали, что никак, поскольку используем буфер монопольно.
После записи данных о треугольнике в вершинный буфер мы
не можем в функции OnPaint() рисовать треугольник
как прежде функцией DrawUserPrimitives().
Для этого существует другая функция - DrawPrimitives().
Измените
в функции OnPaint() код формирования сцены,
размещенный сразу после настройки источника света, на следующий// Сформировать сцену с учетом параметров
// "положение-нормаль-цвет"
device.BeginScene();
// Установить формат обработки вершин при отображении
device.VertexFormat = CustomVertex.PositionNormalColored.Format;
// Нарисовать треугольник по данным из буфера
device.SetStreamSource(0, vb, 0);
device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
device.EndScene();
С помощью функции SetStreamSource() мы
подключаем к устройству вершинный буфер. Первый параметр
этой функции определяет номер потока, который будет использовать
данные. Мы используем один поток с номером 0. Второй параметр
- вершинный буфер с данными рисования. Третий параметр -
смещение в байтах, с которого начнется рисование. Мы будем
рисовать все данные, поэтому задали нулевое смещение.
Далее мы рисуем данные из созданного потока с помощью функции DrawPrimitives().
Первый параметр определяет примитив, с помощью которого будет
рисоваться фигура - у нас это единственный треугольник будет
аппроксимироваться треугольным примитивом. Второй параметр
- начальная вершина в потоке. Последний параметр - число
примитивов, которые мы будем рисовать.
Постройте
приложение и убедитесь, что треугольник строится и вращается
как преждеНо здесь есть проблема: если попытаться изменить размер окна формы, то треугольник исчезает, сразу и навсегда.
Причина в том, что при изменении размеров окна графическое
устройство автоматически сбрасывается.
Это означает, что пул при сбрасывании устройства автоматически
устанавливается в нулевое состояние. То есть там после сброса
не будет никаких данных, поэтому ничего не отобразится на
экране. До введения вершинного OnPaint() при каждой перерисовке,
поэтому такого эффекта не наблюдалось, хотя сбрасывание при
изменении размеров окна имело место.
Нужно каким-то образом вновь заполнить вершинный буфер после
сброса. Вершинный буфер имеет событие Microsoft.Created,
которое отслеживает момент восстановления буфера и готовность
его к заполнению. Нам нужно перехватить это событие в приложении
и создать для него обработчик, в котором разместить код создания
треугольника и заполнения вершинного буфера.
В
функции InitializeGraphics() сразу после кода создания вершинного буфера поместите
код регистрации события Created и начальный
вызов обработчика для только что созданной формы// Создать вершинный буфер
vb = new VertexBuffer(typeof(CustomVertex.PositionNormalColored),
3,
device,
Usage.Dynamic | Usage.WriteOnly,
CustomVertex.PositionNormalColored.Format,
Pool.Default);
// Регистрация события Created вершинного буфера
vb.Created += new EventHandler(vb_Created);
// Принудительный вызов создания треугольника
// и заполнения вершинного буфера при первом
// создании формы
vb_Created(vb, null);
Нулевая ссылка на месте второго параметра в принудительном
вызове обработчика vb_Created() является
заглушкой для объекта типа EventArgs параметров
события, поскольку никаких параметров внутри обработчика
мы не используем.
Перенесите всю
оставшуюся часть функции InitializeGraphics() (код
создания вершин треугольника и заполнения буфера) в созданный
обработчик, который станет такимvoid vb_Created(object sender, EventArgs e)
{
// Создать массив структур непреобразованных координат
// треугольника с возможностью определения нормали к нему
CustomVertex.PositionNormalColored[] verts = new
CustomVertex.PositionNormalColored[3];
// Задать параметры треугольника
verts[0].SetPosition(new Vector3(0.0F, 1.0F, 1.0F));
verts[0].Color = System.Drawing.Color.Aqua.ToArgb();
verts[1].SetPosition(new Vector3(-1.0F, -1.0F, 1.0F));
verts[1].Color = System.Drawing.Color.Black.ToArgb();
verts[2].SetPosition(new Vector3(1.0F, -1.0F, 1.0F));
verts[2].Color = System.Drawing.Color.Purple.ToArgb();
// Дополнить вершины параметрами нормалей
verts[0].SetNormal(new Vector3(0.0F, 0.0F, -1.0F));
verts[1].SetNormal(new Vector3(0.0F, 0.0F, -1.0F));
verts[2].SetNormal(new Vector3(0.0F, 0.0F, -1.0F));
// Заполнить вершинный буфер данными треугольника
vb.SetData(verts, 0, LockFlags.None);
}
Запустите
приложение и попробуйте изменить размер окнаТеперь треугольник восстанавливается в вершинном буфере и прорисовывается всякий раз после сброса устройства.
Конечно, для такого графического объекта, как наш треугольник, выигрыш от применения вершинного буфера не слишком заметен. Но для формирования сложных объектов, состоящих из огромного количества вершин, этот выигрыш существенно возрастет.

Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.