Дым — это очень полезный и красивый эффект, при этом совсем не сложный.
Исходные коды возьмите из урока «Камера: часть 5«.
Переходим к редактированию main.cpp:
float g_FogDensity = 0.2f; // Плотность дыма
bool g_bFog = true; // Включен или выключен дым// Изменяем функцию Init(); включим в ней дым. Прежде всего нужно выбрать
// цвет дыма. Так как это потенциально цвет RGBA, нужно установить 4 значения.
// По умолчанию они = (0,0,0,0), и нам нужно изменить их.
// Помещаем наши цвета в массив, т.к. ф-я glFogfv принимает их в таком виде.float fogColor[4] = {0.0f,0.0f,1.0f,1.0f};// Установим цвет мира таким же, как цвет тумана:
glClearColor(0, 0, 1, 1);// Передаём OpenGL массив цветов:
glFogfv(GL_FOG_COLOR, fogColor);// Теперь, имея цвет дыма, установим его режим. Я выбрал GL_EXP2, но по умолчанию
// установлен GL_EXP. Ещё есть GL_LINEAR. Попробуйте все, чтобы наглядно понять их.
// Смысл в том, что они просчитываются по-разному. Мне кажется, что «экспотенциальный»
// дым выглядит лучше всего. Его формула: (f=e^(-density * Z), где Z — позиция камеры.
glFogi(GL_FOG_MODE, GL_EXP2);// Изменим плотность дыма. По умолчанию она равна единице, но мы начнем с 0.2f:
glFogf(GL_FOG_DENSITY, g_FogDensity);
// FOG_HINT — опция, устанавливающая, как именно будет отрисован дым.
// Нам всё равно, так мы и скажем %) GL_DONT_CARE даёт возможность OpenGL
// выбрать, рисовать вершинный и пикселный дым. На выбор есть 2 опции: GL_FASTEST и GL_NICEST
glHint(GL_FOG_HINT, GL_DONT_CARE);
// Это важная часть. Тут мы устанавливаем расстояние от нашей камеры, на котором будет
// начинатся дым. Пространство вне START и END будет окрашено цветом дыма. Я обычно ставлю
// дальнее значение таким же, как и дистанция взгляда. Минимальное по умолчанию 0,
// и мы не будем его изменять.
glFogf(GL_FOG_START, 0);
// значение END по умолчанию единица, увеличим его:
glFogf(GL_FOG_END, 10.0f);
// Наконец, инициализировав все необходимое, включим дым:
glEnable(GL_FOG);
// Следующие изменения нужно внести в функцию WinProc, в секцию WM_KEYDOWN:
case WM_KEYDOWN:
switch (wParam)
{
// Ниже мы дадим возможность пользователю увеличивать и уменьшать
// плотность дыма нажатием ‘+’ и ‘-‘. После увеличения плотности
// нужно отослать новую информацию OpenGL вызовом glFogf().
// В функцию передаётся флаг GL_FOG_DENSITY и новая плотность.
case VK_ESCAPE:
PostQuitMessage(0);
break;
case VK_ADD: // Если нажат плюс
g_FogDensity += 0.015f; // Увеличиваем плотность
glFogf(GL_FOG_DENSITY, g_FogDensity); // Передадим её OpenGL
if(g_FogDensity > 1) g_FogDensity = 1;
break;
case VK_SUBTRACT: // Если нажат минус
g_FogDensity -= 0.015f; // Уменьшим плотность
glFogf(GL_FOG_DENSITY, g_FogDensity); // Передадим её OpenGL
// Убедимся, что не менее 0:
if(g_FogDensity < 0) g_FogDensity = 0;
break;
case ‘F’: // Если нажата «F»
g_bFog = !g_bFog;// Установим переключатель в противоположное
if(g_bFog) // если включен дым
glEnable(GL_FOG);
else // иначе
glDisable(GL_FOG);
break;
}
break;
//////////////////////////////////////////
На этом всё. Пройдемся ещё раз по пунктам:
1) Нужно установить способ генерации дыма этой функцией: glFogi(GL_FOG_MODE, GL_EXP2);
2) Передаём OpenGL массив цвета дыма: glFogfv(GL_FOG_COLOR, fogColor);
3) Устанавливаем плотность дыма: glFogf(GL_FOG_DENSITY, g_FogDensity);
4) Способ создания дыма (GL_NICEST/GL_FASTEST/GL_DONT_CARE):
glHint(GL_FOG_HINT, GL_DONT_CARE);
5) Передаём OpenGL ближнюю и дальнюю дистанции отрисовки дыма:
glFogf(GL_FOG_START, 0);
glFogf(GL_FOG_END, 10.0f);
6) И, наконец, включаем дым: glEnable(GL_FOG);