Программирование графики с использованием Direct3D

         

Функция MoleculeWin::CreateChildren()


Функция CreateChildren() назначает атрибуты вращения, присоединяет сетки и создает дочерние фреймы.

BOOL MoleculeWin::CreateChildren(LPDIRECT3DRMFRAME frame, int depth) { LPDIRECT3DRMFRAME parent; frame->GetParent(&parent); D3DVECTOR vector; D3DRMVectorRandom(&vector); frame->SetRotation(parent, vector.x, vector.y, vector.z, D3DVALUE(rand() % 100) / D3DVALUE(1000) + D3DVALUE(.1)); frame->AddVisual(mesh[curdepth - depth]); if (depth > 1) { LPDIRECT3DRMFRAME child; d3drm->CreateFrame(frame, &child); static int count; count++; D3DVALUE trans = distance[curdepth - depth]; D3DVALUE smalltrans = trans / D3DVALUE(2); D3DVALUE xtrans = (count % 2) ? trans : -trans; D3DVALUE ytrans = (rand() % 2) ? smalltrans : -smalltrans; D3DVALUE ztrans = (rand() % 2) ? smalltrans : -smalltrans; child->SetPosition(frame, xtrans, ytrans, ztrans); for (int i = 0; i < numchildren; i++) CreateChildren(child, depth - 1); } return TRUE; }

Сначала функция CreateChildren() назначает полученному фрейму атрибут вращения. Чтобы сделать это, необходимо получить указатель на фрейм, являющийся родителем полученого фрейма. Для этой цели применяется функция GetParent() интерфейса Direct3DRMFrame. Как только родительский фрейм становится известен, выполняется вычисление и назначение атрибутов вращения:

D3DVECTOR vector; D3DRMVectorRandom(&vector); frame->SetRotation(parent, vector.x, vector.y, vector.z, D3DVALUE(rand() % 100) / D3DVALUE(1000) + D3DVALUE(.1));

Обратите внимание, что фрейм parent передается функции SetRotation() в ее первом аргументе. Однако сперва с помощью функции D3DRMVectorRandom() выполняется вычисление случайного вектора, который используется для получения следующих трех аргументов функции SetRotation(). При вычислении последнего аргумента функции SetRotation(), определяющего скорость вращения, используется функция rand(). Выражение, применяемое для вычисления скорости обеспечивает случайный выбор значения в диапазоне от медленной до средней скорости.

Затем к фрейму присоединяется соответствующая сетка:

frame->AddVisual(mesh[curdepth - depth]);

Выбор сетки зависит от глубины текущего фрейма в иерархии. Оставшаяся часть функции CreateChildren() выглядит так:

if (depth > 1) { LPDIRECT3DRMFRAME child; d3drm->CreateFrame(frame, &child); static int count; count++; D3DVALUE trans = distance[curdepth - depth]; D3DVALUE smalltrans = trans / D3DVALUE(2); D3DVALUE xtrans = (count % 2) ? trans : -trans; D3DVALUE ytrans = (rand() % 2) ? smalltrans : -smalltrans; D3DVALUE ztrans = (rand() % 2) ? smalltrans : -smalltrans; child->SetPosition(frame, xtrans, ytrans, ztrans); for (int i = 0; i < numchildren; i++) CreateChildren(child, depth - 1); }

Выполнение этой части кода зависит от значения параметра depth. Код выполняется, если значение depth больше единицы. Код создает новый дочерний фрейм с помощью функции CreateFrame() интерфейса Direct3DRM. Новый фрейм позиционируется на основе полученных псевдослучайных чисел. Статическая переменная счетчика используется, чтобы при дальнейших вычислениях избежать получения обескураживающе предсказуемых результатов. Вычисленная позиция назначается фрейму функцией SetPosition().

В завершение функция CreateChildren() вызывает сама себя. Используемый для вызова функции цикл зависит от числа дочерних фреймов, которые должны быть присоединены. Обратите внимание, что в качестве второго аргумента CreateChildren() используется выражение depth– 1. Как только значение параметра depth станет равным единице, создание дочерних фреймов прекратится. Если из аргумента, задающего глубину не вычесть единицу, функция будет бесконечно вызывать сама себя.



Содержание раздела