Заблокирован
Старожил
Регистрация: 20.07.2008
Сообщений: 4,032
|
Цитата:
В этой статье вы узнаете, как создавать реалистичные молнии и выводить их на экран. Выводить молнии на экран мы будем по массиву точек, полученных алгоритмом, который называется “Фрактализация отрезка”. Рендерить ее можно многими способами и я опишу все, которые дают приемлемую картинку.
Фрактализация отрезка
Этот метод заполняет массив (Array of TVector) точками, определяющими тело молнии. Вся сложность заключается в том, чтобы создать кривую, по форме похожую на реальную молнию. Метод фрактализации отрезка заключается в том, что кривая формируется рекурсивным делением отрезка и заменой на случайное колено. Для начала рассмотрим двумерный случай фрактализации. Допустим, нам даны две концевые точки A и B (это начало молнии и ее конец). Первым шагом мы заменяем отрезок AB двумя отрезками AC и CB, где точка C выбирается случайным образом вдоль срединного перпендикуляра отрезка AB, причем она может лежать по обе стороны отрезка. Далее мы рекурсивно делим отрезки AC и CB, получим уже 4 отрезка AD, DC, CE и EB, далее делим их и так делаем до получения желанной кривой.
Но как определить, что нужно остановить рекурсию? Глубину рекурсии можно контролировать по ее уровню (то есть когда уровень рекурсии достигнет какого то числа или по длине отрезка прямой. Если молния не будет занимать много пикселей на экране, тогда можно продолжать рекурсию, до предела разрешающей способности самого монитора. Но я использовал первый метод и вам советую, это дает хорошее управление глубиной фрактализации.
Теперь, о том, как формировать кривую в пространстве. Здесь точка C будет выбираться случайным образом из плоскости, перпендикулярной отрезку и лежащей на его середине. Для этого находим два вектора, допустим PlaneU и PlaneV, с помощью векторных произведений. Эти вектора и будут представлять нужную плоскость точек.
Кратко формулу получения точки C можно записать так:
Код:
C = 0.5 * (A+B) + factor * (PlaneU * RND + PlaneV * RND)
Здесь RND - дает случайное число от -0,5 до 0,5, а factor - это величина возмущения. То есть, чем больше factor, тем сильнее дергается молния. Нормальное значение factor от 0,1 до 0,4.
Код:
Dir := VectorSubtract(A, B);
PlaneU := VectorCrossProduct(Dir, YAxis);
PlaneV := VectorCrossProduct(PlaneU, Dir);
NormalizeVector(PlaneU);
NormalizeVector(PlaneV);
C[0] := 0.5*(A[0] + B[0]) + factor*(PlaneU[0]*(random-0.5) + PlaneV[0]*(random-0.5));
C[1] := 0.5*(A[1] + B[1]) + factor*(PlaneU[1]*(random-0.5) + PlaneV[1]*(random-0.5));
C[2] := 0.5*(A[2] + B[2]) + factor*(PlaneU[2]*(random-0.5) + PlaneV[2]*(random-0.5));
Теперь, когда мы получили точку C, нам нужно рекурсивно разделить полученные отрезки. Все полученные точки занесем в массив Points, чтобы потом вывести их на экран. Вот код этой процедуры:
Код:
procedure Fract(A, B : TVector; factor : Single; maxFracDepth, fracCount : Byte);
var
Dir, PlaneU, PlaneV, C : TVector;
begin
inc(fracCount); // Увеличим глубину рекурсии
if fracCount > maxFracDepth then // Если then глубина рекурсии больше заданной, тогда…
begin
inc(numPoints);
points[numPoints] := B; // Сохраним точку и выходим
exit;
end;
Dir := VectorSubtract(A, B);
PlaneU := VectorCrossProduct(Dir, YHmgVector);
PlaneV := VectorCrossProduct(PlaneU, Dir);
NormalizeVector(PlaneU);
NormalizeVector(PlaneV);
C[0] := 0.5*(A[0] + B[0]) + factor*(PlaneU[0]*(random-0.5) + PlaneV[0]*(random-0.5));
C[1] := 0.5*(A[1] + B[1]) + factor*(PlaneU[1]*(random-0.5) + PlaneV[1]*(random-0.5));
C[2] := 0.5*(A[2] + B[2]) + factor*(PlaneU[2]*(random-0.5) + PlaneV[2]*(random-0.5));
Fract(A, C, factor*fracDec, maxFracDepth, fracCount); // Рекурсивно делим отрезок AC
Fract(C, B, factor*fracDec, maxFracDepth, fracCount); // Рекурсивно делим отрезок CB
end;
Чтобы кривая выглядела правильно, нужно уменьшать уровень возмущения (factor) по мере увеличения глубины рекурсии. Для этого я ввел переменную fracDec, на которую умножается factor; она должна быть меньше единицы и больше нуля. Нормальное ее значение около 0.5 или 0.6.
Вот код процедуры, объединяющей все вышесказанное:
Код:
procedure DoFractalLightning(Src, Dst : TVector;
factor{сила возмущения},
fracDec{коэффициент ослабления возмущения}: Single;
maxFracDepth{максимальная глубина} : Byte;
cR, cG, cB {цвет}: Single);
var i : Integer;
begin
numPoints := 0;
points[0] := Src;
fracLev := fracLev * VectorDistance(Src, Dst);
Fract(Src, Dst, factor, maxFracDepth, 0);
end;
С помощью параметров factor и fracDec можно управлять молнией. Немного изменяйте эти параметры, и вы поймете, как они влияют на генерацию молнии.
Александр Гарустович
http://www.mirgames.ru/
|
Взял из сборника Delphi_Full.
// Не посчитайте за рекламу)))
|