Студопедия — OpenGL ES 1. Зеркальное отражение при помощи кубических текстур
Студопедия Главная Случайная страница Обратная связь

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

OpenGL ES 1. Зеркальное отражение при помощи кубических текстур






Кубическая текстура представляет из себя шесть фотографий окружающего пространства: "Правая сторона", "Левая сторона", "Верх", "Низ", "Передняя сторона", "Задняя сторона", которые должны быть подготовлены заранее. Всем шести картинкам присваивается одно имя текстуры и обращение идет к текстуре производится по данному имени. Для создания эффекта зеркального отражения используется автоматическая генерация текстур при помощи команды glTexGeni с параметром GL_REFLECTION_MAP. При этом каждой вершине полигона присваивается координата текстуры, соответствующая зеркальному отражению от поверхности полигона.

Автоматическая генерация текстур несмотря на высокую скорость расчета текстурных координат имеет свои недостатки. В частности, при перемещении камеры зеркальное отражение перемещается в месте с ней и расплывается. Чтобы избавиться от таких нежелательных эффектов, нужно изменять матрицу текстуры. Матрица текстуры - это аналог матрицы модели-вида, применяемый не к координатам вершин X, Y, Z, а координатам текстур S, T, R. Все операции, которые можно применить к матрице модели-вида, можно применять и к матрице текстуры, но действовать они будут на текстурные координаты. По умолчанию матрица текстуры равна единичной матрице. Чтобы зеркальное отражение выглядело корректно нужно компенсировать поворот и перемещение камеры. Для этого записываем в массив текущую матрицу модели-вида с учетом все поворотов и перемещений камеры, получаем из нее обратную матрицу модели-вида, а затем зануляем у обратной матрицы модели-вида элементы, связанные с перемещением. Результат всех этих манипуляций записываем в матрицу текстуры. Перед рисованием следующего полигона матрицу текстуры нужно снова превратить в единичную.

Продемонстрирую это на примере. За основу возьмем код статьи, в которой мы рисовали полупрозрачные пирамиды. Изменим код класса Texture на следующий:

------------------------------------------------------------------------------------------------------------

