| Украина, Киев |
Более совершенные технологии рендеринга в DirectX
Создание нескольких вращающихся кубов с применением буфера глубины
Буфер глубины ( depth buffer, Z-буфер, W-буфер ) применяется в приложениях Direct3D для хранения информации о глубине отображаемого объекта. Эта информация используется в процессе растеризации (из векторной в растровую) для определения того, насколько пикселы перекрывают друг друга. На данном этапе наше приложение не имеет буфера глубины, но в этом разделе мы его введем и используем.
-
Через
контекстное меню панели Solution Explorer получите
копию файла Form2 и переименуйте
ее в Form3.cs
-
Через
контекстное меню панели Solution Explorer откройте
файл Form3.cs в режиме View Code
-
В
панели Solution Explorer двойным щелчком
на файле Form3.designer.cs откройте
его в рабочей области редактора оболочки -
Строго проследите,
чтобы открытыми были только файлы Form3.cs Form3.designer.cs и
замените в них все вхождения Form2 на Form3 через
окно замены, которое можно вызвать комбинацией клавиш Ctrl-H.
Предварительно настройте опции окна
замены по приведенному снимку
-
Выполните
команду меню Project/RenderBest Properties и
установите форму Form3 стартовой
-
Запустите
проект на выполнение и убедитесь, что Form3 работает
в прежнем варианте Form2, т.е. целостность
кода сохранилась и мы можем продолжать развитие проекта
Вначале вместо одного куба создадим 9 кубов и для правильного их отображения отодвинем камеру.
-
Добавьте
в класс Form3 новую функцию DrawCubes() для
рисования 9 кубов
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, 0.0f, 0.0f); // По центру
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, 0.0f, 0.0f); // Сдвиг вправо
device.DrawIndexedPrimitives(
PrimitiveType.TriangleList, 0, 0, 8, 0, indices.Length / 3);
device.Transform.World = Matrix.RotationYawPitchRoll(
angle / (float)Math.PI,
angle / (float)Math.PI * 4.0f,
angle / (float)Math.PI / 2.0f) *
Matrix.Translation(-4.0f, 0.0f, 0.0f); // Сдвиг влево
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(0.0f, -4.0f, 0.0f); // По центру
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, -4.0f, 0.0f); // Сдвиг вправо
device.DrawIndexedPrimitives(
PrimitiveType.TriangleList, 0, 0, 8, 0, indices.Length / 3);
device.Transform.World = Matrix.RotationYawPitchRoll(
angle / (float)Math.PI,
angle / (float)Math.PI * 4.0f,
angle / (float)Math.PI / 2.0f) *
Matrix.Translation(-4.0f, -4.0f, 0.0f); // Сдвиг влево
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(0.0f, 4.0f, 0.0f); // По центру
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, 4.0f, 0.0f); // Сдвиг вправо
device.DrawIndexedPrimitives(
PrimitiveType.TriangleList, 0, 0, 8, 0, indices.Length / 3);
device.Transform.World = Matrix.RotationYawPitchRoll(
angle / (float)Math.PI,
angle / (float)Math.PI * 4.0f,
angle / (float)Math.PI / 2.0f) *
Matrix.Translation(-4.0f, 4.0f, 0.0f); // Сдвиг влево
device.DrawIndexedPrimitives(
PrimitiveType.TriangleList, 0, 0, 8, 0, indices.Length / 3);
if (flagRotate)
angle += 0.02F;
}
Листинг
13.19.
Код функции рисования 9 кубов DrawCubes()
-
Удалите
из функции SetupCamera() две последних
секции, ответственные за вращение куба, поскольку эту функциональность
мы включили в новую функцию DrawCubes()
// Установка камеры в сцену
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.Transform.World = Matrix.RotationYawPitchRoll(
angle / (float)Math.PI,
angle / (float)Math.PI * 2.0F,
angle / (float)Math.PI);
if (flagRotate)
angle += 0.02F;
}
Листинг
13.20.
Удаляем код в конце функции SetupCamera()
-
Замените
в секции формирования сцены функции OnPaint() вызов функции DrawIndexedPrimitives() на вызов функции DrawCubes()
// Сформировать сцену с учетом параметров
// "положение-нормаль-цвет"
device.BeginScene();
// Установить формат обработки вершин при отображении
device.VertexFormat = CustomVertex.PositionColored.Format;
// Нарисовать треугольник по данным из буфера
device.SetStreamSource(0, vb, 0);
device.Indices = ib;
DrawCubes();
device.EndScene();
Листинг
13.21.
Код формирования сцены в функции OnPaint()
-
В
функции SetupCamera() отодвиньте камеру, чтобы была видна
вся сцена с 9 кубами
// Установка камеры в сцену
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, 15.0F), // Положение камеры
new Vector3(), // Положение объекта текущее
new Vector3(0, 1, 0)); // Направление камеры
// Освещение
device.RenderState.Lighting = false;
}
Листинг
13.22.
Увеличение расстояния установки камеры в функции SetupCamera()
-
Запустите
приложение и получите примерно следующее
Настало время перейти к использованию буферов глубины объектов. Давайте добавим еще три куба к нашей сцене вращающихся кубов.
-
Добавьте в конец функции 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;
}
Листинг
13.23.
Добавление в конец функции DrawCubes() кода рисования трех новых кубов
-
Запустите
приложение и увидите по горизонтальному среднему ряду еще
дополнительных три куба
Здесь мы хотим получить вращение дополнительных кубов вокруг трех центральных кубов, расположенных по горизонтали. Чтобы этого достичь, следует добавить буфер глубины в устройство device.
Существуют разные форматы буферов глубины, но большинство современных графических плат поддерживают 16-разрядные буферы глубины. Поэтому используем именно такую глубину.
-
Добавьте
в функцию 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);
// Создать вершинный буфер
// .................................................
}
Листинг
13.24.
Параметры настройки буфера глубины в функции InitializeGraphics()
-
Запускаем
приложение и видим, что вместо кубов появились их осколки
Исчезновение сцены после добавления параметров буфера глубины произошло потому, что этот буфер не был очищен
-
Добавьте
к первой секции кода функции OnPaint() дополнительный
флаг очистки буфера глубины
protected override void OnPaint(PaintEventArgs e)
{
// Очистить цветом клиентскую область формы
device.Clear(ClearFlags.Target
| ClearFlags.ZBuffer,
System.Drawing.Color.CornflowerBlue,
1.0F, 0);
..........................................
}
Листинг
13.25.
Добавление флага сброса буфера глубины устройства device в функцию OnPaint()
-
Запустите
приложение и мы увидим фантастическую картину, иллюстрирующую
использование буфера глубины
Краткие выводы
В данной лабораторной работе мы познакомились с более совершенными методами рендеринга, а именно
- Посмотрели на работу различных типов примитивов, приминяемых для рендеринга объектов.
- Попробовали использовать индексные буферы, позволяющие существенно сократить объем данных за счет устранения дублирования описания параметров вершин.
- Применили буфер глубины устройства для более реалистичного (или фантастического) отображения объектов.





