Студопедия — OpenGL ES 2.0. Урок 5. Шейдер преломления света
Студопедия Главная Случайная страница Обратная связь

Разделы: Автомобили Астрономия Биология География Дом и сад Другие языки Другое Информатика История Культура Литература Логика Математика Медицина Металлургия Механика Образование Охрана труда Педагогика Политика Право Психология Религия Риторика Социология Спорт Строительство Технология Туризм Физика Философия Финансы Химия Черчение Экология Экономика Электроника

OpenGL ES 2.0. Урок 5. Шейдер преломления света






В предыдущем уроке мы рисовали гладкую поверхности в виде бегущей волны. В этом уроке мы попробуем превратить нашу поверхность в настоящую воду. Луч света проходящий, через границу двух сред, немного изменяет свое направление. Этот эффект называют преломлением света. Пусть на глубине y = ybottom расположено дно, покрытое текстурой. Над поверхностью воды находится глаз наблюдателя, т.е. камера. Нужно выяснить, какую точку текстуры дна увидит наблюдатель. Для этого изменим направление хода луча света на обратное. Луч света будет выходить из глаза наблюдателя, преломляться на поверхности воды и попадать на дно. Точка пересечения преломленного луча и дна и будет видна наблюдателю.

 

Разобьем задачу на три этапа:
1. Найти входящий вектор IN.
2. Найти преломленный вектор OUT.
3. Найти точку пересечения преломленного вектора с дном.

Приступаем к решению первого этапа. Входящий вектор найти нетрудно, если известны координаты вершины и координаты камеры. В фрагментном шейдере это будет выглядеть так:

vec3 IN=v_vertex - u_camera;

где u_camera - координаты камеры в виде униформы, а v_vertex - это вершина на поверхности воды, на которую положил глаз наблюдатель.

 

Вектор IN не обязательно должен быть нормализован. В предыдущих уроках при расчете освещения мы уже использовали вектор:

vec3 lookvector = normalize(u_camera - v_vertex)

Поэтому если мы хотим скомбинировать преломление с освещением можно в качестве вектора IN взять lookvector с противоположным знаком (т.е. IN = - lookvector), чтобы не создавать лишних вычислений в шейдере.


Приступаем к решению второго этапа.

Если нам известен входящий вектор IN, вектор единичной нормали N и относительный показатель преломления на границе двух сред k находим преломленный вектор OUT по закону Снелла:

Здесь:

 

 

Создадим в фрагментном шейдере функцию myrefract, которая будет принимать на вход аргументы IN, NORMAL, k и возвращать преломленный вектор:
vec3 myrefract(vec3 IN, vec3 NORMAL, float k){
// скалярное произведение нормали и вектора входящего луча
float nv=dot(NORMAL,IN);
// квадрат длины входящего вектора
float v2 = dot(IN,IN);
// коэффициент перед вектором нормали
float knormal=(sqrt(((k*k-1.0)*v2)/(nv*nv)+1.0)-1.0)* nv;
// вектор исходящего луча
vec3 OUT = IN + (knormal * NORMAL);
return OUT;
}

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

Найдем точку пересечения преломленного вектора с плоскостью дна. Зададим уравнение плоскости дна, оно выглядит очень просто:

у = ybottom, где ybottom - глубина дна

Как задать в пространстве уравнение прямой? Нужно знать какую-нибудь точку через которую проходит прямая и вектор, приложенный к этой точке. Преломленный вектор проходит через вершину v_vetrex. Хорошо, одну точку прямой мы знаем. Прицепим к ней вектор OUT, который мы уже нашли, и получим параметрическое уравнение прямой линии преломленного луча света:

x = v_vertex.x +OUT.x * t
y = v_vertex.y + OUT.y * t
z = v_vertex.z +OUT.z *t

где t - параметр, т.е. любое число. Все бесконечное множество чисел t дают нам бесконечное количество точек прямой. Кто хочет узнать больше про уравнение прямой линии в параметрическом виде могут обратиться к википедии. Нам нужно найти такой параметр t, который соответствует пересечению вектора OUT с плоскостью дна. Соединим вместе уравнение плоскости дна и уравнение прямой, т.е. подставим в уравнение прямой ybottom вместо у:

ybottom = v_vertex.y + OUT.y * t

Теперь мы знаем параметр t=(ybottom - v_vertex.y)/OUT.y

Подставляем найденный t в выражения для x и z получаем получаем координаты точки пересечения вектора OUT с дном:

xbottom = v_vertex.x +OUT.x * (ybottom - v_vertex.y)/OUT.y

zbottom = v_vertex.z +OUT.z * (ybottom - v_vertex.y)/OUT.y

Значение xbottom станет нашей текстурной координатой s, а zbottom - текстурной координатой t. Чтобы текстура не выглядела мелкой, уменьшим текстурные координаты в два раза. Получим двумерный вектор координат текстуры:

vec2 texCoord = vec2(0.5*xbottom,0.5*zbottom);

Пришло время оформить фрагментный шейдер. В нем я соединил эффект преломления с освещением:
precision mediump float;
uniform vec3 u_camera;
uniform vec3 u_lightPosition;
uniform sampler2D u_texture0;
varying vec3 v_vertex;
varying vec3 v_normal;