package com.blogspot.andmonahov.pyramidmirror;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;
import javax.microedition.khronos.opengles.GL11ExtensionPack;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLUtils;
public class Texture {
private int name;
// конструктор кубической текстуры
public Texture(GL10 gl, Context context,
int idpicture1,int idpicture2,int idpicture3,
int idpicture4,int idpicture5,int idpicture6){
// передаем в конструктор шесть фотографий с идентификаторами
// idpicture1, idpicture2, idpicture3, idpicture4, idpicture5, idpicture6
int[] names=new int[1];
// генерируем свободное имя текстуры
gl.glGenTextures(1, names, 0);
name=names[0];
gl.glPixelStorei(GL10.GL_UNPACK_ALIGNMENT,1);
// Вместо параметра состояния GL10.GL_TEXTURE_2D будем использовать GL11ExtensionPack.GL_TEXTURE_CUBE_MAP
gl.glBindTexture(GL11ExtensionPack.GL_TEXTURE_CUBE_MAP, name);
// устанавливаем параметры текстуры
gl.glTexParameterf(GL11ExtensionPack.GL_TEXTURE_CUBE_MAP,

GL10.GL_TEXTURE_MIN_FILTER,

GL10.GL_LINEAR_MIPMAP_LINEAR);

gl.glTexParameterf(GL11ExtensionPack.GL_TEXTURE_CUBE_MAP,
GL10.GL_TEXTURE_MAG_FILTER,
GL10.GL_LINEAR);
gl.glTexParameterx(GL11ExtensionPack.GL_TEXTURE_CUBE_MAP,
GL10.GL_TEXTURE_WRAP_S,
GL10.GL_CLAMP_TO_EDGE);
gl.glTexParameterx(GL11ExtensionPack.GL_TEXTURE_CUBE_MAP,
GL10.GL_TEXTURE_WRAP_T,
GL10.GL_CLAMP_TO_EDGE);
gl.glTexParameterx(GL11ExtensionPack.GL_TEXTURE_CUBE_MAP,
GL11.GL_GENERATE_MIPMAP, GL11.GL_TRUE);
//загружаем картинки правая сторона (положительная координата X)
Bitmap bitmap1 = BitmapFactory.decodeResource
(context.getResources(),idpicture1);
GLUtils.texImage2D(
GL11ExtensionPack.GL_TEXTURE_CUBE_MAP_POSITIVE_X,
0, bitmap1, 0);
bitmap1.recycle();
//левая сторона (отрицательная координата X)
Bitmap bitmap2 = BitmapFactory.decodeResource
(context.getResources(),idpicture2);
GLUtils.texImage2D(
GL11ExtensionPack.GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
0, bitmap2, 0);
bitmap2.recycle();
//верх (положительная координата Y)
Bitmap bitmap3 = BitmapFactory.decodeResource
(context.getResources(),idpicture3);
GLUtils.texImage2D(
GL11ExtensionPack.GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
0, bitmap3, 0);
bitmap3.recycle();
//низ (отрицательная координата Y)
Bitmap bitmap4 = BitmapFactory.decodeResource
(context.getResources(),idpicture4);
GLUtils.texImage2D(
GL11ExtensionPack.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
0, bitmap4, 0);
bitmap4.recycle();
//задняя часть (положительная координата Z)
Bitmap bitmap5 = BitmapFactory.decodeResource
(context.getResources(),idpicture5);
GLUtils.texImage2D(
GL11ExtensionPack.GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
0, bitmap5, 0);
bitmap5.recycle();
//передняя часть (отрицательная координата Z)
Bitmap bitmap6 = BitmapFactory.decodeResource
(context.getResources(),idpicture6);
GLUtils.texImage2D(
GL11ExtensionPack.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
0, bitmap6, 0);
bitmap6.recycle();
}
// метод возвращает имя текстуры
public int getName(){
return name;
}
} //конец класса
------------------------------------------------------------------------------------------------------------

Далее нам не нужно задавать координаты текстуры для вершин полигонов, т.к. мы попросим OpenGL генерировать их автоматически с параметром GL_REFLECTION_MAP, создающим координаты зеркального отражения. В классе Triangle заменим метод draw, рисующий треугольник:

