Разработка приложения для визуализации трехмерных iен с использованием карт освещения и динамического освещения
Дипломная работа - Компьютеры, программирование
Другие дипломы по предмету Компьютеры, программирование
кстурных координатconst mat4 bias (
.5f, 0.0f, 0.0f, 0.5f,
.0f, 0.5f, 0.0f, 0.5f,
.0f, 0.0f, 0.5f, 0.5f,
0.0f, 0.0f, 0.0f, 1.0f
);
// расчитаем необходимые матрицы
mat4 view = GLFromEuler (camera.rotation) * GLTranslation (-camera.position);viewProjection = bias * camera.projection * view;
// передадим матрицу источника освещения в шейдерную программу
glUniformMatrix4fv (glGetUniformLocation(program, transform.light), 1, GL_TRUE, viewProjection.m);
}
Комментарий по поводу матрицы bias. Сначала мы получаем видовую матрицу источника освещения view, она переводит координаты вершины из мирового пространства координат в пространство координат источника освещения. Затем, используя проекционную матрицу, мы переводим координаты в однородные. Однако, известно что однородные координаты лежат в диапазоне [-1, 1], а нам необходимо получить текстурные координаты, которые лежат в диапазоне [0, 1], именно для этого используется матрица bias. Трансформация этой матрицы равносильна операции a * 0.5 + 0.5 для каждого элемента трансформируемого вектора.
В результате, используя матрицу источника освещения, мы можем перевести координаты вершины из мирового пространства в текстурные координаты карты глубины в вершинном шейдере:
layout (location = VERT_POSITION) in vec3 position;(location = VERT_TEXCOORD) in vec2 texcoord;(location = VERT_NORMAL) in vec3 normal;
// параметры преобразованийstruct Transform
{model;viewProjection;light;normal;viewPosition;
} transform;
// параметры точеченого источника освещения
uniform struct Light
{ambient;diffuse;specular;4 position;
} light;
// параметры для фрагментного шейдера
out Vertex
{texcoord;smcoord;normal;lightDir;viewDir;
} Vert;
void main(void)
{
// переведем координаты вершины в мировую систему координат
vec4 vertex = transform.model * vec4 (position, 1.0);
// передадим в фрагментный шейдер некоторые параметры
// вычисляем текстурные координаты вершины на карте глубины
Vert.smcoord = transform.light * vertex;
// передаем текстурные координаты.texcoord = texcoord;
// передаем нормаль в мировой системе координат
Vert.normal = transform.normal * normal;
// передаем направление на источник освещения
Vert.lightDir = vec3 (light.position);
// передаем направление от вершины к наблюдателю в мировой системе координат
Vert.viewDir = transform.viewPosition - vec3 (vertex);
// переводим координаты вершины в однородные_Position = transform.viewProjection * vertex;
}
Используя полученные координаты и теневую карту мы можем найти глубину фрагмента относительно камеры источника освещения. Обладая информацией о глубине фрагмента относительно камеры источника освещения и относительно камеры наблюдателя мы можем сравнить эти два значения и узнать, находится ли этот фрагмент в тени другого в пространстве источника освещения.3.30 обладает двумя возможностями, которые облегчают нам получение требуемой информации о фрагментах:
Самплер sampler2DShadow
Функция textureProj
Использование специального текстурного самплера sampler2DShadow позволяет изменить логику работы некоторых функций для работы с текстурой, а использование функции textureProj позволяет получить значение текселя текстуры с коррекцией текстурных координат. При передаче в функцию textureProj в качестве текстурных координат 3х компонентного вектора для получения текселя она использует первые два компонента деленные на третий. Это позволит нам получить корректное значение карты глубины с учетом глубины фрагмента относительно камеры источника освещения.
При создании текстуры для хранения значений глубины мы использовали специальный параметр:
glTexParameteri (GL_TEXTURE_2D,_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
Использование этого параметра позволяет производить автоматический тест на затенение (shadow test), это происходит когда мы вызываем функцию textureProj. В случае если глубина фрагмента с координатами smccord больше чем в текстуре глубины depthTexture функция textureProj вернет 1.0, иначе она вернет 0.0. Итоговый фрагментый шейдер:
// текстурный самплер карты глубиныsampler2DShadow depthTexture;
// параметры точеченого источника освещенияstruct Light
{ambient;diffuse;specular;position;
} light;
// параметры материалаstruct Material
{D texture;ambient;diffuse;specular;emission;shininess;
} material;
// параметры полученные из вершинного шейдера
in Vertex
{texcoord;smcoord;normal;lightDir;viewDir;
} Vert;
(location = FRAG_OUTPUT0) out vec4 color;
void main(void)
{
// нормализуем полученные данные для коррекции интерполяции
vec3 normal = normalize (Vert.normal);lightDir = normalize (Vert.lightDir);viewDir = normalize (Vert.viewDir);
// коэффициент затененияshadow = textureProj (depthTexture, Vert.smcoord);
// добавим собственное свечение материала= material.emission;
// добавим фоновое освещение+= material.ambient * light.ambient;
// добавим рассеянный светNdotL = max (dot(normal, lightDir), 0.0);
color += material.diffuse * light.diffuse * NdotL;
// добавим отраженный светRdotVpow = max (pow(dot (reflect(-lightDir, normal), viewDir), material.shininess), 0.0);+= material.specular * light.specular * RdotVpow;
// вычислим итоговый цвет пикселя на экране с учетом текстуры
color *= texture (material.texture, Vert.texcoord) * shadow;
}
Для сглаживания краев тени в используется техника Percentage Closer Filtering (PCF). Данная техника заключается в том, что производится несколько тестов на затенение в окрестностях искомого фрагмента и для затенения используется среднее значение этих тестов, таким образом, граница тени будет более мягкой.
Относительно описанного выше фрагментного шейдера эту технику можно использовать так:
// сглаживание границы тени, используем PCF с выборкой 3x3
float PCF (in vec4 smcoord)
{res = 0.0;+= textureProjOffset (depthTexture, smcoord, ivec2 (-1, - 1));+= textureProjOffset (depthTexture, smcoord, ivec2 (0, - 1));+= textureProjOffset (depthTexture, smcoord, ivec2 (1, - 1));+= textureProjOffset (depthTexture, smcoord, ivec2 (-1, 0));+= textureProjOffset (depthTexture, smcoord, ivec2 (0, 0));+= textureProjOffset (depthTexture, smcoord, ivec2 (1, 0));+= textureProjOffset (depthTexture, smcoord, ivec2 (-1, 1));+= textureProjOffset (depthTexture, smcoord, ivec2 (0, 1));+= textureProjOffset (