//функция преломления света, она должна быть объявлена до функции main
vec3 myrefract(vec3 IN, vec3 NORMAL, float k){
// скалярное произведение нормали и вектора входящего луча
float nv=dot(NORMAL,IN);
// квадрат длины входящего вектора
float v2 = dot(IN,IN);
//коэффициент перед вектором нормали
float knormal=(sqrt(((k*k-1.0)*v2)/(nv*nv)+1.0)-1.0)* nv;
// вектор исходящего луча
vec3 OUT = IN + (knormal * NORMAL);
return OUT;
}

void main() {
vec3 n_normal=normalize(v_normal);
vec3 lightvector = normalize(u_lightPosition - v_vertex);
vec3 lookvector = normalize(u_camera - v_vertex);
float ambient=0.1;
float k_diffuse=0.7;
float k_specular=0.3;
float diffuse = k_diffuse * max(dot(n_normal, lightvector), 0.0);
vec3 reflectvector = reflect(-lightvector, n_normal);
float specular = k_specular * pow(max(dot(lookvector,reflectvector),0.0), 40.0);
vec4 one=vec4(1.0,1.0,1.0,1.0);
//цвет освещения
vec4 lightColor=(ambient+diffuse+specular)*one;
//входящий вектор IN это (-lookvector)
//преломленный вектор OUT с показателем преломления 1.2
vec3 OUT=myrefract(-lookvector, n_normal, 1.2);
//глубина дна
float ybottom=-1.0;
//точка пересечения преломленного вектора и плоскости дна
float xbottom=v_vertex.x+OUT.x*(ybottom-v_vertex.y)/OUT.y;
float zbottom=v_vertex.z+OUT.z*(ybottom-v_vertex.y)/OUT.y;
//координаты текстуры
vec2 texCoord = vec2(0.5*xbottom,0.5*zbottom);
//цвет текстуры, извлеченный из текстуры по координатам
vec4 textureColor=texture2D(u_texture0, texCoord);
//цвет пикселя - комбинация цвета освещения и цвета текстуры
gl_FragColor=lightColor*textureColor;
}

Внесем в код предыдущего урока небольшие изменения. Заменим фрагментный шейдер, а также в методе onSurfaceCreated загрузим какую-нибудь текстуру, например такую:

 

//создадим текстурный объект
mTexture0=new Texture(context,R.drawable.picture);
//создадим шейдерный объект
mShader=new Shader(vertexShaderCode, fragmentShaderCode);
//свяжем буфер вершин с атрибутом a_vertex в вершинном шейдере
mShader.linkVertexBuffer(vertexBuffer);
//свяжем буфер нормалей с атрибутом a_normal в вершинном шейдере
mShader.linkNormalBuffer(normalBuffer);
//свяжем текстурный объект с шейдерным объектом
mShader.linkTexture(mTexture0, null);

Запусти приложение на исполнение и получим живую воду:

 







Дата добавления: 2015-10-19; просмотров: 900. Нарушение авторских прав; Мы поможем в написании вашей работы!



Композиция из абстрактных геометрических фигур Данная композиция состоит из линий, штриховки, абстрактных геометрических форм...

Важнейшие способы обработки и анализа рядов динамики Не во всех случаях эмпирические данные рядов динамики позволяют определить тенденцию изменения явления во времени...

ТЕОРЕТИЧЕСКАЯ МЕХАНИКА Статика является частью теоретической механики, изучающей условия, при ко­торых тело находится под действием заданной системы сил...

Теория усилителей. Схема Основная масса современных аналоговых и аналого-цифровых электронных устройств выполняется на специализированных микросхемах...

Классификация ИС по признаку структурированности задач Так как основное назначение ИС – автоматизировать информационные процессы для решения определенных задач, то одна из основных классификаций – это классификация ИС по степени структурированности задач...

Внешняя политика России 1894- 1917 гг. Внешнюю политику Николая II и первый период его царствования определяли, по меньшей мере три важных фактора...

Оценка качества Анализ документации. Имеющийся рецепт, паспорт письменного контроля и номер лекарственной формы соответствуют друг другу. Ингредиенты совместимы, расчеты сделаны верно, паспорт письменного контроля выписан верно. Правильность упаковки и оформления....

КОНСТРУКЦИЯ КОЛЕСНОЙ ПАРЫ ВАГОНА Тип колёсной пары определяется типом оси и диаметром колес. Согласно ГОСТ 4835-2006* устанавливаются типы колесных пар для грузовых вагонов с осями РУ1Ш и РВ2Ш и колесами диаметром по кругу катания 957 мм. Номинальный диаметр колеса – 950 мм...

Философские школы эпохи эллинизма (неоплатонизм, эпикуреизм, стоицизм, скептицизм). Эпоха эллинизма со времени походов Александра Македонского, в результате которых была образована гигантская империя от Индии на востоке до Греции и Македонии на западе...

Демографияда "Демографиялық жарылыс" дегеніміз не? Демография (грекше демос — халық) — халықтың құрылымын...

Studopedia.info - Студопедия - 2014-2024 год . (0.008 сек.) русская версия | украинская версия