Рейтинговые книги
Читем онлайн Программирование на Visual C++. Архив рассылки - Алекс Jenter

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 86 87 88 89 90 91 92 93 94 ... 156

Рисунок: триангуляции

Все это работает следующим образом: вертекс-буфер содержит точки 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, который обеспечивает построение сетки графика функции.

Управление светом в Direct3D8.

Direct 3D имеет довольно мощные средства для работы с освещением 3D-сцены. Поддерживается несколько различных типов источников света: параллельный (directional), точечный (point-source) и прожектор (spotlight). Параллельный свет не имеет источника – только направление. В качестве аналогии приведу солнце: все его лучи параллельны (простите, физики и астрономы!). Точечный свет и прожектор имеют вполне определенную точку, из которой исходят все лучи. Точечный свет испускается во все стороны, а прожектор имеет строго очерченный конус распространения лучей. Для получения более подробной информации можете обратиться к DirectX 8.0a SDK. Сейчас меня больше интересует другое. Есть одна проблема: все точки (vertexes), которые принимают участие в вычислении освещенности сцены должны включать вектор нормали. Определение нормали на самом деле очень просто, если Вы все еще помните курс школьной геометрии. Как это сделать? Есть, как минимум, 2 пути:

Во-первых, мы можем найти аналитическое выражение, описывающее координаты вектора нормали. Это будет очень точный результат, но для каждого новой 3D-функции придется провести все выкладки заново.

Во-вторых, мы можем рассчитать примерные координаты нормали исходя из координат точки, в которой определяется нормаль и координат соседних с ней точек. Пусть это лишь приближенное решение: его вполне достаточно для наших целей. К тому же оно зато абсолютно не зависит от самой функции. Именно этот подход реализован в демо-приложении и Вы можете найти его в функции C3DGraphic::CalcNormal(). Попробую прокомментировать сам алгоритм.

Рисунок: расчет нормали

– Находим 4 вектора к соседним точкам:

V01 = P1 – P0;

V02 = P2 – P0;

V03 = P3 – P0;

V04 = P4 – P0;

– Находим 4 нормали к каждой из треугольных граней. Нормали находятся как векторное произведение соответствующих векторов.

N1 = [V02, V01];

N2 = [V03, V02];

N3 = [V04, V03];

N4 = [V01, V04];

– Искомая нормаль определяется как средний вектор четырех ранее найденных нормалей.

N = (N1 + N2 + N3 + N4) / 4;

Управление материалами.

Все в этом мире имеет цвет. Цвет определяет восприятие нами окружающего мира. Яблоко – красное, небо – синее и так далее. Для обозначения свойств поверхности объектов Direct3D использует термин "материал". Свойства материала описываются структурой D3DMATERIAL8:

typedef struct _D3DMATERIAL8 {

 D3DCOLORVALUE Diffuse;

 D3DCOLORVALUE Ambient;

 D3DCOLORVALUE Specular;

 D3DCOLORVALUE Emissive;

 float         Power;

} D3DMATERIAL8;

Переменные Diffuse, Ambient и Specular определяют, как данный материал отражает соответствующие компоненты источников света. Кроме того, Вы можете указать мощность, с которой отражается зеркальная (specular) составляющая света – это определяет вид бликов на объектах. Ненулевая излучательная (emissive) компонента заставляет объект светится, но помните, что свет, излученный объектом, никак не отражается прочими объектами сцены. Только источники света имеют право освещать кого-либо.

Для установки свойств материала объекта Вы должны вызвать функцию SetMaterial() перед вызовом DrawPrimitive() или любой другой функции рендеринга. Делается это, например, вот так:

hr = m_p3DDevice->SetMaterial(&m_theGraphMaterial);

ATLASSERT(SUCCEEDED(hr));

if (FAILED(hr)) {

 return hr;

}

За подробностями обращайтесь к исходному коду моего проекта. Экспериментируйте, меняйте параметры, пишите, если что-то непонятно.

Вместо заключения

В конце я бы хотел сказать еще несколько слов по поводу демо-приложения. Оно имеет 4 окна свойств, каждое из которых может быть активировано из меню "Properties". Коротко опишу назначение каждого из окон:

• Material properties. Это окошко позволяет изменить свойства материала поверхности функции: диффузионную (diffuse), окружающую (ambient), излучательную (emissive) и зеркальную (specular) компоненты, а также мощность отражения (specular power).