------------------------------------------------------------------------------------------------------------
public void draw (GL10 gl){
vertexBuffer.position(0);
normalBuffer.position(0);
texcoordBuffer.position(0);
// включаем использование массивов вершин
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// указываем, что буфер с именем vertexBuffer является буфером вершин
gl.glVertexPointer(3,GL10.GL_FLOAT,0,vertexBuffer);
// включаем использование массивов нормалей
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
// указываем, что буфер с именем normalBuffer является буфером нормалей
gl.glNormalPointer(GL10.GL_FLOAT,0,normalBuffer);
if (textureName!=0){
// если имя текстуры не пустое включаем использование кубических текстур
gl.glEnable(GL11ExtensionPack.GL_TEXTURE_CUBE_MAP);
// для учета освещения при использовании текстур включаем режим модуляции
gl.glTexEnvx(GL10.GL_TEXTURE_ENV,
GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE);
// устанавливаем активной текстуру с именем textureName
gl.glBindTexture(GL11ExtensionPack.GL_TEXTURE_CUBE_MAP,
textureName);
GL11ExtensionPack gl11ep = (GL11ExtensionPack) gl;
GL11 gl11 = (GL11) gl;
// переходим в режим работы с текстурной матрицей
gl.glMatrixMode(GL10.GL_TEXTURE);
gl.glLoadIdentity();
// записываем в массив modelViewMatrix текущую матрицу модели-вида
float[] modelViewMatrix = new float[16];
gl11.glGetFloatv(GL11.GL_MODELVIEW_MATRIX, modelViewMatrix, 0);
//записываем в массив invertModelViewMatrix обратную матрицу модели-вида
float[] invertModelViewMatrix=new float [16];
Matrix.invertM(invertModelViewMatrix,0,modelViewMatrix,0);
// зануляем у обратной матрицы модели-вида компоненты, связанные с переносом
invertModelViewMatrix[12]=0;
invertModelViewMatrix[13]=0;
invertModelViewMatrix[14]=0;
// записываем invertModelViewMatrix в матрицу текстуры
gl.glLoadMatrixf(invertModelViewMatrix,0);
//генерируем координаты зеркального отражения
gl.glEnable(GL11ExtensionPack.GL_TEXTURE_GEN_STR);
gl11ep.glTexGeni(GL11ExtensionPack.GL_TEXTURE_GEN_STR,
GL11ExtensionPack.GL_TEXTURE_GEN_MODE,
GL11ExtensionPack.GL_REFLECTION_MAP);
//переходим в режим работы с матрицей модели-вида
gl.glMatrixMode(GL10.GL_MODELVIEW);
}else{
// если имя текстуры пустое отключаем использование кубических текстур
gl.glDisable(GL11ExtensionPack.GL_TEXTURE_CUBE_MAP);
}
// рисуем треугольник последний параметр - это количество точек треугольника (т.е. три)
gl.glDrawArrays(GL10.GL_TRIANGLES,0,3);
}
------------------------------------------------------------------------------------------------------------
Аналогично заменим метод draw в классе Quadr.
Отличие будет только в последней строке. Вместо glDrawArrays(GL10.GL_TRIANGLES,0,3) у прямоугольника будет glDrawArrays(GL10.GL_TRIANGLE_FAN,0,4);
Изменим код класса MyClassRenderer. Вместо объявления пяти текстур объявим только одну private Texture texcubemap; и выполним в методе onSurfaceCreated загрузку только одной кубической текстуры

texcubemap=new Texture(gl,context, R.drawable.icon1,R.drawable.icon2,

R.drawable.icon3,R.drawable.icon4,

R.drawable.icon5,R.drawable.icon6);

