Пример 08 - Полный штиль
Этот пример демонстрирует использование специальных эффектов и моделирования сложного
освещение.
Оттенки Неба
Чтобы нарисовать небо мы будем пользоваться спрайтом без текстуры:
hgeSprite *sky;
sky=new hgeSprite(0, 0, 0, SCREEN_WIDTH, SKY_HEIGHT);
Его верхние и нижние вершины окрашены в разные цвета, плавно переходящие друг в друга:
hgeColor colSkyTop;
hgeColor colSkyBtm;
sky->SetColor(colSkyTop.GetHWColor(), 0);
sky->SetColor(colSkyTop.GetHWColor(), 1);
sky->SetColor(colSkyBtm.GetHWColor(), 2);
sky->SetColor(colSkyBtm.GetHWColor(), 3);
sky->Render(0, 0);
Цвет неба зависит от времени суток и вычисляются посредствам интерполяции между несколькими
константными значениями:
hgeColor col1, col2;
col1.SetHWColor(skyTopColors[seq[seq_id]]);
col2.SetHWColor(skyTopColors[seq[seq_id+1]]);
colSkyTop=col2*seq_residue + col1*(1.0f-seq_residue);
col1.SetHWColor(skyBtmColors[seq[seq_id]]);
col2.SetHWColor(skyBtmColors[seq[seq_id+1]]);
colSkyBtm=col2*seq_residue + col1*(1.0f-seq_residue);
Море и Волны
Похожая техника раскрашивания применяется и для моря. Но в этот раз мы воспользуемся классом
hgeDistortionMesh вместо класса hgeSprite
для моделирования волн:
hgeDistortionMesh *sea;
sea=new hgeDistortionMesh(SEA_SUBDIVISION, SEA_SUBDIVISION);
sea->SetTextureRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT-SKY_HEIGHT);
Чтобы создать водны, мы установим перемещение и окраску для каждого узла сетки искажения (мы опустим
первую и последнюю строчки так как мы не хотим, чтобы они двигались):
for(i=1; i<SEA_SUBDIVISION-1; i++)
{
// these are constants for each vertices line
a=float(i)/(SEA_SUBDIVISION-1);
col1=colSeaTop*(1-a)+colSeaBtm*a;
dwCol1=col1.GetHWColor();
fTime=2.0f*hge->Timer_GetTime();
a*=20;
for(j=0; j<SEA_SUBDIVISION; j++)
{
sea->SetColor(j, i, dwCol1);
dy=a*sinf(seaP[i]+ // precalculated phase shift
(float(j)/(SEA_SUBDIVISION-1)-0.5f)*M_PI*16.0f-fTime);
sea->SetDisplacement(j, i, 0.0f, dy, HGEDISP_NODE);
}
}
Теперь установим окраску для пропущеных первой и последней строк узлов сетки искажения:
dwCol1=colSeaTop.GetHWColor();
dwCol2=colSeaBtm.GetHWColor();
for(j=0; j<SEA_SUBDIVISION; j++)
{
sea->SetColor(j, 0, dwCol1);
sea->SetColor(j, SEA_SUBDIVISION-1, dwCol2);
}
Теперь море готово и мы рисуем его одним единсвтенным вызовом:
sea->Render(0, SKY_HEIGHT);
В настоящем исходном коде еше добавлена эмуляция луны и солнца. Чтобы это сделать, мы просто добавим
немного белый окрас в узлы сетки искажения которые находятся прямо под солцем/луной.
Небесные Тела
Звезды, луна и солнце являются просто масштабированными и подкрашенными спрайтами:
hgeSprite *sun;
hgeSprite *moon;
hgeSprite *star;
sun=new hgeSprite(texObjects,81,0,114,114);
sun->SetHotSpot(57,57);
moon=new hgeSprite(texObjects,0,0,81,81);
moon->SetHotSpot(40,40);
star=new hgeSprite(texObjects,72,81,9,9);
star->SetHotSpot(5,5);
Интересная деталь - хало и отражения на поверхности воды. Это тоже обычные спрайты:
hgeSprite *glow;
hgeSprite *seaglow;
glow=new hgeSprite(texObjects,128,128,128,128);
glow->SetHotSpot(64,64);
glow->SetBlendMode(BLEND_COLORADD | BLEND_ALPHABLEND);
seaglow=new hgeSprite(texObjects,128,224,128,32);
seaglow->SetHotSpot(64,0);
seaglow->SetBlendMode(BLEND_COLORADD | BLEND_ALPHAADD);
Заметьте, что спрайты хало различаются методами смешивания, чтобы достичь правильных цветов. Так же
заметьте, что оба спрайта делять одну и туже область текстуры.
Позиция солнца и луны, масштабирование и окраска вычисляются в функции UpdateSimulation
и затем все объекты отображаются в функции RenderSimulation:
glow->SetColor(colSunGlow.GetHWColor());
glow->RenderEx(sunX, sunY, 0.0f, sunGlowS);
sun->SetColor(colSun.GetHWColor());
sun->RenderEx(sunX, sunY, 0.0f, sunS);
glow->SetColor(colMoonGlow.GetHWColor());
glow->RenderEx(moonX, moonY, 0.0f, moonGlowS);
moon->SetColor(colMoon.GetHWColor());
moon->RenderEx(moonX, moonY, 0.0f, moonS);
Тоже самое для отражений на море:
seaglow->SetColor(colSeaGlow.GetHWColor());
seaglow->RenderEx(seaGlowX, SKY_HEIGHT,
0.0f, seaGlowSX, seaGlowSY);
Заметьте, что спрайт отражения на море масштабируется не пропорционально.
Производительность
Несмотря на видимую сложность, этот пример выполняется с довольно высоким FPS. Это становится
возможным благодаря выводу спрайтов через Direct3D, узким местом является пропускная
способность текстур. И этот пример рисует всего лишь несколько спрайтов из маленькой текстуры.
Большие области экрана заполняются сплошным цветом.
Полный исходный код с детальными комментариями для этого примера вы можете найти в директории tutorials\tutorial08.
Требуемые медиа файлы можно найти в директории tutorials\precompiled.
Используйте клавиши 1 по 9 чтобы изменить скорость воспроизведения, 0 для
реального времени и ESC чтобы выйти.
|