Затенение по Фонгу — модель расчёта освещения трёхмерных объектов, в том числе полигональных моделей и примитивов, а также метод интерполяции освещения по всему объекту.

Гладкое затенение править

Модели обычно задаются набором плоских выпуклых граней, хотя большинство реальных трёхмерных предметов имеют гладкие криволинейные поверхности. Таким образом, криволинейная поверхность рисуется как ребристая полигональная сетка; для того, чтобы эта сетка выглядела гладкой, используется тот или иной метод интерполяции освещённости вершин полигональной сетки.

Если используется затенение по Гуро, то расчёт цвета производится в каждой вершине каждой грани, а затем рассчитанный цвет интерполируется по всей грани. В результате блики, которые должны проявиться в середине полигона, нарисованы не будут — при интерполяции цветов вершин более яркое освещение центра многоугольника невозможно.

При затенении по Фонгу интерполируется вектор нормали[1]. Для нахождения вектора нормали в произвольной точке поверхности используют нормированную взвешенную сумму векторов нормали граней, которым эта точка принадлежит:

 

Вычислительные затраты на затенение по Гуро или по Фонгу зависят соответственно от числа вершин и от числа фрагментов изображения. Современное графическое оборудование использует второй способ, вычисляя цвет каждого фрагмента (т.е. пикселя), а не каждой вершины.

Модель освещения править

Освещение по Фонгу включает в себя также и модель освещения Фонга, т.е. алгоритм расчёта освещения в заданной точке. Это локальная модель освещения, т.е. она учитывает только свойства заданной точки и источников освещения, игнорируя эффекты рассеивания, линзирования, отражения от соседних тел.

Затенение по Фонгу требует сравнительно мало ресурсов, но большинство оптических явлений игнорируются либо рассчитываются с грубым приближением.

Другие модели освещения могут лучше учитывать свойства материала (локальные модели Орена-Наяра, Кука-Торренса, анизотропные модели) или сложные оптические явления (глобальные модели), но ведут к росту накладных расходов.

Способ расчёта освещения править

Расчёт освещения по Фонгу требует вычисления цветовой интенсивности трёх компонент освещения: фоновой (ambient), рассеянной (diffuse) и глянцевых бликов (specular). Фоновая компонента — грубое приближение лучей света, рассеянных соседними объектами и затем достигших заданной точки; остальные две компоненты имитируют рассеивание и отражение прямого излучения.

 
Иллюстрация различных компонент, соединённых в модели Фонга

 

где

  — вектор нормали к поверхности в точке

  — падающий луч (направление на источник света)

  — отраженный луч (направление идеально отраженного от поверхности луча)

 

  — коэффициент фонового освещения

  — коэффициент бликового освещения

  — коэффициент диффузного освещения


Освещение в OpenGL править

В конвейере OpenGL цветовая интенсивность фрагмента рассчитывается для каждого источника света в отдельности, затем результаты складываются и добавляется свет, излучаемый телом (GL_EMISSION).

Алгоритм расчёта освещения по Фонгу можно проиллюстрировать с помощью следующих шейдеров:

Вершинный шейдер править

varying vec3 n;
varying vec3 v;

void main(void)
{
    v = vec3(gl_ModelViewMatrix * gl_Vertex);
    n = normalize(gl_NormalMatrix * gl_Normal);
    gl_Position = ftransform();
}

Фрагментный шейдер править

varying vec3 n;
varying vec3 v;

void main(void)
{
    vec4 result = vec4(0.0);
    for (int li = 0; li < gl_MaxLights; ++li)
    {
        vec3 viewPos = gl_LightSource[li].position.w * v;
        vec3 l = normalize(gl_LightSource[li].position.xyz - viewPos);
        vec3 e = normalize(-v);
        vec3 r = normalize(-reflect(l, n));

        vec4 Iamb = gl_FrontLightProduct[li].ambient;

        vec4 Idiff = gl_FrontLightProduct[li].diffuse * max(dot(n, l), 0.0);
        Idiff = clamp(Idiff, 0.0, 1.0);

        vec4 Ispec = gl_FrontLightProduct[li].specular
                     * pow(max(dot(r, e), 0.0),
                           gl_FrontMaterial.shininess);
        Ispec = clamp(Ispec, 0.0, 1.0);

        result += Iamb + Idiff + Ispec;
    }

    gl_FragColor = gl_FrontLightModelProduct.sceneColor + result;
}

Где величина

gl_FrontLightModelProduct.sceneColor

эквивалентна выражению

gl_FrontMaterial.emission + gl_FrontMaterial.ambient * gl_LightModel.ambient

Примечания править

  1. Д. Роджерс. Алгоритмические основы машинной графики = Procedural Elements for Computer Graphics. — М.: Мир, 1989. — С. 394. — 512 с. — ISBN 0-07-053534-5.

Ссылки править