Система координат
В Direct3D она соответствует так называемому правилу "левой руки". Суть правила в том, что если Вы растопырите пальцы левой руки так, что указательный палец будет направлен к экрану, большой к потолку, а средний параллельно столу туда, где обычно лежит мышиный коврик, то большому пальцу будет соответствовать координата Y, среднему - X, указательному Z. Говоря короче координата Z направлена как бы вглубь экрана (я во всяком случае нахожусь по эту его сторону :-)), координата Y - вверх, координата X - вправо (все рисунки из SDK).

Возможно Вам это покажется непривычным. А что Вы тогда скажите на это - в DirectX цвета задаются тремя составляющими R,G,B, каждая из которых - число с плавающей точкой в диапазоне [0-1]. Например белый цвет - (1,1,1), серенький (0.5,0.5,0.5), красный (1,0,0) ну и т.д.
Все трехмерные объекты задаются в виде набора (mesh) многоугольников (граней - faces). Каждый многоугольник должен быть выпуклым. Вообще-то лучше всего использовать треугольники - более сложные многоугольники все равно будут разбиты на треугольники (на это уйдет столь драгоценно процессорное время). Грани (faces) состоят из вершин (vertex).

Грань становится видимой если она повернута так, что образующие ее вершины идут по часовой стрелке с точки зрения наблюдателя. Отсюда вывод - если Ваша грань почему-то не видна - переставьте вершины так, чтоб они были по часовой стрелке.
Кроме того имеются другие объекты - источники света (прямой свет - directional light и рассеянный свет - ambient light), т.н. камера, текстуры, которые могут быть "натянуты" на грани и прочая, прочая: Наборы объектов составляют т.н. frames (затрудняюсь дать этому русское название). В Вашей программе всегда будет хоть один главный frame, называемый сцена (scene), не имющий фрейма-родителя, остальные фреймы принадлежат ему или друг другу.
Я не буду долго разговаривать о том, как инициализировать все это хозяйство, для Дельфи-программиста достаточно разместить на форме компонент TDXDraw из библиотеки DelphiX.
Перейдем однако к делу. Запустите-ка Дельфи и откройте мою (честно говоря не совсем мою - большую часть кода написал Hiroyuki Hori - однако не будем заострять на этом внимание :-)) учебную программку - .
Найдите метод TMainForm.DXDrawInitializeSurface.
Этот метод запускается при инициализации компонента TDXDraw.
Обратите внимание, что DXDraw инкапсулирует D3D, D3D2, D3Ddevice, D3DDevice2, D3DRM, D3DRM2, D3DRMDevice, D3DRMDevice2, DDraw - ни что иное как соответствующие интерфейсы DirectX. (только в названиях интерфейсов Microsoft вместо первой буквы D слово IDirect). Инициализация компонента очень подходящее место, чтоб выбрать кое какие режимы (что и делается в программке). Обратите внимание на DXDraw.D3DRMDevice2.SetRenderMode(D3DRMRENDERMODE_BLENDEDTRANSPARENCY or D3DRMRENDERMODE_SORTEDTRANSPARENCY); - Эти два флага установлены вот для чего - если у нас два треугольника находятся один под другим и оба видны (т.е. вершины у них по часовой) нужно их сперва отсортировать по координате Z чтоб понять кто кого загораживает. Включает такую сортировку флаг, названный скромненько эдак, по Microsots-ки: D3DRMRENDERMODE_SORTEDTRANSPARENCY. Однако как говаривал К. Прутков - смотри в корень. Корнем же у нас является метод TMainForm.DXDrawInitialize(Sender: TObject);
Здесь сначала создаются два фрейма - Mesh и Light, для нашего видимого объектика и для лампочки, его освещающей. MeshFrame.SetRotation(DXDraw.Scene, 0.0, 10.0, 0.0, 0.05);
(первые три цифры - координаты вектора вращения, последний параметр - угол полворота) . Тонкое (не очень правда :-)) отличие между методами SetRotation и AddRotation в том, что AddRotation поворачивает объект только один раз, а SetRotation - заставляет его поворачиваться на указанный угол при каждом следующей итерации (with every render tick) Потом создается т.н. MeshBuilder - специальный объект, инкапсулирующий методы для добавления к нему граней. Этот обьект может быть загружен из файла (и естественно сохранен в файл). По традиции файлы имеют расширение X. (насколько мне извесно эта традиция возникла еще до появления сериала X-Files :-)) В самом же деле - в конце 20 века задавать координаты каждого треугольника вручную: Можно заставит сделать это кого то еще - а потом просто загрузить готовый файл :-). Ну а если серьезно в DirectX SDK входит специальная утилита - conv3ds. {conv3ds converts 3ds models produced by Autodesk 3D Studio and other modelling packages into X Files. } Однако создадим объект вручную - ну их эти Х-файлы. Наш объект будет состоять из 4-х граней (ни одного трехмерного тела с меньшим количеством граней я не смог придумать).
Естественно каждая грань - треугольник, имеющий свой цвет. MeshBuilder.Scale(3, 3, 3); - Увеличиваем в три раза по всем координатам.
Наконец MeshFrame.AddVisual(MeshBuilder); - наш MeshBuilder готов, присоединяем его как визуальный объект к видимому объекту Mesh. DXDraw.Scene.SetSceneBackgroundRGB(0,0.7,0.7); -
Как понятно из названия метода цвет фона. (Видите - я не врал RGB-цвет действительно задается числами с плавающей точкой :-)) Интересные дела творятся в методе TMainForm.DXTimerTimer. (небольшая тонкость - это не обычный таймер, а DXTimer из библиотеки DelphiX) DXDraw.Viewport.ForceUpdate(0, 0, DXDraw.SurfaceWidth, DXDraw.SurfaceHeight);
указываем область, которую нужно обновить (не мудрствуя лукаво - весь DXDraw.Surface) DXDraw.Scene.Move(1.0);
- применяем все трехмерные преобразования, добавленные методами вроде AddRotation и SetRotation к нашей сцене. (вот где собака то порылась: :-) вычисления новых координат точек начнутся не сразу после метода AddRotation а только здесь) DXDraw.Render - Рендерим (ну как же это по русски то? :-)) DXDraw.Flip - выводим результат рендеринга на экран (аминь :-));
(в этом методе помещены также несколько строк, выводящих на экран число кадров в секунду и информацию о поддержке Direct3D аппаратурой или программно - пригодится при отладке) Метод FormKeyDown.
Здесь проверяется код нажатой клавиши - если Alt+Enter - переходим из оконного в полноэкранный режим (клево, правда? :-)) и наоборот. Напоследок пара слов о DXDrawClick. Просто выводим FileOpenDialog - Вы можете поэкспериментировать с x-файлами. Пока все. Пишите: ,
Описанный в статье пример Вы можете скачать (198К).
Продолжение (на сайте ): Часть I:
Часть II:
Часть III: