- •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. Шейдер преломления света
1.2 OpenGl es 1. Основы рисования для начинающих
Основным изображаемым объектом в OpenGL является вершина. Вершина-это точка в трёхмерном пространстве. Вершина имеет ряд атрибутов. Главными атрибутами вершины являются ее координаты X, Y, Z. В OpenGL принято, что относительно экрана, на который проецируется изображение, ось X направлена слева направо, ось Y-снизу вверх, ось Z-из глубины экрана к его поверхности. По умолчанию точка с координатами X=0, Y=0, Z=0 находится в центре экрана. Другими атрибутами вершины являются цвет, вектор нормали и координаты текстуры.
Aтрибут координат вершины.
В отличие от "большого" OpenGL в "маленьком" OpenGL ES при рисовании многоугольников не существует возможности передачи в графический конвейер координат каждой точки отдельно. Команда glVertex не включена в данный API. Также отсутствует блок рисования glBegin...glEnd. Единственным способом передачи координат вершин в OpenGL ES являются массивы. Однако, массивы чисел с плавающей точкой в OpenGL ES напрямую тоже не передаются. OpenGL ES в качестве координат вершин принимает только найтивные буферы класса FloatBuffer. Поэтому мы должны предварительно записать координаты вершин в буфер, а затем передать этот буфер в OpenGL ES. На первом этапе главным является правильное вычисление размера буфера.
Например, нам требуется нарисовать треугольник. Каждой вершине треугольника присвоены три координаты как числа с плавающей точкой, каждой число с плавающей точкой занимает в памяти 4 байта. Итого, получаем 12 байт на точку. Всего для координат вершин треугольника, который имеет три точки, требуется буфер размером 36 байт. В нашем случае подготовка буфера для координат выглядит следующим образом:
FloatBuffer vertexBuffer; ByteBuffer bb = ByteBuffer.allocateDirect(36); bb.order(ByteOrder.nativeOrder()); vertexBuffer = bb.asFloatBuffer();
Приступим к заполнению буфера координатами вершин. Для этого служит метод put класса FloatBuffer. Рассмотрим это на примере прямоугольного треугольника:
// задаем координаты первой вершины треугольника float x1=0; float y1=0; float z1=0; // задаем координаты второй вершины треугольника float x2=1; float y2=0; float z2=0; // задаем координаты третьей вершины треугольника float x3=0; float y3=1; float z3=0; // поставим текущую позицию в буфере на начало vertexBuffer.position(0); // записываем в буфер координаты вершин треугольника vertexBuffer.put(x1); vertexBuffer.put(y1); vertexBuffer.put(z1); vertexBuffer.put(x2); vertexBuffer.put(y2); vertexBuffer.put(z2); vertexBuffer.put(x3); vertexBuffer.put(y3); vertexBuffer.put(z3); // снова ставим текущую позицию в буфере на начало vertexBuffer.position(0);
Координаты передаются в буфер последовательно X,Y,Z первой точки, X,Y,Z второй точки, и.т.д. Кроме того, важно соблюдать порядок обхода точек. У треугольника есть две стороны - лицевая и обратная. Лицевой стороной считается та, у которой обход вершин выполнен против часовой стрелки. Обратной стороной та, у которой обход выполнен по часовой стрелке. По умолчанию лицевая сторона будет видна нам, а обратная-нет.
На практике я выяснил, что метод put является затратным с точки зрения времени выполнения. Чем реже используется метод put, тем быстрее выполняется отрисовка кадра.
Поэтому при большом количестве точек целесообразно сначала завести массив чисел, а потом одной командой put "загнать" его в буфер. Например, для треугольника это выглядит так:
float [] trianglecoord={0,0,0, 1,0,0, 0,1,0}; vertexBuffer.position(0); vertexBuffer.put(trianglecoord); vertexBuffer.position(0);
После подготовки буфера координат можно приступать к передаче его OpenGL ES.
Однако подготовительные мероприятия на этом не закончены. Мы должны сначала разрешить использование массивов вершин командой
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
Теперь начинаем передачу координат вершин OpenGL. Мы должны сообщить OpenGL, что в данный момент для рисования мы будем использовать именно наш буфер координат vertexBuffer, а не какой-нибудь другой. Для установки текущего буфера координат используется команда:
gl.glVertexPointer(3,GL10.GL_FLOAT,0,vertexBuffer); Первый аргумент 3 - количество координат на вершину. Каждая вершина имеет три координаты X,Y,Z. Второй аргумент GL10.GL_FLOAT указывает, что буфере заполнен числами с плавающей точкой. Третий аргумент 0 - сдвиг в байтах между координатами одной вершины и координатами следующей вершины. Сдвиг использовать не будем, чтоб не усложнять статью. Четвертый аргумент vertexBuffer - это наш буфер координат вершин. Теперь координаты вершин переданы в OpenGL. Приступаем к отображению треугольника на экране: gl.glDrawArrays(GL10.GL_TRIANGLES,0,3);
Первый аргумент этой команды GL10.GL_TRIANGLES сообщает OpenGL, что нужно соединить все три точки в треугольник и отобразить его со сплошной заливкой цветами вершин.
Второй аргумент 0 - это индекс начального элемента.
Третий аргумент 3 - количество индексов, т.е. количество отображаемых точек. У треугольника их три.
Треугольник является базовой фигурой для рисования поверхностей в OpenGL. Почему именно треугольник ? Потому что все три точки треугольника лежат в одной плоскости. Для расчета освещения нам понадобится вычислить нормаль к поверхности. Для всех точек, лежащих в одной плоскости, нормаль всегда одинакова и определяется однозначно. Если же взять за основу четырехугольник, то совсем не обязательно, что все четыре точки будут находиться в одной плоскости. Поэтому в общем случае нормаль для четырехугольника не определяется однозначно. Однако, всегда можно вычислить четвертую точку исходя из первых трёх, чтобы все четыре точки лежали в одной плоскости.
Из треугольников можно составить любую поверхность если сделать эти треугольники достаточно маленькими, чтобы поверхность отображалась ровной. Даже если поверхность при выводе на экран кажется ступенчатым многогранником можно привести её к ровному виду если включить режим сглаживания цветов командой glShadeModel(GL10.GL_SMOOTH). При этом все же нужно обеспечить на поверхности достаточное количество треугольников, иначе изображение будет размыто и потеряет четкость.
Как составить поверхность из треугольников ? Вернемся к описанию команды glDrawArrays.
При использование аргумента GL10.GL_TRIANGLES каждая тройка точек рисуется как отдельный треугольник. Например, если у нас имеется буфер координат из 9 точек, пронумерованных от 0 до 8, то при выполнении команды glDrawArrays(GL10.GL_TRIANGLES,0,9) будут нарисованы три треугольника: первый - из точек 0-1-2, второй - из точек 3-4-5, третий-из точек 6-7-8.
Если вместо GL10.GL_TRIANGLES использовать аргумент GL10.GL_TRIANGLE_STRIP будет нарисована сплошная лента из связанных треугольников. При этом порядок рисования треугольников будет такой - сначала рисуется треугольник из точек 0-1-2, затем 2-1-3, затем 2-3-4, затем 4-3-5 и.т.д.
|
Порядок обхода вершин при использовании GL_TRIANGLE_STRIP |
При использовании аргумента GL10.GL_TRIANGLE_FAN получаем веер треугольников с общей точкой 0. Порядок рисования при этом изменится: сначала рисуется треугольник с вершинами 0-1-2, затем 0-2-3, затем 0-3-4 и.т.д.
|
Порядок обхода вершин при использовании GL_TRIANGLE_FAN |
С помощью комбинаций GL_TRIANGLE_STRIP и GL_TRIANGLE_FAN можно построить довольно сложную поверхность. Например, поверхность земного шара в виде сферы :) На полюсах можно построить веер, а параллели изобразить виде лент.
