Я сделал эту очень простую, отлично работающую реализацию Модель 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 не с правильной интенсивностью, но в основном это должно быть правильно).Но результат неправильный.
Вот два изображения.Слева, как он должен отображаться правильно, и вправо, как он рисует.
Если я уменьшу коэффициент блеска, в правом верхнем углу вы увидите небольшой зеркальный свет:
Хотя я понимаю концепцию освещения Phong, а также упрощенную, более производительную адаптацию blinn phong, которую я пробую несколько дней и просто не могу заставить ее работать.Любая помощь оценивается.
Редактировать:
Мне стало известно об ошибке этого ответа , что я искажаюсь |L+V|
вместо того, чтобы делить его, когдавычисляя H. Я перешел на деление следующим образом:
Vec3 H = Vec3.mul(Vec3.add(L.normalize(), V), 1/Vec3.add(L.normalize(), V).length());
К сожалению, это не сильно изменится.Результаты выглядят следующим образом:
, и если я увеличу зеркальную константу и уменьшу блеск, вы можете увидеть эффекты более отчетливо в неправильной улыбке:
Однако это деление только нормализация.
Я думаю, что мне не хватает одного шага.Потому что подобные формулы просто не имеют смысла для меня.
Если вы посмотрите на эту картинку: http://en.wikipedia.org/wiki/File:Blinn-Phong_vectors.svg
Проекция H на N намного меньше, чем V на R. И еслиВы представляете себе, что при изменении вектора V на изображении угол совпадает, когда вектор просмотра находится «с левой стороны».и становится все более и более разным при движении вправо.
Я бы в личном порядке умножил бы всю проекцию на два, чтобы она стала чем-то похожим (и дырка заключается в том, чтобы избежать вычисления R).Хотя я ничего не читал о том, что я собираюсь попробовать это ...
Результат: интенсивность зеркального света слишком велика (белые области), и позиция все еще неправильна.
Мне кажется, я что-то напутал, потому что размышления просто не в том месте.Но что?
Редактировать: Теперь я читаю в википедии в примечаниях, что угол N / H на самом деле составляет примерно половину или V / R.Чтобы компенсировать это, я должен умножить мой показатель блеска на 4, а не на мою проекцию.Если я это сделаю, у меня не будет видимого зеркального света.