• Light properties. Сцена освещена одним параллельным источником света. Вы можете изменить любую из составляющих спектра света. Кроме того, можно скорректировать направление света.

• Background color. Это всего-навсего цвет, используемый для очистки каждого нового кадра. Вы можете выбрать любой цвет фона по Вашему усмотрению.

• Function type. Вы можете выбрать одну из трех функций: Splash-функцию, плоскость или параболоид.

Все значения в окнах свойств редактируются с помощью трэкбаров. 0 – минимальное значение, 1 – максимальное. Минимальному значению соответствует нижнее положение трэкбара, максимальному – верхнее.

ПРИМЕЧАНИЕ

DirectX, Direct3D, Windows, Microsoft являются торговыми марками компании Microsoft. Все права защищены. OpenGL является торговой маркой фирмы Silicon Graphics Inc. Все права защищены.

ВОПРОС-ОТВЕТ 

Почему вместо нормального контекстного меню появляется узкая полоска?

Автор: Александр Шаргин

Обычно такая проблема возникает, когда вы пытаетесь выполнить код следующего вида:

POINT pt;

GetCursorPos(&pt);

HMENU hMenu;

hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(_MENU1));

TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hWnd, NULL);

DestroyMenu(hMenu);

В чём же здесь ошибка? Дело в том, что в Windows существует два совершенно разных вида меню – полоска меню (menu bar), которая традиционно размещается под заголовком окна, и всплывающее меню (popup menu). Работа и с тем, и с другим осуществляется с помощью хэндла типа HMENU. Это вносит некоторую путаницу, так как функции, предназначенные для работы с всплывающим меню, не могут работать с полоской меню, и наоборот.

Дескриптор всплывающего меню возвращают всего две функции – CreatePopupMenu и GetSubMenu. Именно эти функции можно использовать совместно с TrackPopupMenu(Ex). С другой стороны, функция LoadMenu загружает из ресурсов полоску меню, что и приводит к ошибке.

Описание и примеры использования функций CreatePopupMenu и GetSubMenu можно найти в статье "Как отобразить контекстное меню?".

ЭКЗАМЕН 

What two rectangular regions does Windows use to derive a scaling factor and an orientation?

1. Viewport and quadrant

2. Window and frame

3. Frame and viewport

4. Quadrant and frame

5. Window and viewport 

Верный ответ – 5. Window and viewport. Именно они используются в Windows для определения координат точек и коэффициента масштабирования. 

Это все на сегодня. Пока! 

Алекс Jenter [email protected] Duisburg, 2001. Публикуемые в рассылке материалы принадлежат сайту RSDN.

Программирование на Visual C++

Выпуск №53 от 4 ноября 2001 г.

Приветствую вас, дорогие подписчики!

Прежде всего хочу извиниться – в предыдущем выпуске в статье про Direct3D по моему недосмотру были указаны некорректные ссылки на примеры программ. Ну, все мы люди ;-) Вот верные ссылки:

Демонстрационное приложение (только .exe) (72 kb)

Демонстрационное приложение (исходный код) (44 kb)

Также ссылки исправлены в той версии выпуска, которая лежит в архиве на сайте RSDN.

И еще один вопрос: мне продолжают приходить письма с различными вопросами по программированию. К сожалению, у меня сейчас нет времени даже на то, чтобы просто отвечать на все эти письма, не говоря уже о содержащихся в них вопросах. Поэтому хочу всем напомнить, что в ФОРУМЕ на сайте RSDN вы можете получить ответ (и даже не один!) на любой свой вопрос по программированию.

Поэтому большая просьба вопросы задавать там, вам наверняка ответят. А если вы считаете какой-нибудь из вопросов очень интересным и достойным внимания подписчиков этой рассылки, то я буду благодарен, если вы мне пришлете ссылку на соответствующее сообщение форума. Дело в том, что у рассылки начиная с этого выпуска появляется новая рубрика – "ФОРУМ RSDN – ИЗБРАННОЕ", и там будут публиковаться самые интересные дискуссии. Надеюсь, это сделает рассылку для вас еще интереснее.

1 ... 86 87 88 89 90 91 92 93 94 ... 156
На этой странице вы можете бесплатно читать книгу Программирование на Visual C++. Архив рассылки - Алекс Jenter бесплатно.
Похожие на Программирование на Visual C++. Архив рассылки - Алекс Jenter книги

Оставить комментарий