Среда, 01.05.2024, 21:38
Приветствую Вас Заблудший(Гость) | RSS
Главная | Рассеивание частиц (Particle Engine) - Форум | Регистрация | Вход
Меню сайта
Форма входа
Друзья сайта

Статистика
pIR

[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 1
  • 1
Форум » Программирование » 3D програмирование 2d программирование » Рассеивание частиц (Particle Engine) (учимсо, разбираемсо и т.д.)
Рассеивание частиц (Particle Engine)
GotSutinerДата: Среда, 11.02.2009, 12:34 | Сообщение # 1
Первенец
Группа: Проверенные
Сообщений: 31
Репутация: 1
Статус: Offline
итак, собственно начнем:

рассеивание частиц (Particle Engine)

так вот - на данном скрине мы види что ? - да СНЕГ,ДЫМ и ФОНТАНЧИК ))

Сразу давайте оговоримся, термин billboard означает прямоугольник, состоящий из двух треугольных полигонов, причем данный прямоугольник покрыт текстурой.
Термин alpha-blending означает прозрачность.

Основы.

Работа с частицами похожа на демку billboards, которая есть в Direct3D SDK. Вообще, что такое в трехмерной графике фонтан, огонь, дым, взрыв и тому подобные эффекты, никогда не задумывались? Физически, это только связка прозрачных текстурируемых прямоугольников - полигонов, на которые наложенна текстура взрыва или дыма. На каждый полигон накладывается разная текстура, на экране же прокручивается вереница полигонов и создается иллюзия взрыва или дыма. На самом деле эти полигоны - кадры прокручиваются как пленка в кинотеатре. Вашего воображения достаточно для создания каких угодно эффектов, главное задать алгоритм "разбрасывания" полигонов.

Поскольку демка billboards важный этап в понимании работы с частицами, давайте подытожим, что мы знаем:

1). billboard это - прямоугольник, состоящий из двух треугольных полигонов
2). на этом прямоугольнике находиться текстура (взрыва, дождя)
3). они находятся всегда лицом к камере [b]

Это скриншот из демки billboards из Direct3D SDK.
Вот эти деревья на скриншоте и есть billboards - прямоугольники,
покрытые текстурой, про которые мы с вами говорили.

В дополнение к характеристикам billboards добавим, что эти частицы почти всегда прозрачны, то есть:
D3DRENDERSTATE_ALPHABLENDENABLE всегда имеет значение TRUE.

Скоро мы вернемся к alpha-blending (к прозрачности). Но сначала давайте решим другую проблему: как сделать, чтобы каждая частица была повернута лицом к камере, а не к примеру углом или ребром? Как Вы знаете, вершина в трехмерной графике задается тремя матрицами: мировой матрицей (world matrix), матрицей вида (view matrix) и матрицей проекции (projection matrix). Очевидно мы должны применить следующую трансформацию: вращение к матрице вида (наше представление камеры). Мы хотим ведь, чтобы наши частицы могли переноситься в трехмерном пространстве, увеличиваться или уменьшаться в масштабе, но при этом не в коем разе не поворачиваться к камере ребром (иначе мы эффекта разбрасывания просто не увидим, видите, на скриншоте деревья повернуты к камере лицом, а не ребром).
Мы должны сделать следующее - применить матрицу вида к позиции каждой частицы вручную (чтобы задать алгоритм разбрасывания). После этого мы задаем прямоугольник, позиционируя четыре его вершины вокруг центра этого прямоугольника. Z-координата будет той же самой (0. 0f) для всех вершин. При прорисовке (рендеринге) частицы (прямоугольника) трансформация вида должна быть выключена, так, чтобы вершина не трансформировалась дважды. У вас еще крыша не поехала? Ничего, это лишь пояснение к коду.
Короче, смотрите код, который создает нашу частицу:

//////////////////////////////Код C++

// получаем текущую матрицу вида:

D3DMATRIX matView;
lpDevice->GetTransform(D3DTRANSFORMSTATE_VIEW, &matView);

D3DVECTOR Pos = Particles[i].Position;
D3DVECTOR TransPos; // Transformed position
// Apply the view matrix to the position vector:
TransPos.x = Pos.x * matView(0, 0) + Pos.y * matView(1, 0) + Pos.z * matView(2, 0) + matView(3, 0);
TransPos.y = Pos.x * matView(0, 1) + Pos.y * matView(1, 1) + Pos.z * matView(2, 1) + matView(3, 1);
TransPos.z = Pos.x * matView(0, 2) + Pos.y * matView(1, 2) + Pos.z * matView(2, 2) + matView(3, 2);

D3DLVERTEX Shape[4];
// upper left:
Shape[0] = D3DLVERTEX(
TransPos + D3DVECTOR(-0.5f*Particles[i].Size, 0.5f*Particles[i].Size, 0.0f),
ParticleColor, 0xffffffff, // color (with alpha) and specular color
0.0f, 0.0f); // texture coords
// upper right:
Shape[1] = D3DLVERTEX(
TransPos + D3DVECTOR(0.5f*Particles[i].Size, 0.5f*Particles[i].Size, 0.0f),
ParticleColor, 0xffffffff, 1.0f, 0.0f);
// lower left:
Shape[2] = D3DLVERTEX(
TransPos + D3DVECTOR(-0.5f*Particles[i].Size, -0.5f*Particles[i].Size, 0.0f),
ParticleColor, 0xffffffff, 0.0f, 1.0f);
// lower right:
Shape[3] = D3DLVERTEX(
TransPos + D3DVECTOR(0.5f*Particles[i].Size, -0.5f*Particles[i].Size, 0.0f),
ParticleColor, 0xffffffff, 1.0f, 1.0f);