Для улучшения эффекта зеркальности увеличим Альфа-компоненту отраженного рассеянного света:
private float [] diffusematerialArray={0.8f, 0.8f, 0.8f, 0.8f};
Привожу код класса MyClassRenderer полностью:
-----------------------------------------------------------------------------------------------------------
package com.blogspot.andmonahov.pyramidmirror;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
public class MyClassRenderer implements GLSurfaceView.Renderer{
// интерфейс GLSurfaceView.Renderer содержит
// три метода onDrawFrame, onSurfaceChanged, onSurfaceCreated
// которые должны быть переопределены
// текущий контекст
private Context context;
// позиция камеры
public static float xposition,yposition,zposition;
// направление взгляда камеры
private float xlook,ylook,zlook;
// координаты вектора, указывающего камере, где верх
private float xtop,ytop,ztop;
//
// массивы для хранения цветов материала цвета общего фонового освещения
private float [] ambientmaterialArray={0.2f, 0.2f, 0.2f, 1f};
// цвета отраженного рассеянного света
private float [] diffusematerialArray={0.8f, 0.8f, 0.8f, 0.8f};
// цвета отраженного зеркального света
private float [] specularmaterialArray={0.5f, 0.5f, 0.5f,1f};
// соответствующие им буферы цветов материала
private FloatBuffer ambientmaterialBuffer,
diffusematerialBuffer,specularmaterialBuffer;

// массив для хранения координат источника света
private float [] positionlightArray={0.5f,0,0.2f,0};
// массивы для хранения цветов источника света
// цвета общего фонового освещения
private float [] ambientlightArray={0.5f, 0.5f, 0.5f, 1f};
// цвета отраженного рассеянного света
private float [] diffuselightArray={0.8f, 0.8f, 0.8f, 1f};
// цвета отраженного зеркального света
private float [] specularlightArray={0.8f, 0.8f, 0.8f,1f};
// соответствующие им буферы источника света
private FloatBuffer positionlightBuffer,ambientlightBuffer,
diffuselightBuffer,specularlightBuffer;

//текстуры
private Texture texcubemap;
//пирамиды
private Pyramid p1, p2;
//конструктор
public MyClassRenderer(Context context) {
// запомним контекст он нам понадобится для загрузки текстур
this.context=context;
// настройки камеры
xposition=0.3f;
yposition=0.3f;
zposition=1.2f;
xlook=0;
ylook=0;
zlook=0;
xtop=0;
ytop=1;
ztop=0;
// переписываем цвета материалов из массивов в буферы
ByteBuffer b1 = ByteBuffer.allocateDirect(4 * 4);
b1.order(ByteOrder.nativeOrder());
ambientmaterialBuffer = b1.asFloatBuffer();
ambientmaterialBuffer.put(ambientmaterialArray);
ambientmaterialBuffer.position(0);
//
ByteBuffer b2 = ByteBuffer.allocateDirect(4 * 4);
b2.order(ByteOrder.nativeOrder());
diffusematerialBuffer = b2.asFloatBuffer();
diffusematerialBuffer.put(diffusematerialArray);
diffusematerialBuffer.position(0);
//
ByteBuffer b3 = ByteBuffer.allocateDirect(4 * 4);
b3.order(ByteOrder.nativeOrder());
specularmaterialBuffer = b3.asFloatBuffer();
specularmaterialBuffer.put(specularmaterialArray);
specularmaterialBuffer.position(0);
//
// переписываем координаты источника света в буфер
ByteBuffer b4 = ByteBuffer.allocateDirect(4 * 4);
b4.order(ByteOrder.nativeOrder());
positionlightBuffer = b4.asFloatBuffer();
positionlightBuffer.put(positionlightArray);
positionlightBuffer.position(0);
//
// переписываем цвета источника света из массивов в буферы
ByteBuffer b5 = ByteBuffer.allocateDirect(4 * 4);
b5.order(ByteOrder.nativeOrder());
ambientlightBuffer = b5.asFloatBuffer();
ambientlightBuffer.put(ambientlightArray);
ambientlightBuffer.position(0);
//
ByteBuffer b6 = ByteBuffer.allocateDirect(4 * 4);
b6.order(ByteOrder.nativeOrder());
diffuselightBuffer = b6.asFloatBuffer();
diffuselightBuffer.put(diffuselightArray);
diffuselightBuffer.position(0);
//
ByteBuffer b7 = ByteBuffer.allocateDirect(4 * 4);
b7.order(ByteOrder.nativeOrder());
specularlightBuffer = b7.asFloatBuffer();
specularlightBuffer.put(specularlightArray);
specularlightBuffer.position(0);

// создаем пирамиды
p1=new Pyramid(-0.15f, 0, 0, 0.3f, 0.45f);
p2=new Pyramid(0.3f, 0.2f,-1, 0.3f, 0.45f);
}

public void onDrawFrame(GL10 gl) {
//этот метод вызывается циклически здесь мы будем выполнять рисование
// очищаем буферы глубины и цвета
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// перейдем в режим работы с матрицей модели-вида
gl.glMatrixMode(GL10.GL_MODELVIEW);
// сбросим матрицу модели-вида на единичную
gl.glLoadIdentity();
//
// поворачиваем пирамиды вокруг осей относительно текущего положения пирамиды
p1.rotatecenter0(0.5f);
p1.rotatecenter1(0.2f);
p2.rotatecenter1(-0.5f);
p2.rotatecenter2(-0.2f);
//
// устанавливаем камеру
GLU.gluLookAt(gl, xposition,yposition,zposition, xlook,ylook,zlook, xtop,ytop,ztop);
//
// включаем источник света с номером 0
gl.glEnable(GL10.GL_LIGHT0);
// устанавливаем координаты источника света
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, positionlightBuffer);
// устанавливаем цвета источника света
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);
//
// устанавливаем цвета материала
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);
//
//рисуем дальнюю пирамиду
p2.draw(gl);
//рисуем ближнюю пирамиду
p1.draw(gl);
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
// вызывается при изменении размеров окна
//
// установим область просмотра равной размеру экрана
gl.glViewport(0, 0, width, height);
// подсчитаем отношение ширина/высота
float ratio = (float) width / height;
// перейдем в режим работы с матрицей проекции
gl.glMatrixMode(GL10.GL_PROJECTION);
// сбросим матрицу проекции на единичную
gl.glLoadIdentity();
// устанавливаем перспективную проекцию угол обзора 60 градусов
// передняя отсекающая плоскость 0.1 задняя отсекающая плоскость 100
GLU.gluPerspective (gl, 60, ratio, 0.1f, 100f);
// перейдем в режим работы с матрицей модели-вида
gl.glMatrixMode(GL10.GL_MODELVIEW);
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// вызывается при создании окна включим пересчет нормалей на единичную длину
gl.glEnable(GL10.GL_NORMALIZE);
// включим сглаживание цветов
gl.glShadeModel(GL10.GL_SMOOTH);
// включим проверку глубины
gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glDepthFunc(GL10.GL_LEQUAL);
// разрешим использовать освещение
gl.glEnable(GL10.GL_LIGHTING);

