Хотя OpenGL поддерживает задание тумана, но используемая для этого модель предполагает, что все
пространство равномерно заполнено туманом с заданной неизменяемой плотностью.
Поэтому реализовать другие варианты объемного тумана (например слой тумана заданной толщины над
поверхностью Земли) этим способом невозможно.
Для этого удобно воспользоваться расширением GL_EXT_fog_coord, поддерживаемом большинством современных
графических ускорителей. Данное расширение позволяет пользователю самому задать степень затуманивания
для каждой вершины (т.е. фактически степень затумания фактически выступает в качестве еще одного
атрибута вершины наравне с цветов, нормалью, текстурными координатами).
При таком подходе степень "затуманивания" каждого пиксела грани получается путем билинейной
интерполяции заданных в вершинах грани значений.
Данное расширение вводит две новых функции (glFogCoord и glFogCoordPointerEXT) и ряд констант.
Интерфейс первой из вводимых функций задается следующим образом:
void glFogCoordf ( float fogFactor );
Для непосредственного использования данного расширения необходимо настроить использование
объемного тумана следующим образом:
glEnable ( GL_FOG );
glFogi ( GL_FOG_MODE, GL_LINEAR );
glFogfv ( GL_FOG_COLOR, fogColor );
glFogf ( GL_FOG_START, s );
glFogf ( GL_FOG_END, e );
glFogi ( GL_FOG_HINT, GL_NICEST );
glFogi ( GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT );
Данный фрагмент когда устанавливает, что в качесвте величины затуманивания будут использованы
явно заданные значения для каждой вершины.
Также задается даипазон изменения затуманивания (s,e)
(если значение оказывается меньше стартовой величины s, то затуамнивания вообще не происходит,
в случае, когда степень затуманивания оказывается больше, чем е, то происходит полное затуманивание
(т.е. объект рисуется цветовм тумана).
В качестве спсоба вычисления точной степени затуманивания выбран линейный закон
t = (f-s)/(e-s)
Значения затуманивая можно либо явно задавать в каждой вершине при помощи функции glFogCoordf или
же можно воспользоваться для этого вершинными массивами:
glEnableClientState ( GL_FOG_COORDINATE_ARRAY );
glFogCoordPointerEXT ( GL_FLOAT, 0, fogValues );
....
glDisableClientState ( GL_FOG_COORDINATE_ARRAY );
Рассотрим теперь каким образом можно явно вычислить степень затуманивания для заданной вершины.
Рассмотрим случай, когда у нас имеется слой тумана постоянной плотности, расположенный в диапазоне
y0 <= y <= y1
В этом случае степень затуманивания точки Р фактически равна длине части отрезка, соединяющего
положение камеры с этой точкой, лежащей внутри полосы тумана, умноженной на плотность тумана (см рис.).
Рис. 1. Точное вычисление пути внутри слоя тумана.
Подобные вычисления, особенно в слчае, когда число вершин довольно велико, могут сильно нагрузиь процессор,
поэтмоу во многих случаях можно использовать упрощенную модель (дающую вполне приемлимые результаты в
большинстве случаев) - берется длина проекции отрезка на прямую, перпендикулярную плоскости тумана.
В нашем случае в качестве такой плоскости выступает ось Оу.
Рис. 2. Приближенное вычисление по сравнению с точным.
Для вычисления этого достаточно (в случае, когда камеры расположена выше полосы тумана), просто взять
разницу у-координаты самой точки Р и y1, умножив ее на плотность тумана.
В случае использования закона GL_LINEAR, вместо вычитания и задания плотности тумана можно просто задать
соответствующим образом величины s и e. В этом случае в качестве величины s будет выступать y1, а
величина е будет равна плотности тумана плюс y1.
Однако следует иметь в виду, что если задаваемый объект подвергавется преобразованиям (при помощи
матрицы model-view), то в качестве степени затуманивания должна выступать у-координата преобразованной
вершины, а не исходной.
Все что, для этого следует сделать - это получиь текущую model-view матрицу при помощи glGet и для
каждой вершины найти ее у-координату посмле преобразования этой матрицей.
Рис3. Тор в слое тумана.
Именно этот подход и реализован в следующем примере, исходный код которого можно скачать
здесь.