Этот графический примитив (наш прямоугольник) может быть прорисован, как два треугольника:

//////////////////////////////Код C++
lpDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_LVERTEX, Shape, 4, NULL);

Обратите внимание: Вместо того, чтобы писать ваш собственный код для применения матрицы к вектору, Вы можете использовать функцию D3DMath_VectorMatrixMultiply из DirectX SDK D3DFrame.

Обратите внимание: Вы не должны использовать вершины D3DLVERTEX. С этими вершинами проще применить новые значения прозрачности и цвета без необходимости устанавливать материал. Кроме того, на многие системы частиц нельзя повлиять световыми источниками во всяком случае (огонь, например, испускает собственный источник света, также как взрывы).

 
GotSutinerДата: Среда, 11.02.2009, 12:42 | Сообщение # 2
Первенец
Группа: Проверенные
Сообщений: 31
Репутация: 1
Статус: Offline
Alpha-blending

Для particle систем Alpha прозрачность имеет следующее значение (на рисунках это наглядно показано).


На левом скриншоте вы видите прорисовку частиц без Alpha прозрачности. Вы можете наглядно увидеть, что весь этот, на первый взгляд сложный эффект огня состоит из движения прямоугольников, покрытых текстурой, как я уже объяснял. А на правом рисунке вы видите тот же самый эффект, но с включенной Alpha прозрачностью, при этом blend factor установлен как D3DBLEND_ONE.

Нет ничего хитрого в работе разбрасывания частиц при Alpha прозрачности. Тогда вот вам формула для вычисления конечного цвета нашего спецэффекта. (FinalColor = DestColor ? DestBlendFactor + SrcColor ? SrcBlendFactor). Что можно перевести примерно как: Конечный цвет = Имеющийся цвет ? Имеющийся фактор прозрачности + SrcColor ? SrcBlendFactor). Да, конечно, сейчас это для вас не понятно, но не расстраивайтесь, ниже будет пример исходного кода, вот на его примере вы все и поймете. Фактически, вы можете задавать любую комбинацию цветов для нашего "огня" по этой формуле. Однако для обычной системы частиц некоторые цвета все же предпочтительнее других.

Например, если большее количество частиц находиться в верхней части, тогда по идее в этой области свет должен быть более яркий. Так, одиночная белая частица с непрозрачностью 0. 5f изменила бы черный фон на
50 процентный серый фон. Вторая частица, в той же самой позиции (или частично перекрывая первую частицу) изменила бы фон еще больше, на 75 процентов или даже на 100 процентов. Смотрите рисунок.

Одна частица делает фон, на 50 % серым, две частицы делают его на 75 % серым, три частицы делают его
на 87.5 % серым.

Нужная величина прозрачности может быть достигнута смешиванием исходного коофицента (источника) D3DBLEND_SRCALPHA и требуемого коофицента прозрачности (адресата) D3DBLEND_INVSRCALPHA :

//////////////////////////////Код C++

lpDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
lpDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);

Обратите внимание: Смешиваемые режимы требуют, чтобы текстура частицы имела alpha - канал. (файлы текстур DDS поддерживают это, DDS файлы вы можете конвертировать из любого файла, используя утилиту dxtex.exe из DirectX SDK.) Иначе весь прямоугольник - частица будет блеклым. Чуть позже будет разъяснено, как избежать этого эффекта.

Если мы просто добавим цвет, смешивая источник и адресат как предыдущее смешивание режимов D3DBLEND_ONE, то у нас не всегда получится желаемый результат. Не понятно? Речь идет о смешивании цветов в частицах, и о том, к чему это приводит. Например: берем частицу с красным цветом (1, 0, 0) на синем фоне
(0, 0, 1). Красная частица это типа источник, а синяя типа адресат. Таким образом, при смешивании цвета частицы с фоном одиночная частица изменила бы цвет адресата на сиреневый (1, 0, 1), то есть при прорисовке красных частиц на синем фоне мы получим сиреневый огонь. Так вот, при прорисовке второй частицы в том же самом месте цвет нашего огня не измениться (а надо бы) - наложение двух красных частиц друг на друга при синем фоне не изменит цвет огня. А нам надо, чтобы изменила, тогда наложением частиц можно создавать различные оттенки цветов огня. В нашем случае красные и синие компоненты уже насыщены и добавление зеленого компонента уже не подействует на частицы.
Надо при задании цвета писать не целочисленное значение, а дробное, например: 1. 0f, 0. 1f, 0. 1f. Это бы гарантировало, что дополнительные частицы повлияют на цвет нашего огня. Однако, такая запись цвета не делает наши частицы ярче (все равно нельзя задавать оттенки насыщенности при наложении частиц друг на друга, ведь в спецэффекте только начальные значения цвета задается значениями RGB, а дальнейшие оттенки яркости должны получаться при наложении двух одноцветных частиц друг на друга, что мы сделать пока не можем), наоборот, в конечном итоге мы получим белый цвет.

В итоге ясно, что не возможно затемнить пикселы адресата (огня) или одиночные цветные каналы (величины RGB). Они будут по крайней мере такими же яркими, как и были. А нам необходимо чтобы это было возможно, тогда мы сможем задавать любые цветовые оттенки для спецэффектов (смотрите рисунок выше). Нам может помочь только одна вещь - текстура с альфа - каналом...

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

Внимание, если вы плохо знакомы с alpha-blending, вам будет труднее понять все.

Сообщение отредактировал GotSutiner - Среда, 11.02.2009, 12:44
 
Форум » Программирование » 3D програмирование 2d программирование » Рассеивание частиц (Particle Engine) (учимсо, разбираемсо и т.д.)
  • Страница 1 из 1
  • 1
Поиск:
Copyright Piraties © 2024