- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Программирование на Visual C++. Архив рассылки - Алекс Jenter
Шрифт:
Интервал:
Закладка:
pDirect3DObject = Direct3DCreate8(D3D_SDK_VERSION);
if (!pDirect3DObject) {
// Do something!!! Error occured!!!
}
После создания объекта IDirect3D8 мы должны создать еще что-то, на чем мы будем рисовать. Это "что-то" называется IDirect3DDevice8 и мы можем его создать с помощью метода IDirect3D8::CreateDevice(). В демо-проекте эта функция вызывается из C3DGraphic::Create() следующим образом:
D3DDISPLAYMODE theDisplayMode;
hr = m_p3DApplication->m_pDirect3DObject->GetAdapterDisplayMode(3DADAPTER_DEFAULT, &theDisplayMode);
if (FAILED(hr)) {
return hr;
}
D3DPRESENT_PARAMETERS thePresentParams;
ZeroMemory(&thePresentParams, sizeof(thePresentParams));
thePresentParams.Windowed = TRUE;
thePresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
thePresentParams.BackBufferFormat = theDisplayMode.Format;
thePresentParams.EnableAutoDepthStencil = TRUE;
thePresentParams.AutoDepthStencilFormat = D3DFMT_D16;
hr = m_p3DApplication->m_pDirect3DObject->CreateDevice(
D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hwndRenderTarget,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&thePresentParams, &m_p3DDevice);
if (FAILED(hr)) {
return hr;
}
Только что мы создали 3D устройство, задав при этом кучу параметров. Несколько комментариев и разъяснений, что есть что:
• 3D устройство было создано для видеоадаптера, используемого по умолчанию. Об этом говорит параметр D3DADAPTER_DEFAULT. Средний житель России имеет от 0 до 1 видеоадаптеров, так что особых проблем с этим параметром возникнуть не должно.
• Созданное устройство имеет один back-буфер, цветовой формат буфера такой же как у экрана.
• Устройство создано для использования в оконном режиме. Весь рендеринг будет направлен на окно m_hwndRenderTarget. Эта переменная соотвествует окну нашего вида C3DGraphFrame. Антиподом оконному режиму служит полноэкранный режим. Для работы с ним надо при создании устройства переменную Windowed установить в FALSE, а не в TRUE.
• Устройство имеет автоматически созданный depth-буфер, который иногда еще называют z-буфером. Формат z-буфера – 16 бит на точку. В наше время трудно (но, правда, можно) найти видеоадаптер, который не поддерживает такой формат z-буфера. Z-буфер используется вычислительным ядром Direct3D для хранения информации о текущей z-координате каждой точки картинной плоскости. В конечном счете это используется для удаления невидимых линий и поверхностей.
• 3D устройство должно использовать все возможности аппаратуры. Если какое-либо требуемое свойство не поддерживается, Direct3D попытается эмулировать его на программном уровне. Вы можете поменять тип устройства с D3DDEVTYPE_HAL на D3DDEVTYPE_REF. В этом случае все вычисления будут проводиться на программном уровне. Такая эмуляция является очень медленной, и не все на свете можно эмулировать.
• Обрабатываться вершины (vertexes) должны на программном уровне. Мы сделали этот выбор, указав значение D3DCREATE_SOFTWARE_VERTEXPROCESSING. Можно указать вместо этого D3DCREATE_MIXED_VERTEXPROCESSING или D3DCREATE_HARDWARE_VERTEXPROCESSING, но эти режимы поддерживаются далеко не всеми видеокартами.
Стоит заметить, что реальное приложение (игра, например) должны вначале анализировать возможности установленного оборудования, а затем уже принимать решение о возможности или, наоборот, невозможности продолжать работу. Для упрощения такая проверка в демо-приложении не делается.
От f(x,y)=sin(x+y) до 2D картинкиЖизнь всегда была сложнее, чем хотелось бы программисту. Например, все было бы гораздо проще, если бы существовала некая функция ХочуЧтобыНарисовалсяГрафикФункции(). Но во-первых, по-русски функции называть нельзя, во-вторых, такой функции просто нет. Все, что умеет IDirect3DDevice8, это нарисовать некоторые примитивы, да и для этого надо проделать кучу подготовительной работы. Как минимум, вы должны разместить координаты примитивов в вертекс-буфер ("vertex buffer"). Полное обсуждение вертекс-буферов находится за пределами этой статьи и могу лишь сказать, что это некая абстракция простого блока памяти, предназначенного для хранения координат и свойств точек трехмерного пространства. Работа с буфером осуществляется через интерфейс IDirect3DVertexBuffer8. Вы может заблокировать вертекс-буфер, получив при этом указатель на область памяти. Разыменовав указатель, можно записать что-нибудь в буфер, не забыв потом его разблокировать. В демо-приложении вы можете увидеть как это делается.
Обычно перед рисованием чего-либо мы хотим очистить кадр, чтобы новый кадр не накладывался на предыдущий. Это делается вызовом метода IDirect3DDevice8::Clear(). Вы найдете это в функции C3DGraphic::ReRender():
hr = m_p3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, m_dwBackColor, f, 0);
if (FAILED(hr)) {
return hr;
}
Мы здесь очищаем весь back-буфер, заполняя его цветом m_dwBackColor. Кроме этого, очищается z-буфер – он заполняется значением 1.0. 1.0 соответствует максимально дальней от наблюдателя плоскости (горизонт, грубо говоря), 0.0 – максимально ближней. Непосредственно рисование на 3D устройстве начинается с
m_p3DDevice->BeginScene();
а заканчивается строкой
m_p3DDevice->EndScene();
Все, что находится между этими вызовами символизирует анимацию очередного кадра. Обратите внимание на то, что мы постоянно употребляем термин "back-буфер". Совершенно верно! Все, что мы сейчас нарисовали, не видно на экране, оно существует пока только в памяти компьютера (не будем уточнять, в какой именно: системной или видео – очень тонкий вопрос). Для того, чтобы эти изменения перенеслись на экран монитора необходимо скопировать изображение из back-буфера на основную поверхность. Это делается вызовом функции IDirect3DDevice8::Present().
Следующий код обеспечивает непосредственно отрисовку изображения трехмерной функции:
hr = m_p3DDevice->SetStreamSource(0, m_pDataVB, sizeof(GRAPH3DVERTEXSTRUCT));
if (FAILED(hr)) {
return hr;
}
hr = m_p3DDevice->SetVertexShader(D3DFVF_GRAPH3DVERTEX);
if (FAILED(hr)) {
return hr;
}
hr = m_p3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, m_dwElementsInVB - 2);
if (FAILED(hr)) {
return hr;
}
Переменная m_pDataVB является членом класса C3DGraphic, она содержит указатель на интерфейс IDirect3DVertexBuffer8. В нашем случае содержимое вертекс-буфера представляет из себя массив структур GRAPH3DVERTEXSTRUCT:
typedef struct {
FLOAT x, y, z;
FLOAT nx, ny, nz;
} GRAPH3DVERTEXSTRUCT;
Здесь x, y и z – координаты точки, nx, ny, nz – компоненты нормали. Вектор нормали используется подсистемой Direct3D, отвечающей за освещение сцены. Чуть позже мы рассмотрим, как можно рассчитать эти компоненты. Перед вызовом функции DrawPrimitive() мы должны указать vertex shader и используемый поток данных. Выбор и установка потока данных производится с помощью функции SetStreamSorce(). Мы передаем ей номер устанавливаемого потока (0, если оспользуется только один поток), указатель на вертекс-буфер, из которого будут браться данные, и размер каждого элемента в потоке (то есть, sizeof(GRAPH3DVERTEXSTRUCT). Vertex shaders – новая возможность Direct3D. Это эдакая абстракция, символизирующая обработку вершин (вертексов). Грубо говоря, vertex shader обеспечивает перевод точки из трехмерного пространства модели в двумерную картинную плоскость. Вы можете написать на особом языке скрипт, обеспечивающий этот перевод, а можете использовать один из поддерживаемых стандартных механизмов, что мы и сделаем. Наш vertex shader D3DFVF_GRAPH3DVERTEX определен как D3DFVF_XYZ | D3DFVF_NORMAL. Это означает, что каждая точка характеризуется 6-ю числами. Первые 3 из них трактуются как координаты вершины, остальные – как компоненты нормали.
После установки необходимых потока данных и вертекс-шейдера мы можем вызвать метод DrawPrimitive(), который отображает данные из вертекс-буфера на плоскость back-буфера. Способ рендеринга данных выбирается первым параметром этого метода – он может быть одним из значений перечисляемого типа D3DPRIMITIVETYPE: D3DPT_POINTLIST, D3DPT_LINELIST, D3DPT_LINESTRIP, D3DPT_TRIANGLELIST, D3DPT_TRIANGLESTRIP или D3DPT_TRIANGLEFAN. Я решил, что наиболее подходящим способом для построения графика функции является использование D3DPT_TRIANGLESTRIP, поскольку этот способ требует относительно немного памяти для хранения данных о поверхности. Триангуляции области построения графика осуществляется как показано на следующем рисунке.
Рисунок: триангуляции
Все это работает следующим образом: вертекс-буфер содержит точки P1, P2, P3, P4 и так далее. Когда я вызываю функцию DrawPrimitive() с параметром D3DPT_TRIANGLESTRIP, Direct3D начинает отображать треугольники 1, 2, 3 и так далее. Треугольник 1 определяется точками P1, P2, P3, треугольник 2 – P2, P3, P4. Таким образом, N точек, находящихся в вертекс-буфере, соответствуют (N-2) треугольникам. Все очень хорошо, но есть и недостатки: все треугольники получаются связаны друг с другом. Вот почему четные ряды триангулируются слева направо, а нечетные – наоборот. Думаю, нет необходимости напоминать, что всякого рода нумерации у меня начинаются с нуля.
Реализация всего этого находится в методе C3DGraphic::RecalculateData(). Эта функция использует вспомогательный класс CGraphGrid, который обеспечивает построение сетки графика функции.