Разработка приложения для визуализации трехмерных 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 (