d
Эффект затенения
«Честные» динамические тени в аркадных 3D-играх не всегда бывают уместны. Как правило, разработчики ограничиваются статическими предрассчитанными тенями от неподвижных объектов и простым темным кружочком на земле под персонажем – дешево и сердито =) Я решил дополнить этот нехитрый метод одной простой, но важной деталью: изменение яркости персонажа в зависимости от его местоположения – в тени или на свету.
Цвет для яркости будет считываться из карты освещения, в которой «запечены» все статические тени на карте.
Допустим, у вас есть некий блок кода, в котором вы находите точку на поверхности полигона под ногами персонажа:
// Проверяем факт пересечения
IntrStatus istatus = character.downRay.intersectTriangle(tri);
if (istatus.hit)
{
// Извлекаем точку пересечения
Vector3f ipt = istatus.intersectionPoint;
if (ipt.y > currentFloorHeight)
{
currentFloorHeight = ipt.y;
// Берем материал полигона
Material mat = materialByIndex[tri.matIndex];
// Если нет карты освещения (текстура 1), то ничего не делаем
if (mat.textures[1])
{
// Берем изображение карты освещения
Image lightmap = imageByIndex[mat.textures[1].imgIndex];
// Находим текстурные координаты точки пересечения
Vector2f tc = triObjSpaceToTexSpace(tri.vertices, tri.texCoords2, ipt);
// Конвертируем текстурные координаты в дискретные
uint imgX = cast(uint)(tc.x * lightmap.width - 0.5f);
uint imgY = cast(uint)(tc.y * lightmap.height - 0.5f);
// Считываем цвет пикселя c карты освещения
Color lumel = lightmap[imgX, imgY];
// Применяем полученный цвет к материалу персонажа
chMaterial.ambientColor = lumel;
chMaterial.diffuseColor = lumel;
chMaterial.specularColor = lumel;
}
}
}
Осталось определить функцию triObjSpaceToTexSpace. Она будет использовать барицентрические координаты:
Vector2f triObjSpaceToTexSpace(
Vector3f[3] vertices,
Vector2f[3] texCoords,
Vector3f point)
{
Vector3f v0 = vertices[2] - vertices[0];
Vector3f v1 = vertices[1] - vertices[0];
Vector3f v2 = point - vertices[0];
float dot00 = dot(v0, v0);
float dot01 = dot(v0, v1);
float dot02 = dot(v0, v2);
float dot11 = dot(v1, v1);
float dot12 = dot(v1, v2);
float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01);
float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
float v = (dot00 * dot12 - dot01 * dot02) * invDenom;
Vector2f t2 = texCoords[1] - texCoords[0];
Vector2f t1 = texCoords[2] - texCoords[0];
return texCoords[0] + t1 * u + t2 * v;
}
Atrium собирается последней версией LDC
Решив проверить LDC на практике, я только что собрал им Atrium. Результат очень обрадовал, при компиляции в релизном режиме и с уровнем оптимизаций -O3, LDC выдал весьма шустрый код: ~100 FPS против ~80 у DMD 2.060! При этом я всего один раз столкнулся с необходимостью поправить исходники – при использовании ассоциативного массива указателей.
Как вывод: LDC вполне созрел для использовании в качестве основного компилятора D под Linux – во всяком случае, для работы с OpenGL и графикой реального времени. К сожалению, я не в курсе, как у него обстоят дела c поддержкой Windows – надеюсь, со временем этот вопрос устаканится.
Журнал “FPS” №21
> Blender: обзор дополнений (выпуск 3)
> Tears of Steel: роботы тоже плачут…
> Эффект “старинного фото” в GIMP
> Журнал GIMP Magazine
> Язык D: новости
> Семь мифов о D
> Сборщик мусора – враг или друг?
> Юникод в OpenGL. Раз и навсегда
> Почему я выбираю Linux?
> Патентные войны
Номер доступен для онлайн-чтения и загрузки на сервисе Issuu.com и Документах Google. Последние новости по проекту вы можете узнать в публичной странице журнала в социальной сети Google+.
Передискретизация в dlib.image
Linear
Самый простой и, следовательно, самый быстрый способ изменить размеры изображения. Известен также как интерполяция методом ближайшего соседа (Nearest Neighbor). Для промежуточных пикселей выбирается ближайшее известное значение.
Bilinear
Для получения промежуточного значения производится линейная интерполяция между четырьмя ближайшими пикселями. Это позволяет несколько сгладить переходы. Билинейный фильтр – неплохой компромисс между скоростью и качеством результата.
Bicubic
Промежуточные значения вычисляются путем свертки ядра 4×4 специальной бикубической функцией. Достаточно медленный алгоритм, но зато дает наименее пикселизированный результат.
Lanczos
У бикубической интерполяции есть недостаток – изображение получается несколько размытым. Чтобы сохранить четкость, можно воспользоваться фильтром Ланцоша. Он немного увеличивает пикселизацию, но создает контрастные области вдоль контуров для повышения четкости. В моей реализации я использовал ядро 7х7. Очень медленно, зато качественно.
Существуют и другие алгоритмы – постепенно они тоже будут добавлены в библиотеку.
Изменения доступны в dlib ревизии r5 и выше.