- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Графика DirectX в Delphi - Михаил Краснов
Шрифт:
Интервал:
Закладка:
Для получения реалистичных изображений необходимо выполнить три условия:
* при описании примитивов задать нормали; определить свойство материала; включить источник света.
Нормали помогают системе рассчитать освещенность примитива при различном его положении относительно источника света. В самом простом использовании нормаль представляет собой вектор, перпендикулярный воспроизводимому треугольнику. Этот вектор задается для каждой вершины, образующей примитив, и из требований оптимизации должен быть нормализован, т. е. иметь единичную длину.
Формат вершин теперь помимо пространственных координат обязан включать вектор нормали (тройку вещественных чисел), а FVF-флаг должен дополниться константой D3DFVF_NORMAL. ЭТО первое новшество в модуле нашего следующего примера, проекта каталога Ех02, где рисуется красивый желтый кубик (рис. 9.3).
Итак, запись описания вершины дополнилась тремя полями:
type
TCUSTOMVERTEX = packed record
X, Y, Z : Single;
nX, nY, nZ : Single; // Вектор нормали end;
const
D3DEVF_CUSTOMVERTEX = D3DFVF_XYZ or D3DFVF_NORMAL;
Буфер содержит 36 вершин, предназначенных для построения куба. Они образуют 12 независимых треугольников, по 2 соприкасающихся треугольника на каждую сторону куба. Все треугольники описываются по часовой стрелке, чтобы при воспроизведении мы могли, для экономии времени, отключить воспроизведение примитивов, перечисляемых в поле зрения против часовой стрелки. То есть стороны куба, повернутые к нам задней стороной, воспроизводить не будем, это обычный прием, применяемый к замкнутым трехмерным фигурам. Нормали для всех вершин, относящихся к одной стороне, задаются одинаковыми, исходя из того, какая сторона куба описывается. Так выглядит описание первого треугольника:
Vertices.X := -0.5;
Vertices.Y := -0.5;
Vertices.Z := -0.5;
Vertices.nX := -1.0;
Inc(Vertices);
При инициализации графической системы вызывается процедура, задающая свойства материала и включающая источник света:
procedure TfrmD3D.SetupLights;
var
Material : TD3DMaterial8;
Light : TD3DLight8;
begin
// Инициализация материала, желтый цвет
Material := InitMaterial(1, 1, 0, 0) ;
// Устанавливаем материал в объекте устройства
FD3DDevice.SetMaterial(Material);
// Инициализация направленного источника, белый свет
Light := InitDirectionalLight(DSDVector(0, 0, 1), 1, 1, 1, 0) ;
// Устанавливаем источник света
FDSDDevice.SetLight(0, Light);
// Включаем источник света
FD3DDevice.LightEnable(0, True);
end;
Материал и источник света являются записями (не СОМ-объекты) и имеют тип TD3DMateriais и TD3DLight8 соответственно. Пользовательская функция InitMaterial заполняет поля структуры материала и получает в качестве аргументов значения ARGB. Отличает эти параметры от привычного их использования, помимо порядка, в котором они перечисляются, то, что это вещественные числа, единица соответствует максимальному значению аргумента.
В примере материал задается желтым, для того, чтобы установить его. При этом используется метод SetMaterial объекта устройства.
Функция InitDirectionalLight заполняет поля структуры, описывающей направленный источник света. Первым аргументом передается вектор, задающий направление лучей света. Напоминаю, что мы наблюдаем сцену с отрицательной стороны оси Z. Чтобы лучи света были параллельны нашему взору, вектор направления задается (0, 0, 1). Следующие три аргумента описывают цветовой фильтр, накладываемый на источник света, обычно источник задается белым. Эти числа также вещественны. Значение последнего аргумента для направленного источника безразлично.
Метод setLight объекта устройства устанавливает источник света на сцене. Первый аргумент, целое число, основанное на нуле, является индексом, идентификатором источника света. Метод только задает источник света, включается же он с помощью отдельного метода, LightEnabie, первый аргумент которого - индекс нужного источника, второй аргумент - булево выражение.
Как я уже говорил, отключается воспроизведение задних сторон треугольников, т. е. тех, чьи вершины перечисляются против часовой стрелки:
SetRenderState(D3DRS__CULLMODE, D3DCULL_CCW);
Совсем не обязательно, чтобы вершины примитива перечислялись именно по часовой стрелке, можно использовать и противоположное направление. Просто желательно, чтобы существовал какой-нибудь определенный порядок перечисления, чтобы можно было отсекать воспроизведение задних сторон. Повторюсь, внутренние стороны кубика нам не видны в любом случае, поэтому и незачем тратить время на их воспроизведение. Также обращаю ваше внимание на то, что связанные треугольники приспособлены для перечисления вершин именно по часовой стрелке.
Есть и еще один важный аспект, который нам необходимо учитывать: DirectSD не может окрашивать примитивы с двух сторон. Замените последний аргумент метода Drawprimitive на 2 и установите значение для режима D3DRs_CULLMODE в D3DCULL_NONE. Теперь будет выводиться только одна сторона куба, отсечение задней стороны примитивов не производится. Обратите внимание, что когда квадрат поворачивается к зрителю задней стороной, он выводится черным, т. е. совершенно не окрашиваемым.
Кубик в нашем примере вращается вокруг двух осей одновременно:
SetRotateXMatrix(matRotateX, Angle);
SetRotateYMatrix(matRotateY, Angle);
FD3DDevice.SetTransform(D3DTS_WORLD, MatrixMul(matRotateX, matRotateY));
FD3DDevice.DrawPrimitive(D3DPT__TRIANGLELIST, 0, 12);
На рисунке куб получился крупнее, чем при работе приложения. Для того, чтобы увеличить изображение, можно просто "приблизить" глаз наблюдателя:
SetViewMatrixfmatView, D3DVector(0, 0, -2),
D3DVector(0, 0, 0), D3DVector(0, I, 0));
Есть и другой способ: действительно увеличить объект. Для этого в матрицу трансформаций надо добавить матрицу масштабирования, по главной диагонали которой стоят числа, отличные от единицы и равные масштабным множителям по трем осям отдельно. Попробуйте сейчас увеличить кубик в два раза:
procedure TfrmD3D.DrawScene;
var
matView, matProj : TD3DMatrix;
matRotateX, matRotateY : TD3DMatrix;
niatScale : TD3DMatrix; // Добавилась матрица масштабирования
begin
SetRotateXMatrix(matRotateX, Angle);
SetRotateYMatrix(matRotateY, Angle);
SetScaleMatrix(matScale, 2.0, 2.0, 2.0); // Увеличиваем в 2 раза
// Добавляем матрицу масштабирования
FD3DDevice.SetTransform(D3DTS_WORLD, MatrixMul(matScale,
MatrixMul(matRotateX, matRotateY)));
Обязательно это сделайте, чтобы увидеть, что куб действительно увеличился. Однако освещение его тоже изменилось. Связано это с тем, что векторы нормалей к вершинам вслед за масштабированием стали увеличенными, и требуется их нормализация. В таких случаях необходимо включить режим автоматической нормализации этих векторов:
SetRenderState(D3DRS NORMALIZENORMALS, DWORD (True));
Буфер глубины
Продолжим рассмотрение нашего примера с вращающимся кубом. В нем еще остались некоторые новые для нас вещи. Рисуемые примитивы накладываются друг на друга в том порядке, в котором они воспроизводятся: нарисованные позже лежат поверх созданных ранее. Это хорошо для двумерных построений, но при переходе в ЗD-пространство нам приходится беспокоиться о том, чтобы положения объектов передавались правильно: более удаленные от глаза наблюдателя объекты могут заслонять воспроизведенные позже, но располагающиеся ближе к камере. Графическая система предлагает решение в виде использования буфера глубины - вспомогательного экрана, предназначенного только для сортировки объектов, располагающихся в пространстве. При подключении этого буфера воспроизведение осуществляется дважды: первый раз в буфер записывается информация о значении расстояния от камеры до точки, второй раз в буфер кадра помещаются данные только о точках, действительно видимых и не заслоняемых другими точками.
Другое название буфера глубины - Z-буфер.
При инициализации Direct3D надо указать, что будет использоваться буфер глубины, и задать его формат. Обычно используется 16-битный формат:
with d3dpp do begin
Windowed := True;
SwapEffect := D3DSWAPEFFECT_DISCARD;
BackBufferFormat := dSddm.Format;
// Будет использоваться буфер глубины
EnableAutoDepthStencil := True;
AutoDepthStencilFormat := D3DFMT_D16; // 16-битный формат
end;
Размеры буфера глубины будут автоматически определяться системой при каждом изменении размеров окна.
При очередной перерисовке кадра теперь должен очищаться не только буфер кадра, но и подключенный буфер глубины. Предпоследний параметр метода clear объекта устройства - значение, которым заполняется буфер глубины. Этим значением должна быть единица, фон экрана бесконечно удален в пространстве:
FD3DDevice.Clear(0, nil, D3DCLEAR_TARGET or D3DCLEAR_ZBUFFER,
$00FFFFFF, 1.0, 0) ;
Для разрешения работы с буфером глубины надо также задать положительный флаг для соответствующего режима:
SetRenderState(D3DRS_ZENABLE, D3DZBJTRUE);
Флагом для этого состояния может быть и обычная булева константа.
Сейчас нам необходимо перейти к следующему примеру, проекту каталога Ех03, после его запуска на экране появляется вращающийся чайник и стрелки осей координат (рис. 9.4).
Буфер вершин заполняется данными для трех трехмерных объектов: цилиндра, конуса и чайника:

