- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Графика DirectX в Delphi - Михаил Краснов
Шрифт:
Интервал:
Закладка:
Для манипуляций с вершинами предназначен особый механизм, называемый вершинным шейдером (vertex shader). После того как буферы вершин заполнены, объект устройства создает шейдер вершин, заполняемый данными буфера.
Попробуем посмотреть, как все это осуществляется, с помощью простейшего примера, проекта каталога Ех06, в котором посередине окна рисуется точка.
Чтобы отобразить точку на плоскости, нам достаточно задать две ее координаты, но мы должны придерживаться правила об использовании форматов вершин из определенного набора. Минимальный набор характеристик вершины включает в себя три координаты вершины в пространстве. Хотя наши построения будут выполняться на плоскости, и нет нужды в третьей координате, мы просто обязаны указывать ее. Если же мы хотим опираться в плоскостных построениях на оконные координаты, вершины должны включать дополнительную характеристику, служащую индикатором таких построений, и называемую RHW (Reciprocal Homogeneous W). Нами она также явно не используется, но присутствовать должна.
Формат описания вершины вводится клиентом; все атрибуты должны быть типа single:
type
TCUSTOMVERTEX = packed record
X, Y, Z, RHW : Single;
end;
Переменная Vpoint этого типа введена в программе для хранения характеристик нашей точки. Также нам требуется объект буфера вершин:
FD3DVB : IDIRECT3DVERTEXBUFFER8;
По окончании работы программы с ним производятся обычные манипуляции, связанные с высвобождением памяти, а создается этот объект вызовом специального метода объекта устройства в отдельной функции инициализации:
function TfrmD3D.InitPoint : HRESULT;
var
pVertices : PByte;
hRet : HRESULT;
begin
// Задаем координаты точки, опираемся на оконные координаты
with VPoint do begin
X := 150.0;
У := 150.0;
Z := 0.0;
RHW := 0.0;
end;
// Создание буфера вершин
hRet := FD3DDevice.CreateVertexBuffer(SizeOf(VPoint) ,
D3DUSAGE_WRITEONLY, D3DFVF_XYZRHW,
D3DPOOL_DEFAULT, FD3DVB);
if Failed (hRet) then begin
Result := hRet;
Exit;
end;
// Запираем буфер
hRet := FD3DVB.Lock(0, SizeOf(VPoint), pVertices, 0);
if Failed (hRet) then begin
Result := hRet;
Exit;
end;
// Заполняем данными о вершине
Move (VPoint, pVertices", SizeOf(VPoint));
hRet := FD3DVB.Unlock; // Отпираем буфер вершин
if Failed (hRet) then begin
Result := hRet;
Exit;
end;
// Связываем буфер вершин с потоком данных
hRet := FD3DDevice.SetStreamSource(0, FD3DVB, SizeOf(TCUSTOMVERTEX));
if Failed (hRet) then begin
Result := hRet;
Exit;
end;
// Устанавливаем вершинный шейдер
Result := FD3DDevice.SetVertexShader(D3DFVF_XYZRHW);
end;
Разберем подробнее действия, выполняемые программой. Как мы уже выяснили, размеры клиентской области окна в момент инициализации графической системы задают область вывода, размеры и координаты. Размеры окна установил 300x300 пикселов, поэтому координаты точки посередине окна - (150, 150). Координаты построений опираются на левый верхний угол окна: если координату X увеличить на 50, точка сдвинется на 50 пикселов вправо. Значения последних двух полей Vpoint безразличны.
Структура, содержащая характеристики вершины, заполнена. Однако напрямую она для построений не используется. Этими данными должен заполняться буфер вершин. Сначала буфер вершин должен быть создан методом createVertexBuffer объекта устройства. Первый аргумент метода - размер буфера вершин, в байтах. Второй аргумент - флаг либо комбинация флагов, задает параметры работы с буфером. Используемый здесь флаг D3DUSAGE_WRITEONLY информирует систему, что нам не потребуется чтение содержимого буфера. Такой режим наиболее оптимальный.
Третий параметр - комбинация FVF-флагов, определяет формат вершин. Флаг D3DFVF_XYZRHW соответствует используемому нами формату из четырех чисел, координаты опираются на систему координат, связанную с окном.
Четвертый аргумент рассматриваемого метода позволяет задавать месторасположение создаваемого буфера, при использовании константы D3DPOOL_DEFAULT буфер будет расположен в видеопамяти, если это возможно.
Последним аргументом передается переменная, в которую будет помещен результат - создаваемый объект типа IDIRECTSDVERTEXBUFFERS.
Заполнение буфера конкретными данными производится при его закрытом состоянии, метод Lock приводит к запиранию буфера.
Первый аргумент метода - смещение относительно начала буфера. Передаваемый в качестве аргумента ноль приводит к запиранию буфера с самого начала. Второй аргумент метода задает размер запираемой области. Здесь может быть ноль для того, чтобы явно запереть всю память буфера. Третий параметр - возвращаемый методом адрес запираемой области памяти. Последний, четвертый аргумент, обычно задается нулевым, если нет необходимости использовать особые режимы запирания, такие, как режим "только для чтения".
Буфер заперт, по полученному адресу заносятся данные из нашей переменной Vpoint, используется процедура Move. После этого буфер отпирается, вызывается метод UnLock буфера.
Далее необходимо связать поток данных, поступающих в объект устройства, используя метод setstreamSource. Поток определен как однородный массив данных, где каждый компонент состоит из единственного элемента. Метод не приводит непосредственно к какому-либо действию, чтение данных из потока будет осуществляться при воспроизведении. Первый аргумент - идентификатор потока, как правило, задается нулевым (присутствует единственный поток). Второй аргумент - буфер вершин, с которым ассоциируется поток. Последний аргумент - размер порции данных.
Завершающее действие, которое следует выполнить в коде инициализации - определиться с вершинным шейдером. Для предопределенных форматов вершин нужно только вызывать метод setVertexShader объекта устройства. У метода единственный аргумент - FVF-флаг, то же значение, что и использованное при создании буфера вершин (материал книги ограничивается только таким использованием шейдеров).
В инициализации выполнены все необходимые действия, код воспроизведения должен дополниться действиями, связанными с отображением точки на экране. После очистки заднего буфера вызывается связанный с воспроизведением метод объекта устройства:
hRet := FD3DDevice.DrawPrimitive(D3DPT_POINTLIST, 0, 1);
Первый аргумент - идентификатор нужного примитива. Для вывода точки используется константа D3DPT_POINTLIST. Второй и третий аргументы метода задают интервал считываемых из потока примитивов, в примере берется первый и единственный примитив.
Как видим, код непосредственного воспроизведения выглядит очень просто, чего нельзя сказать об инициализации. Именно при вызове метода DrawPrimitive происходит обращение к потоку данных, поэтому в коде инициализации вызов метода SetstreamSource можно ставить в любом месте после создания буфера. Но, конечно, буфер выбора желательно держать в запертом состоянии максимально короткое время.
В примере я сознательно допустил небольшое упрощение. Процесс непосредственного воспроизведения разработчики рекомендуют обрамлять двумя действиями. Перед первым вызовом метода DrawPrimitive необходимо вызывать метод Beginscene объекта устройства, после воспроизведения вызывается его метод EndScene. У обоих методов отсутствуют параметры. При вызове первого из них программа информирует устройство, что следует подготовиться к воспроизведению. Второй метод сообщает устройству о том, что процесс воспроизведения для текущего кадра закончен. Это парные действия, и если использован один из методов, второй не должен быть пропущен.
Скорее всего, вы не заметите разницы в работе программы, если не станете использовать эти командные скобки. Но я в примерах книги буду неукоснительно следовать рекомендациям разработчиков.
Точки
Примитив точка, соответствующий использованию константы D3DPT_POINTLIST в качестве первого аргумента метода DrawPrimitive, приводит к тому, что для каждой порции данных, считываемых из потока, на экране вывода ставится точка.
Изучим основательнее этот примитив на примере проекта каталога Ех07, где экран усеивается множеством точек (рис. 7.2).
Теперь нам требуется массив, хранящий данные о вершинах:
const
MAXPOINTS = 1000; // Количество точек
var
VPoints : Array [0..MAXPOINTS - 1] of TCOSTOMVERTEX; // Массив точек
Координаты точек берутся случайно, в пределах, обусловленных размерами клиентской области окна приложения:
Randomize; // Инициализируем генератор случайных чисел
for i := 0 to MAXPOINTS - 1 do // Цикл по точкам
with VPoints [i] do begin
X := random (300);
Y := random (300);
Z := 0.0;
RHW := 0.0;
end;
Все остальные изменения кода предыдущей программы по большей части связаны только с изменением имени переменной, хранящей вершины. Лишь в функции воспроизведения произошли наиболее важные перемены:
hRet := FD3DDevice.BeginScene; // Информируем устройство о готовности
if FAILED(hRet) then begin // к воспроизведению
Result := hRet;
Exit; end;
// Последний аргумент - количество используемых точек
hRet := FD3DDevice.DrawPrimitive(D3DPT_POINTLIST, 0, MAXPOINTS);
if FAILED(hRet) then begin
Result := hRet;
Exit;
end;