// включаем режим освещения внешних и внутренних сторон
gl.glLightModelx(GL10.GL_LIGHT_MODEL_TWO_SIDE, GL10.GL_TRUE);
// отключаем отсечение невидимых граней
gl.glDisable(GL10.GL_CULL_FACE);
// включаем альфа-компонету цвета
gl.glEnable(GL10.GL_ALPHA);
// включаем смешивание цветов
gl.glEnable(GL10.GL_BLEND);
// устанавливаем режим смешивания цветов
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
//
//загружаем фотографии в кубическую текстуру
texcubemap=new Texture(gl,context, R.drawable.icon1,R.drawable.icon2,
R.drawable.icon3,R.drawable.icon4,
R.drawable.icon5,R.drawable.icon6);
//привязываем текстуры к пирамидам
p1.setTextureName(texcubemap.getName());
p2.setTextureName(texcubemap.getName());
}
}

-------------------------------------------------------------------------------------------------------
Получаем две красивые вращающиеся пирамиды

 







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



Практические расчеты на срез и смятие При изучении темы обратите внимание на основные расчетные предпосылки и условности расчета...

Функция спроса населения на данный товар Функция спроса населения на данный товар: Qd=7-Р. Функция предложения: Qs= -5+2Р,где...

Аальтернативная стоимость. Кривая производственных возможностей В экономике Буридании есть 100 ед. труда с производительностью 4 м ткани или 2 кг мяса...

Вычисление основной дактилоскопической формулы Вычислением основной дактоформулы обычно занимается следователь. Для этого все десять пальцев разбиваются на пять пар...

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

Методы анализа финансово-хозяйственной деятельности предприятия   Содержанием анализа финансово-хозяйственной деятельности предприятия является глубокое и всестороннее изучение экономической информации о функционировании анализируемого субъекта хозяйствования с целью принятия оптимальных управленческих...

Образование соседних чисел Фрагмент: Программная задача: показать образование числа 4 и числа 3 друг из друга...

Классификация и основные элементы конструкций теплового оборудования Многообразие способов тепловой обработки продуктов предопределяет широкую номенклатуру тепловых аппаратов...

Именные части речи, их общие и отличительные признаки Именные части речи в русском языке — это имя существительное, имя прилагательное, имя числительное, местоимение...

Интуитивное мышление Мышление — это пси­хический процесс, обеспечивающий познание сущности предме­тов и явлений и самого субъекта...

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