| netlib.narod.ru | < Назад | Оглавление | Далее > |
Давайте попробуем изобразить на экране сценку из жизни леса: в ветвях весело щебечут птички, журчит ручеек, где-то ухает филин. Неплохая мысль — но для начала придется нарисовать что-нибудь, хотя бы отдаленно напоминающее дерево. На рис. 4.25 изображена елка (команда Edit | A Tree).

Рис. 4.25. Елка
Конечно, елки бывают и покрасивее, но пока сойдет и такая. Наше дерево состоит из 25 вершин и 19 граней. Если мы хотим создать целый лес из 100 деревьев (из остальных елок сделали бумагу для книги, которую вы читаете), можно включить в макет еще 99 деревьев, похожих на рис. 4.25. Самое время подумать о том, как приказать механизму визуализации нарисовать еще 99 деревьев, в точности аналогичных первому, но расположенных в других местах макета.
Помните, что мы говорили о фреймах и визуальных элементах в главе 3? Объект C3dShape содержит фрейм, определяющий его положение, размер, ориентацию и т.д., а также визуальный элемент, который по сути дела описывает набор вершин, граней и т.д. для объекта, который мы хотим увидеть на экране. Функция C3dShape::Clone позволяет включить один и тот же визуальный элемент в несколько разных фреймов. Она создает новый объект C3dShape по существующему объекту, но вместо того, чтобы строить для него новый визуальный элемент, она присоединяет к объекту визуальный элемент исходной фигуры. Таким образом, чтобы изобразить лес, можно создать одно дерево и продублировать его 99 раз. Результат изображен на рис. 4.26 (команда Edit | A Forest).

Рис. 4.26. Лес
Давайте рассмотрим функцию, в которой строится лес, поскольку некоторые аспекты процесса дублирования оказываются неочевидными.
void CMainFrame::OnEditForest()
{
NewScene();
// Создать первое дерево вместе со стволом
m_pShape = new C3dShape;
m_pShape->CreateCone(0, 0, 0, 1, TRUE,
0, 4, 0, 0, FALSE);
C3dShape trunk;
trunk.CreateRod(0, -2, 0, 0, 0, 0, 0.2);
m_pShape->AddChild(&trunk);
// Присоединить дерево к макету
m_pScene->AddChild(m_pShape);
// Получить позицию и ориентацию ствола
// по отношению к родителю (дереву)
C3dVector p, d, u;
trunk.GetPosition(p);
trunk.GetDirection(d, u);
// Дублировать дерево 99 раз
for (int i = 0; i < 99; i++) {
// Дублировать крону и ствол
C3dShape* pTree = m_pShape->Clone();
C3dShape* pTrunk = trunk.Clone();
pTree->AddChild(pTrunk);
// Задать относительную позицию ствола
// по отношению к кроне
pTrunk->SetPosition(p);
pTrunk->SetDirection(d, u);
// Присоединить дубли как потомков первого дерева,
// чтобы можно было вращать весь лес
m_pShape->AddChild(pTree);
// Задать положение нового дерева в макете
pTree->SetPosition(((double)(rand() % 100) / 5) — 10.0,
0, (double)(rand() % 100) / 5, m_pScene);
// Удалить контейнеры
delete pTrunk;
delete pTree;
}
}
Непременно обратите внимание на то, что ствол присоединяется в качестве потомка к конусу, образующему крону дерева, поэтому при дублировании кроны со стволом важно, чтобы при присоединении ствола-дубликата к кроне-дубликату была сохранена их относительная позиция. Если этого не сделать, ствол будет развернут в каком-нибудь странном направлении и по всей вероятности вообще не будет соединен с кроной. Попробуйте закомментировать фрагменты позиционирования (pTree->SetPosition) и ориентации ствола и заново постройте приложение, чтобы посмотреть, что из этого получится.
Второй важный момент заключается в том, что деревья-дубликаты становятся потомками самого первого дерева, чтобы можно было вращать весь лес с помощью одной переменной m_pShape (первое дерево). Поскольку дубликаты являются потомками первого дерева, их позиция должна быть задана по отношению ко всему макету. Если удалить из вызова pTree->SetPosition необязательный аргумент-фрейм (m_pScene), позиция будет указываться по отношению к родителю, и деревья расположатся неверно. Проверьте!
| netlib.narod.ru | < Назад | Оглавление | Далее > |