Проблема реализации модели затенения Блинна – Фонга - PullRequest
3 голосов
/ 07 января 2011

Я сделал эту очень простую, отлично работающую реализацию Модель Phong Relflection (Пока не реализована атмосфера, но это меня сейчас не беспокоит).Функции должны быть самоочевидными.

/**
 * Implements the classic Phong illumination Model using a reflected light
 * vector.
 */
public class PhongIllumination implements IlluminationModel {

    @RGBParam(r = 0, g = 0, b = 0)
    public Vec3 ambient;

    @RGBParam(r = 1, g = 1, b = 1)
    public Vec3 diffuse;

    @RGBParam(r = 1, g = 1, b = 1)
    public Vec3 specular;

    @FloatParam(value = 20, min = 1, max = 200.0f)
    public float shininess;

    /*
     * Calculate the intensity of light reflected to the viewer .
     * 
     * @param P = The surface position expressed in world coordinates.
     * 
     * @param V = Normalized viewing vector from surface to eye in world
     * coordinates.
     * 
     * @param N = Normalized normal vector at surface point in world
     * coordinates.
     * 
     * @param surfaceColor = surfaceColor Color of the surface at the current
     * position.
     * 
     * @param lights = The active light sources in the scene.
     * 
     * @return Reflected light intensity I.
     */
    public Vec3 shade(Vec3 P, Vec3 V, Vec3 N, Vec3 surfaceColor, Light lights[]) {
        Vec3 surfaceColordiffused = Vec3.mul(surfaceColor, diffuse);
        Vec3 totalintensity = new Vec3(0, 0, 0);
        for (int i = 0; i < lights.length; i++) {
            Vec3 L = lights[i].calcDirection(P);
            N = N.normalize();
            V = V.normalize();
            Vec3 R = Vec3.reflect(L, N); // reflection vector
            float diffuseLight = Vec3.dot(N, L);
            float specularLight = Vec3.dot(V, R);
            if (diffuseLight > 0) {
                totalintensity = Vec3.add(Vec3.mul(Vec3.mul(
                        surfaceColordiffused, lights[i].calcIntensity(P)),
                        diffuseLight), totalintensity);
                if (specularLight > 0) {

                    Vec3 Il = lights[i].calcIntensity(P);

                    Vec3 Ilincident = Vec3.mul(Il, Math.max(0.0f, Vec3
                            .dot(N, L)));

                    Vec3 intensity = Vec3.mul(Vec3.mul(specular, Ilincident),
                            (float) Math.pow(specularLight, shininess));

                    totalintensity = Vec3.add(totalintensity, intensity);
                }

            }
        }
        return totalintensity;
    }
}

Теперь мне нужно адаптировать ее, чтобы она стала моделью освещения Блинна-Фонга

Я использовал формулы от слушателя и пекаря, следовал псевдокодам и пытался реализовать его несколько раз в соответствии со статьями википедии на нескольких языках, но он никогда не работал.Я просто не получаю зеркальных отражений, или они настолько слабые и / или находятся в неправильном месте и / или имеют неправильный цвет.

Из многочисленных неправильных реализаций я выкладываю небольшой код, который уже кажется неправильным.Таким образом, я вычисляю свой вектор Half Way и мой новый зеркальный свет следующим образом:

Vec3 H = Vec3.mul(Vec3.add(L.normalize(), V), Vec3.add(L.normalize(), V).length());
float specularLight = Vec3.dot(H, N);

С этими небольшими изменениями он уже должен работать (maby не с правильной интенсивностью, но в основном это должно быть правильно).Но результат неправильный.

Вот два изображения.Слева, как он должен отображаться правильно, и вправо, как он рисует.

right wrong

Если я уменьшу коэффициент блеска, в правом верхнем углу вы увидите небольшой зеркальный свет: lower shininess

Хотя я понимаю концепцию освещения Phong, а также упрощенную, более производительную адаптацию blinn phong, которую я пробую несколько дней и просто не могу заставить ее работать.Любая помощь оценивается.

Редактировать:

Мне стало известно об ошибке этого ответа , что я искажаюсь |L+V| вместо того, чтобы делить его, когдавычисляя H. Я перешел на деление следующим образом:

Vec3 H = Vec3.mul(Vec3.add(L.normalize(), V), 1/Vec3.add(L.normalize(), V).length());

К сожалению, это не сильно изменится.Результаты выглядят следующим образом:

div

, и если я увеличу зеркальную константу и уменьшу блеск, вы можете увидеть эффекты более отчетливо в неправильной улыбке:

div2

Однако это деление только нормализация.

Я думаю, что мне не хватает одного шага.Потому что подобные формулы просто не имеют смысла для меня.

Если вы посмотрите на эту картинку: http://en.wikipedia.org/wiki/File:Blinn-Phong_vectors.svg

Проекция H на N намного меньше, чем V на R. И еслиВы представляете себе, что при изменении вектора V на изображении угол совпадает, когда вектор просмотра находится «с левой стороны».и становится все более и более разным при движении вправо.

Я бы в личном порядке умножил бы всю проекцию на два, чтобы она стала чем-то похожим (и дырка заключается в том, чтобы избежать вычисления R).Хотя я ничего не читал о том, что я собираюсь попробовать это ...

Результат: интенсивность зеркального света слишком велика (белые области), и позиция все еще неправильна.

Мне кажется, я что-то напутал, потому что размышления просто не в том месте.Но что?

Редактировать: Теперь я читаю в википедии в примечаниях, что угол N / H на самом деле составляет примерно половину или V / R.Чтобы компенсировать это, я должен умножить мой показатель блеска на 4, а не на мою проекцию.Если я это сделаю, у меня не будет видимого зеркального света.

Ответы [ 2 ]

5 голосов
/ 08 января 2011

Разобрался!

Мне пришлось отменить вектор просмотра.

3 голосов
/ 08 января 2011

При расчете H вы, похоже, умножаете L+V на его норму, например: H = (L+V)*|L+V| (при условии Vec3.mul(v,x) умножает v на x). Вместо этого вы должны разделить на норму, H = (L+V)/|L+V|.

...