Назад | Содержание | Вперед

Обратная трассировка лучей

Отображение шероховатости (bump-mapping)

Данная техника позволяет без геометрического изменения поверхности и, как следствие, не сильно замедляя трассировку, получить эффект шероховатости. У материала появляется еще одна карта – карта высоты (bump map). В зависимости от яркости точки, условно "поднимаются" точки на поверхности. Особенность заключается в том, что сама поверхность не изменяется, а меняется только нормаль в точке. К нормали прибавляются небольшие вектора: чем больше разность высот между точками, тем больше нужен прибавляемый вектор. Из-за этого, с помощью такой техники невозможно получить тени от возвышенностей, но для имитации мелких деталей она подходит идеально.

Рассмотрим задачи, которые нужно решить для получения эффекта.

Во-первых, необходимо найти единичные вектора, которые мы будем прибавлять к нормали. Напомню, что основным примитивом в демонстрационной программе является треугольник. Следовательно, у нас есть пространственные (x, y, z) и текстурные (u, v, w) координаты вершин треугольника. Из текстурных координат здесь используются только u и v (да и сам бамп-меппинг в программе пока реализован только для растровых карт). Из несложных построений и последовательности преобразований можно получить следующий алгоритм для этого:

void Triangle::Prepare()
{
    ...
    // ptw0, ptw1, ptw2 - пространсвенные координаты вершин
    // texture0, texture1, texture2 - текстурные координаты
    // bump_du, bump_dv - векторы смещения для нормали
    VectorSubtraction(&vw1, ptw1, ptw0);
    VectorSubtraction(&vw2, ptw2, ptw0);

    REAL du1 = texture1.x - texture0.x;
    REAL du2 = texture2.x - texture0.x;
    REAL dv1 = texture1.y - texture0.y;
    REAL dv2 = texture2.y - texture0.y;
    REAL d = du2*dv1 - du1*dv2;

    bump_dv.x = du2*vw1.x - du1*vw2.x;
    bump_dv.y = du2*vw1.y - du1*vw2.y;
    bump_dv.z = du2*vw1.z - du1*vw2.z;

    bump_du.x = dv2*vw1.x - dv1*vw2.x;
    bump_du.y = dv2*vw1.y - dv1*vw2.y;
    bump_du.z = dv2*vw1.z - dv1*vw2.z;
    
    if (d > EPS)
    {
        bump_dv.Normalize();
        bump_du.Normalize();
        bump_dv.Invert();
    }
    else if (d < - EPS)
    {
        bump_dv.Normalize();
        bump_du.Normalize();
        bump_du.Invert();
    }
    else
    {
        bump_dv = Vector(0.0f, 0.0f, 0.0f);
        bump_du = Vector(0.0f, 0.0f, 0.0f);
    }
}

Во-вторых, необходимо найти яркости точек, вычислить разности, произвести сглаживание полученных величин. Если с поиском яркости точек и нахождением разности проблем возникнуть не должно, то со сглаживанием придется повозится.

Простейший способ найти величину смещения вектора – взять разность яркости точки над и под искомой точкой. Но у такого решения будет большой минус – будут видны переходы между пикселями в растре. Чтобы от этого избавиться можно добавить билинейное сглаживание (билинейная фильтрация, bilinear filtering).

Билинейная фильтрация – просто напросто линейная интерполяция четырех пикселей в растровом изображении. Пара вещественных координат (x, y) определяет четыре точки на растре, а два вещественных остатка определяют весовые коэффициенты для них.

Дальше только дело техники. Если в треугольнике, с которым найдено пересечение, используется бамп-карта, в растре высчитывается разность яркости пар точек с текстурными координатами (u + 1, v), (u - 1, v) и (u, v - 1), (u, b + 1) (вместо единицы можно попробовать использовать другие числа, например 0,5 или 0,25). Затем, к найденной нормали в точке прибавляются соответственные вектора bump_du, bump_dv, умноженные на найденные разности. Все.

Назад | Содержание | Вперед


©Павел Коколемин

Рейтинг@Mail.ru