
- •OpenGl es для новичков
- •2.5 OpenGl es 2.0. Урок 5 Шейдер преломления света……………………………………… 60
- •1.1 OpenGl es в Android, класс glSurfaceView
- •1.2 OpenGl es 1. Основы рисования для начинающих
- •Aтрибут координат вершины.
- •Цвет как атрибут вершины.
- •Координаты вектора нормали.
- •1.3 OpenGl es 1. Применение индексов при обходе вершин
- •1.4 OpenGl es 1. Освещение и материалы
- •1.5 OpenGl es 1. Двумерные текстуры
- •1.6 OpenGl es 1. Текстурирование на примере
- •1.7 OpenGl es 1. Как сделать текстуры прозрачными
- •1.8 OpenGl es 1. Как наложить несколько текстур на один полигон
- •1.9 OpenGl es 1. Текстуры в движении
- •1.10 OpenGl es 1. Зеркальное отражение при помощи кубических текстур
- •2.1 OpenGl es 2.0. Урок первый-Шейдеры Введение в шейдеры.
- •Получение матриц.
- •Создание шейдерного объекта в OpenGl es 2.0
- •Передача данных униформ в шейдеры.
- •Передача атрибутов вершин в вершинный шейдер.
- •Класс шейдерного объекта.
- •2.2 OpenGl es 2.0. Урок второй - Освещение в шейдере
- •Фоновое (ambient) освещение.
- •Диффузное (diffuse) или рассеянное освещение.
- •Зеркальное (specular) или бликовое освещение.
- •Коды шейдеров.
- •Практика. Освещение плоской поверхности.
- •2.3 OpenGl es 2.0. Урок третий - Двумерные текстуры Загрузка текстуры из файла.
- •Доступ к текстурам из шейдера.
- •Получение цвета пикселя из текстуры.
- •Практика. Текстурированный квадрат.
- •Включаем свет.
- •2.4 OpenGl es 2.0. Урок 4. Гладкие поверхности. Полигональная сетка.
- •Расчет нормалей.
- •Разбиваем сетку на треугольники и рисуем поверхность.
- •Полный код класса рендерера, рисующего поверхность.
- •2.5 OpenGl es 2.0. Урок 5. Шейдер преломления света
Получение матриц.
Чтобы передать матрицу модели-вида-проекции u_modelViewProjectionMatrix в вершинный шейдер нужно ее получить. Матрица модели.
Матрица модели описывает собственное движение вершин, из которых состоит модель, в трехмерном пространстве. Простейший случай модели - это одна вершина. Рассмотрим для примера поворот. Например, нам нужно повернуть вершину с координатами x,y,z вершину на угол angle против часовой стрелки относительно вектора с координатами rotateVectorX, rotateVectorY, rotateVectorZ, проходящего через начало координат. Для определения матрицы поворота существует команда Matrix.setRotateM. Получим матрицу поворота modelMatrix.
Определим пустой массив для матрицы модели:
float[] modelMatrix = new float[16];
Применим команду:
Matrix.setRotateM(modelMatrix, 0, angle, rotateVectorX, rotateVectorY, rotateVectorZ);
Получим заполненный массив modelMatrix, соответствующий нашему повороту.
Как получить новые координаты вершины после поворота? Достаточно умножить матрицу модели на вектор координат вершин:
//запишем текущие координаты вершин в четырехкомпонентный вектор float vertex[]={x,y,z,1}; //создадим пустой массив, в который будут записаны новые координаты
float new_vertex=new float[4]; //умножим матрицу модели на вектор координат Matrix.multiplyMV(new_vertex, 0, modelMatrix, 0, vertex, 0); //получили новые координаты после поворота float new_x=new_vertex[0]; float new_y=new_vertex[1]; float new_z=new_vertex[2];
Команда Matrix.multiplyMV умножает матрицу модели modelMatrix на вектор координат вершины vertex и записывает результат в массив new_vertex. Если модель состоит из множества жестко связанных вершин, совершающих одинаковую трансформацию, нужно умножить матрицу модели на координаты каждой вершины. Если вершин несколько тысяч - это может быть затратно по времени, если трансформации вершин производить на CPU. Поэтому, в этом случае удобнее передать матрицу модели в вершинный шейдер как униформу и преобразования координат вершин выполнять в вершинном шейдере. Если вершин немного, можно оставить расчет модельных трансформаций вне шейдера.
Матрица вида.
Матрица вида однозначно связана с координатами камеры. Зная положение и ориентацию камеры мы можем всегда получить матрицу вида. Для этого в классе android.opengl.Matrix существует специальная функция Matrix.setLookAtM.
Определим пустой массив для матрицы вида:
float[] viewMatrix = new float[16];
Зададим положение камеры пространстве для примера:
float xposition=0.3f;
float yposition=1.7f;
float zposition=1.5f;
Зададим точку в пространстве, на которую смотрит камера. Пусть камера смотрит на начало мировых координат:
float xlook=0;
float ylook=0;
float zlook=0;
Для однозначного определения матрицы вида этих данных мало, т.к. недостаточно установить наблюдателя в точку и правильно направить его взгляд. Нужно еще запретить наблюдателю качать головой. Зададим вектор, который определит, где у камеры верх. Пусть верх будет вдоль оси Y:
float xtop=0;
float ytop=1;
float ztop=0;
А затем вызовем функцию функция Matrix.setLookAtM, которая рассчитает и заполнит массив viewMatrix:
Matrix.setLookAtM(viewMatrix, 0, xposition, yposition, zposition, xlook, ylook, zlook, xtop, ytop, ztop);
Матрица вида готова.
Матрица модели-вида. Часто комбинируют матрицы модели и вида в единую матрицу модели-вида, которую можно получить путем умножения матрицы вида на матрицу модели. Для умножения двух матриц используют команду Matrix.multiplyMM. float[] modelViewMatrix = new float[16]; Matrix.multiplyMM(modelViewMatrix, 0, viewMatrix, 0, modelMatrix, 0); Получили заполненный массив modelViewMatrix.
Матрица проекции.
Матрица проекции выполняет проекцию координат вершин на экран аппарата после модельно-видовых трансформаций. Она может получена в методе onSurfaceChanged класса рендерера путем выполнения команды Matrix.frustumM для перспективной проекции. Например, так:
............ float projectionMatrix=new float[16]; ............ public void onSurfaceChanged(GL10 unused, int width, int height) { // устанавливаем glViewport GLES20.glViewport(0, 0, width, height); float ratio = (float) width / height; float k=0.055f; float left = -k*ratio; float right = k*ratio; float bottom = -k; float top = k; float near = 0.1f; float far = 10.0f; // получаем матрицу проекции Matrix.frustumM(projectionMatrix, 0, left, right, bottom, top, near, far); } Матрица модели-вида-проекции. Умножив матрицу проекции на матрицу модели-вида получаем комбинированную матрицу модели-вида-проекции: float modelViewProjectionMatrix=new float[16]; Matrix.multiplyMM(modelViewProjectionMatrix,0,projectionMatrix, 0, modelViewMatrix, 0);
Матрица модели-вида-проекции получена. Напомню, что матрица модели-вида-проекции передается в вершинный шейдер как униформа. Вопрос по передаче данных униформ в шейдеры будет рассмотрен позже.