| Китай |
Рендеринг вращающихся кубов в DirectX
Текстурирование сторон вращающегося куба
Нанесем на стороны куба какие-нибудь рисунки. Это могут быть любые плоские bitmap -рисунки. Для текстурирования объектов в Direct3D используется понятие тексела (texel). Тексел - сокращенное название элемента текстуры или соответствующее значение цвета для каждого адреса в текстуре. Адресом в текстуре служат координаты левого верхнего угла прямоугольника текстуры (обычно 0,0) и правого нижнего угла (обычно 1, 1).
Для того, чтобы отобразить кубический объект с использованием текстурирования, нужно изменить вершинный формат объекта, а также данные, пересылаемые в графическую карту. Мы заменим компонент цвета вершин примитивов координатами текстуры. Для того, чтобы получить куб и цветным и текстурным, будем просто использовать текстуру для определения цвета каждого примитива.
-
В
панели Solution Explorer проекта получите
через контекстное меню копию файла Form1.cs и
переименуйте эту копию в файл Form3.cs
-
Вызовите
комбинацией клавиш Ctrl-H окно замены
текстового редактора для файла Form3.cs и
замените все вхождения Form1 на Form3
-
Откройте
файл Form3.designer.cs и выполните в нем те же самые замены -
Через
меню Project откройте окно свойств проекта
и установите на вкладке Application в качестве стартового
объект класса Form3
-
Запустите
приложение, чтобы убедиться, что версия класса Form3 работоспособна
и равнозначна по функциональности Form1
На этом подготовительная часть задачи текстурирования сторон куба завершена и можно приступать к основной части.
-
Измените
тело обработчика vb_Created() так, как показано ниже
private void vb_Created(object sender, EventArgs e)
{
// Определить внутреннюю ссылку на вершинный буфер
VertexBuffer buffer = (VertexBuffer) sender; // Явное приведение типов
// Создать локальный массив структур непреобразованных координат
CustomVertex.PositionTextured[] verts = new
CustomVertex.PositionTextured[36];
// Задать параметры аппроксимирующих треугольников
verts[0] = new CustomVertex.PositionTextured(-1.0F, 1.0F, 1.0F, 0.0F, 0.0F);
verts[1] = new CustomVertex.PositionTextured(-1.0F, -1.0F, 1.0F, 0.0F, 1.0F);
verts[2] = new CustomVertex.PositionTextured(1.0F, 1.0F, 1.0F, 1.0F, 0.0F);
verts[3] = new CustomVertex.PositionTextured(-1.0F, -1.0F, 1.0F, 0.0F, 1.0F);
verts[4] = new CustomVertex.PositionTextured(1.0F, -1.0F, 1.0F, 1.0F, 1.0F);
verts[5] = new CustomVertex.PositionTextured(1.0F, 1.0F, 1.0F, 1.0F, 0.0F);
verts[6] = new CustomVertex.PositionTextured(-1.0F, 1.0F, -1.0F, 0.0F, 0.0F);
verts[7] = new CustomVertex.PositionTextured(1.0F, 1.0F, -1.0F, 1.0F, 0.0F);
verts[8] = new CustomVertex.PositionTextured(-1.0F, -1.0F, -1.0F, 0.0F, 1.0F);
verts[9] = new CustomVertex.PositionTextured(-1.0F, -1.0F, -1.0F, 0.0F, 1.0F);
verts[10] = new CustomVertex.PositionTextured(1.0F, 1.0F, -1.0F, 1.0F, 0.0F);
verts[11] = new CustomVertex.PositionTextured(1.0F, -1.0F, -1.0F, 1.0F, 1.0F);
verts[12] = new CustomVertex.PositionTextured(-1.0F, 1.0F, 1.0F, 0.0F, 0.0F);
verts[13] = new CustomVertex.PositionTextured(1.0F, 1.0F, -1.0F, 1.0F, 1.0F);
verts[14] = new CustomVertex.PositionTextured(-1.0F, 1.0F, -1.0F, 0.0F, 1.0F);
verts[15] = new CustomVertex.PositionTextured(-1.0F, 1.0F, 1.0F, 0.0F, 0.0F);
verts[16] = new CustomVertex.PositionTextured(1.0F, 1.0F, 1.0F, 1.0F, 0.0F);
verts[17] = new CustomVertex.PositionTextured(1.0F, 1.0F, -1.0F, 1.0F, 1.0F);
verts[18] = new CustomVertex.PositionTextured(-1.0F, -1.0F, 1.0F, 0.0F, 0.0F);
verts[19] = new CustomVertex.PositionTextured(-1.0F, -1.0F, -1.0F, 0.0F, 1.0F);
verts[20] = new CustomVertex.PositionTextured(1.0F, -1.0F, -1.0F, 1.0F, 1.0F);
verts[21] = new CustomVertex.PositionTextured(-1.0F, -1.0F, 1.0F, 0.0F, 0.0F);
verts[22] = new CustomVertex.PositionTextured(1.0F, -1.0F, -1.0F, 1.0F, 1.0F);
verts[23] = new CustomVertex.PositionTextured(1.0F, -1.0F, 1.0F, 1.0F, 0.0F);
verts[24] = new CustomVertex.PositionTextured(-1.0F, 1.0F, 1.0F, 0.0F, 0.0F);
verts[25] = new CustomVertex.PositionTextured(-1.0F, -1.0F, -1.0F, 1.0F, 1.0F);
verts[26] = new CustomVertex.PositionTextured(-1.0F, -1.0F, 1.0F, 1.0F, 0.0F);
verts[27] = new CustomVertex.PositionTextured(-1.0F, 1.0F, -1.0F, 0.0F, 1.0F);
verts[28] = new CustomVertex.PositionTextured(-1.0F, -1.0F, -1.0F, 1.0F, 1.0F);
verts[29] = new CustomVertex.PositionTextured(-1.0F, 1.0F, 1.0F, 0.0F, 0.0F);
verts[30] = new CustomVertex.PositionTextured(1.0F, 1.0F, 1.0F, 0.0F, 0.0F);
verts[31] = new CustomVertex.PositionTextured(1.0F, -1.0F, 1.0F, 1.0F, 0.0F);
verts[32] = new CustomVertex.PositionTextured(1.0F, -1.0F, -1.0F, 1.0F, 1.0F);
verts[33] = new CustomVertex.PositionTextured(1.0F, 1.0F, -1.0F, 0.0F, 1.0F);
verts[34] = new CustomVertex.PositionTextured(1.0F, 1.0F, 1.0F, 0.0F, 0.0F);
verts[35] = new CustomVertex.PositionTextured(1.0F, -1.0F, -1.0F, 1.0F, 1.0F);
// Заполнить вершинный буфер данными треугольников
buffer.SetData(verts, 0, LockFlags.None);
}
Листинг
12.14.
Координаты вершин текстурированных примитивов
При отображении каждая сторона куба будет включать текстуру целиком, то есть отображаться полностью в текстуре.
-
В
функции InitializeGraphics() измените код создания вершинного
буфера
// Создать вершинный буфер
vb = new VertexBuffer(typeof(CustomVertex.PositionTextured),
36,
device,
Usage.Dynamic | Usage.WriteOnly,
CustomVertex.PositionTextured.Format,
Pool.Default);
Листинг
12.15.
Код создания вершинного буфера в функции InitializeGraphics()
-
В
функции 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;
// Не скрывать обратную сторону плоской фигуры
// device.RenderState.CullMode = Cull.None;
// Преобразование пространства для произвольных поворотов
/*
device.Transform.World = Matrix.RotationYawPitchRoll(
angle / (float)Math.PI,
angle / (float)Math.PI * 2.0F,
angle / (float)Math.PI);
*/
if (flagRotate)
angle += 0.02F;
}
Листинг
12.16.
Код, который нужно вырезать, и приращение угла скорректировать
-
Перенесите
вырезанный код в функцию OnPaint() и
вставьте перед вызовом функции рисования DrawPrimitives().
Откорректируйте определения формата устройства
protected override void OnPaint(PaintEventArgs e)
{
// Очистить цветом клиентскую область формы
device.Clear(ClearFlags.Target,
System.Drawing.Color.CornflowerBlue,
1.0F, 0);
// Вызов нашей функции установки камеры
SetupCamera();
// Сформировать сцену с учетом параметров
// "положение-нормаль-цвет"
device.BeginScene();
// Установить формат обработки вершин при отображении
device.VertexFormat = CustomVertex.PositionTextured.Format;
// Нарисовать треугольник по данным из буфера
device.SetStreamSource(0, vb, 0);
// Преобразование пространства для произвольных поворотов
device.Transform.World = Matrix.RotationYawPitchRoll(
angle / (float)Math.PI,
angle / (float)Math.PI * 2.0F,
angle / (float)Math.PI);
device.DrawPrimitives(PrimitiveType.TriangleList, 0, 12);
device.EndScene();
// Показать буфер кадра
device.Present();
// Принудительно перерисовать
this.Invalidate();
}
Листинг
12.17.
Перенесенный код в функции OnPaint()
-
Вставьте
в секцию "Сформировать сцену" опять перед функцией рисования
объекта код установки текстуры его сторон
// Сформировать сцену с учетом параметров
// "положение-нормаль-цвет"
device.BeginScene();
// Установить формат обработки вершин при отображении
device.VertexFormat = CustomVertex.PositionTextured.Format;
// Нарисовать треугольник по данным из буфера
device.SetStreamSource(0, vb, 0);
// Преобразование пространства для произвольных поворотов
device.Transform.World = Matrix.RotationYawPitchRoll(
angle / (float)Math.PI,
angle / (float)Math.PI * 2.0F,
angle / (float)Math.PI);
// Установка текстуры
device.SetTexture(0, texture);
device.DrawPrimitives(PrimitiveType.TriangleList, 0, 12);
device.EndScene();
Листинг
12.18.
Установка текстуры рисования сторон в функции OnPaint()
Direct3D позволяет устанавливать до восьми типов текстур одновременно для примитива рисования. В данном коде мы устанавливаем первым параметром только одну текстуру с индексом 0. Второй параметр является ссылкой на текстуру, которую нужно еще создать. Для этого служит класс Microsoft.DirectX.Direct3D. Texture. Класс имеет четыре версии конструктора
- public Texture(System.IntPtr lp, Microsoft.DirectX.Direct3D.Device device, Microsoft.DirectX.Direct3D.Pool pool )
- public Texture(Microsoft.DirectX.Direct3D.Device device, int width, int height, int numLevels, Microsoft.DirectX.Direct3D.Usage usage, Microsoft.DirectX.Direct3D.Format format, Microsoft.DirectX.Direct3D.Pool pool )
- public Texture(Microsoft.DirectX.Direct3D.Device device, System.Drawing.Bitmap image, Microsoft.DirectX.Direct3D.Usage usage, Microsoft.DirectX.Direct3D.Pool pool )
- public Texture(Microsoft.DirectX.Direct3D.Device device, System.IO.Stream data, Microsoft.DirectX.Direct3D.Usage usage, Microsoft.DirectX.Direct3D.Pool pool )
Мы воспользуемся для создания текстуры предпоследней из приведенных версий. Данный конструктор имеет четыре параметра.
- Первый параметр определяет устройство, используемое для выполнения текстуры (все ресурсы: вершинные буферы, текстуры и т.д. связаны с устройством)
- Второй параметр определяет источник данных, используемый для текстуры. В нашем случае будет использован конструктор класса Bitmap, загружающий рисунок из внедренного ресурса
- Третий параметр определяет индекс используемой структуры
- Четвертый параметр - пул памяти, используемый для хранения текстуры. Для удобства будем использовать управляемый пул
-
Добавьте
в секцию определения ссылок-членов класса перед функцией InitializeGraphics() код создания ссылки на текстуру
private Device device = null;
private VertexBuffer vb = null;
private Texture texture = null;
public void InitializeGraphics()
{
....................................
}
Листинг
12.19.
Создание поля-ссылки класса Form3 на текстуру
-
Поместите
в обработчик vb_Created() в самый его
конец после заполнения вершинного буфера данными аппроксимирующих
треугольников код создания управляемого пула памяти с текстурой
private void vb_Created(object sender, EventArgs e)
{
..........................................
// Заполнить вершинный буфер данными треугольников
buffer.SetData(verts, 0, LockFlags.None);
// Создать объект текстуры
Bitmap bmp = new Bitmap(this.GetType(), "12_16.bmp");
texture = new Texture(device, bmp, 0, Pool.Managed);
}
Листинг
12.20.
Создание пула памяти для текстуры и загрузка в него рисунка
Здесь в качестве текстуры используется прилагаемый к описанию рисунок "12_16.bmp" из каталога Source данной лабораторной работы (вы можете создать свой рисунок в формате bmp ).
-
В
меню Project выполните команду Add
Existing Item,
установите фильтр открывшегося диалогового окна на Image
Files и
добавьте в проект файл 12_16.bmp
-
Перейдите
в панель Solution Explorer, выделите файл 12_16.bmp и
через панель Properties установите свойство Build Action = Embedded
Resource (внедренный
ресурс), чтобы компилятор размещал рисунок прямо в файле
исполнимой сборки -
Постройте
проект и получите примерно такой результат вращающегося
текстурированного куба
-
Для
демонстрации вариантов работы преподавателю создайте меню
выбора варианта, как это сделано в Lab45 - WinFormsApp


