13 октября 2012 г.

Мои разработки. Живые обои "Волны на поверхности"

Живые обои "Волны на поверхности" (английский вариант Surface Wave) - это трехмерная математическая модель виртуальной жидкости. Молекулы на поверхности взаимодействуют друг с другом через силу поверхностного натяжения. Прикосновение к экрану аппарата выводит жидкость из состояния равновесия и приводит к образованию поверхностных волн, которые плавно распространяются во все стороны, накладываются друг на друга и отражаются от границ экрана, постепенно затухая. Чтобы поверхность воды не успокаивалась на экран случайным образом падают капли. Посмотрите как это выглядит:


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

OpenGL ES 2.0. Урок третий-Двумерные текстуры

Загрузка текстуры из файла.
Создадим класс, который загружает двумерную текстуру из графического файла. Нам достаточно разместить какой-нибудь графический файл в папку ресурсов (например, в res/drawable-hdpi), чтобы система присвоила ему идентификатор. Идентификатор ресурса - это целое число, которое является ссылкой на данный ресурс. Идентификаторы ресурсов хранятся в  файле R.java, который система создает автоматически. Если известно имя графического файла ресурса, например picture.png , можно получить его идентификатор как R.drawable.picture.
Итак, приступим к созданию класса. Я думаю, что из комментариев будет все понятно.
public class Texture {
        //создаем поле для хранения имени текстуры
        private int name;
        // конструктор двумерной текстуры из ресурса
        //передаем в качестве аргументов контекст 
        //и идентификатор ресурса графического файла
        public Texture(Context context, int idpicture) {
                //создаем пустой массив из одного элемента
                //в этот массив OpenGL ES запишет свободный номер текстуры, 
                // который называют именем текстуры
                int []names = new int[1];
                // получаем свободное имя текстуры, которое будет записано в names[0]
                GLES20.glGenTextures(1, names, 0);
                //запомним имя текстуры в локальном поле класса
                name = names[0];
                //теперь мы можем обращаться к текстуре по ее имени name
                //устанавливаем режим выравнивания по байту
                GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1);
                //делаем текстуру с именем name текущей
                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, name);
                //устанавливаем фильтры текстуры
                GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
                        GLES20.GL_TEXTURE_MIN_FILTER, 
                        GLES20.GL_LINEAR_MIPMAP_LINEAR);
                GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
                        GLES20.GL_TEXTURE_MAG_FILTER,
                        GLES20.GL_LINEAR);
               //устанавливаем режим повтора изображения 
                //если координаты текстуры вышли за пределы от 0 до 1
                GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
                        GLES20.GL_TEXTURE_WRAP_S,
                        GLES20.GL_REPEAT);
                GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
                        GLES20.GL_TEXTURE_WRAP_T,
                        GLES20.GL_REPEAT);
                // загружаем картинку в Bitmap из ресурса
                Bitmap bitmap = 
                        BitmapFactory.decodeResource(context.getResources(), idpicture);
                //переписываем Bitmap в память видеокарты
                GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
                // удаляем Bitmap из памяти, т.к. картинка уже переписана в видеопамять
                bitmap.recycle();
                // Важный момент ! 
                // Создавать мипмапы нужно только
                // после загрузки текстуры в видеопамять
                GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
        }// конец конструктора двумерной текстуры

        //нам будет нужен метод, который возвращает имя текстуры
        public int getName() {
                return name;
        }
}// конец класса
Создать текстурный объект mTexture для картинки picture.png можно следующим образом:
Texture mTexture=new Texture(context, R.drawable.picture);
а получить его имя можно так:
int  mTextureName=mTexture.getName();

8 октября 2012 г.

OpenGL ES 2.0. Урок второй-Освещение в шейдере

В отличие от OpenGL ES 1 в OpenGL ES 2.0 не предусмотрено специальных команд (glLightfv и glMaterialfv) для управления освещением и материалами. Вместе с тем,  OpenGL ES 2.0 обладает более широкими возможностями по сравнению с OpenGL ES 1.
OpenGL ES 1 автоматически рассчитывает освещение вершин и далее интерполирует их освещенность в цвет пикселя. Вмешаться в процесс расчета цвета пикселя в классическом OpenGL ES 1 мы не можем. Поэтому, чтобы получить плавные переходы в освещенности объекта нужно увеличивать количество вершин. В OpenGL ES 2.0 все проще. Расчет освещенности можно перенести в фрагментный шейдер, в котором все операции производятся с конкретным пикселем.
Поговорим немного об видах освещения.
Фоновое (ambient) освещение.
Фоновое освещение освещает объекты одинаково со всех сторон. Оно не зависит от положения источника света и глаза наблюдателя. Задается константой.
Диффузное (diffuse) или рассеянное освещение.
Яркость объекта, освещенного диффузным светом, зависит от положения объекта и от положения источника света. Диффузный свет отражается от поверхности одинаково во все  стороны. Поэтому положение глаза наблюдателя на диффузное освещение не влияет. Яркость диффузного освещения определяют по фактору Ламберта. Вычисляется косинус угла между вектором нормали и вектором, указывающим из точки на источник света. Чем этот угол меньше, тем ярче освещена точка. Если угол = 0, получаем максимальную яркость. Если угол=90 градусов - яркость будет равна нулю. Покажу это на рисунке: 

3 октября 2012 г.

OpenGL ES 2.0. Урок первый-Шейдеры

Введение в шейдеры.
OpenGL ES 2.0 использует шейдеры языка GLSL. Шейдеры бывают двух типов - вершинный и фрагментный. В вершинном шейдере производятся расчеты над вершинами, а в фрагментном - над пикселями. Рассмотрим простой вершинный шейдер:
uniform mat4 u_modelViewProjectionMatrix;
attribute vec3 a_vertex;
attribute vec3 a_normal;
attribute vec4 a_color;
varying vec3 v_vertex;
varying vec3 v_normal;
varying vec4 v_color;
void main() {
         v_vertex=a_vertex;
         vec3 n_normal=normalize(a_normal);
         v_normal=n_normal;
         v_color=a_color;
        gl_Position = u_modelViewProjectionMatrix * vec4(a_vertex,1.0);
и соответствующий ему фрагментный шейдер:
precision mediump float;
varying vec3 v_vertex;
varying vec3 v_normal;
varying vec4 v_color;
void main() {
        vec3 n_normal=normalize(v_normal);
        gl_FragColor = v_color;
}
Теперь разберем по косточкам, какие процессы происходят в этих шейдерах.