- •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.4 OpenGl es 1. Освещение и материалы
Освещение очень важно для правильного отображения трёхмерных объектов. Например, без освещения сфера будет выглядеть как круг, а цилиндр как прямоугольник. Чтобы использовать освещение нужно обязательно включить его командой glEnable(GL10.GL_LIGHTING), иначе все источники света будут игнорированы. В OpenGL ES допускается одновременно использовать восемь источников света, которые пронумерованы специальными параметрами состояния GL10.GL_LIGHT0, GL10.GL_LIGHT1, GL10.GL_LIGHT2, и.т.д. до GL10.GL_LIGHT7. Чтобы включить источник света нужно вызвать команду glEnable(номер источника света). Например, чтобы включить первый источник света вводим glEnable(GL10.GL_LIGHT1). По умолчанию включен источник света GL10.GL_LIGHT0. Аналогично можно выключить источник света командой glDisable(номер источника света). Каждый источник света имеет свои атрибуты, которые настраиваются независимо от других источников.
Важнейшим из атрибутов источника являются его координаты в пространстве, которые устанавливаются следующей командой:
gl.glLightfv(номер источника, GL10.GL_POSITION, буфер координат источника);
Продемонстрируем это на примере. Например, нам требуется установить источник c номером GL10.GL_LIGHT0 в точку с координатами X=1, Y=1, Z=1. Сначала подготовим буфер для координат источника света длиной в 16 байт:
ByteBuffer bb = ByteBuffer.allocateDirect(16); bb.order(ByteOrder.nativeOrder()); positionlightBuffer = bb.asFloatBuffer();
Почему 16 байт ? Для источника света достаточно трёх координат, каждая из которых занимает 4 байта. Однако, у источника света есть четвертая координата W, которую мы рассматривать не будем и примем равной нулю. Далее создаём массив с координатами и записываем его в буфер:
float [] positionlightArray={1,1,1};
positionlightBuffer.position(0); positionlightBuffer.put(positionlightArray); positionlightBuffer.position(0);
Буфер координат источника света передаем в OpenGL:
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, positionlightBuffer);
Свет, излучаемый источником, содержит в себе три составляющие - фоновую(ambient), рассеянную(diffuse), зеркальную(specular).
Фоновая составляющая освещает трёхмерные объекты одинаково со всех сторон. Фоновый свет отражается во все стороны с одинаковой интенсивностью. Яркость фонового излучения не зависит от ориентации освещаемой поверхности и не зависит от положения глаза наблюдателя и как следствие, одинакова для всех поверхностей.
Рассеянный свет, падая на поверхность, отражается от неё во всех направлениях. Яркость отраженного рассеянного света зависит от ориентации поверхности по отношению к источнику света. В зависимости от направления нормали поверхность может казаться более или менее яркой. Однако, яркость рассеянного света не зависит от положения глаза наблюдателя, т.к. отражение рассеянной составляющей происходит с одинаковой интенсивностью во все стороны.
Зеркальная составляющая отражается от поверхности преимущественно в одном направлении, которое определяется законом отражения. Поэтому её яркость зависит как от ориентации поверхности по отношению к источнику света, так и от положения глаза наблюдателя.
Для каждой составляющей света задаются отдельно четыре компоненты: красная, зелёная, синяя и альфа. Каждая компонента спектра может иметь собственную яркость. Спектральные компоненты источника света передаются в OpenGL при помощи команды:
gl.glLightfv(номер источника света, составляющая света, буфер цветов);
Приведу пример:
// Создадим массивы и буферы для хранения цветов источника света // Запишем спектральные компоненты в буферы
// цвета фоновой составляющей света float [] ambientlightArray={0.5f, 0.5f, 0.5f, 1}; FloatBuffer ambientlightBuffer; ByteBuffer b1 = ByteBuffer.allocateDirect(16); b1.order(ByteOrder.nativeOrder()); ambientlightBuffer = b1.asFloatBuffer(); ambientlightBuffer.position(0); ambientlightBuffer.put(ambientlightArray); ambientlightBuffer.position(0);
// цвета рассеянной составляющей света float [] diffuselightArray={0.8f, 0.8f, 0.8f, 1}; FloatBuffer diffuselightBuffer; ByteBuffer b2 = ByteBuffer.allocateDirect(16); b2.order(ByteOrder.nativeOrder()); diffuselightBuffer = b2.asFloatBuffer(); diffuselightBuffer.position(0); diffuselightBuffer.put(diffuselightArray); diffuselightBuffer.position(0);
// цвета зеркальной составляющей света float [] specularlightArray={0.8f, 0.8f, 0.8f, 1}; FloatBuffer specularlightBuffer;
ByteBuffer b3 = ByteBuffer.allocateDirect(4 * 4); b3.order(ByteOrder.nativeOrder()); specularlightBuffer = b3.asFloatBuffer(); specularlightBuffer.position(0); specularlightBuffer.put(specularlightArray); specularlightBuffer.position(0);
Теперь передадим цвета в OpenGL:
// цвета фоновой составляющей света
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, ambientlightBuffer);
// цвета рассеянной составляющей света gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, diffuselightBuffer);
// цвета зеркальной составляющей света gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPECULAR, specularlightBuffer);
Цвета источника света установлены. Их нужно рассматривать как способность источника света излучать фоновую, рассеянную и зеркальную составляющую света какой-либо цветовой гаммы. Способность отражать ту или иную составляющую света относится к свойствам материала, из которого сделана поверхность. Способность излучать и способность отражать разные свойства. Например, источник света может излучать рассеянную составляющую зеленого цвета с максимальной яркостью, равной 1. Однако, поверхность может быть сделана из такого материала, который вообще не отражает зелёный цвет. В этом случае, зелёный цвет не дойдёт до нашего глаза. Поэтому в OpenGL вводится понятие материала и задаются ряд его свойств связанных с отражением света, которые аналогичны свойствам источника света. Задаются они командой glMaterialfv. Формат команды такой:
gl.glMaterialfv(освещаемая поверхность, составляющая света, буфер);
Первый параметр принимает следующие значения:
GL10.GL_FRONT_AND_BACK - команда применяется для обратной и лицевой стороны поверхности,
GL10.GL_FRONT - команда применяется только для лицевой стороны поверхности,
GL10.GL_BACK - команда применяется только для обратной стороны поверхности.
Второй параметр определяет составляющую света:
GL10.GL_AMBIENT - команда применяется для отраженного поверхностью фонового света,
GL10.GL_DIFFUSE - команда применяется для отраженного поверхностью рассеянного света,
GL10.GL_SPECULAR - команда применяется для отраженного поверхностью зеркального света.
Третий параметр - это буфер в котором содержатся компоненты цветовой гаммы, т.е.яркость красной, зелёной и синей компоненты отраженного света, а также альфа-компонента, т.е степень непрозрачности материала. Применение команды glMaterialfv покажу на примере: // массивы для хранения цветов материала // цвета фонового освещения float [] ambientmaterial={0.2f, 0.2f, 0.2f, 1f}; // цвета рассеянного света float [] diffusematerial={0.8f, 0.8f, 0.8f, 1f}; // цвета зеркального света float [] specularmaterial={0.5f, 0.5f, 0.5f,1f};
// соответствующие им буферы цветов материала private FloatBuffer ambientmaterialBuffer,diffusematerialBuffer,specularmaterialBuffer;
ByteBuffer b1 = ByteBuffer.allocateDirect(16); b1.order(ByteOrder.nativeOrder()); ambientmaterialBuffer = b1.asFloatBuffer(); ambientmaterialBuffer.put(ambientmaterial); ambientmaterialBuffer.position(0);
ByteBuffer b2 = ByteBuffer.allocateDirect(16); b2.order(ByteOrder.nativeOrder()); diffusematerialBuffer = b2.asFloatBuffer(); diffusematerialBuffer.put(diffusematerial); diffusematerialBuffer.position(0); ByteBuffer b3 = ByteBuffer.allocateDirect(16); b3.order(ByteOrder.nativeOrder()); specularmaterialBuffer = b3.asFloatBuffer(); specularmaterialBuffer.put(specularmaterial); specularmaterialBuffer.position(0); // передаем данные о цветах материала в OpenGL gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, ambientmaterialBuffer); gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, diffusematerialBuffer); gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, specularmaterialBuffer);
С зеркальной составляющей тесно связано понятие блеска. Чем больше блеск, тем меньше размер отраженного "зайчика" и тем больше его яркость. Показатель блеска может меняться от 0 до 128. Блеск действует только на зеркальную составляющую и управляется командой:
gl.glMaterialf(GL10.GL_FRONT_AND_BACK, GL10.GL_SHININESS, shine);
где shine - число от 1 до 128.
Если включено освещение собственные цвета вершин игнорируются. Чтобы в режиме освещения включить цвета вершин нужно выполнить команду:
gl.glEnable(GL10.GL_COLOR_MATERIAL);
Однако, при этом исчезнет эффект освещения. Совмещение собственных цветов вершин и цветов отраженного материалом света в OpenGL ES не выполняется. Если нужно вернуться от отображения цветов вершин в режим освещения выполняем команду:
gl.glDisable(GL10.GL_COLOR_MATERIAL);
Мы можем выбрать модель освещения, при которой освещена будет только лицевая сторона полигона, либо другую модель, в которой освещены обе стороны - лицевая и обратная. Установка модели производится командами:
// освещаются обе стороны полигона gl.glLightModelx(GL10.GL_LIGHT_MODEL_TWO_SIDE, GL10.GL_TRUE); // освещается только лицевая сторона gl.glLightModelx(GL10.GL_LIGHT_MODEL_TWO_SIDE, GL10.GL_FALSE);
