Студопедия Главная Случайная страница Обратная связь

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

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; просмотров: 634. Нарушение авторских прав; Мы поможем в написании вашей работы!




Кардиналистский и ординалистский подходы Кардиналистский (количественный подход) к анализу полезности основан на представлении о возможности измерения различных благ в условных единицах полезности...


Обзор компонентов Multisim Компоненты – это основа любой схемы, это все элементы, из которых она состоит. Multisim оперирует с двумя категориями...


Композиция из абстрактных геометрических фигур Данная композиция состоит из линий, штриховки, абстрактных геометрических форм...


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

Хронометражно-табличная методика определения суточного расхода энергии студента Цель: познакомиться с хронометражно-табличным методом опреде­ления суточного расхода энергии...

ОЧАГОВЫЕ ТЕНИ В ЛЕГКОМ Очаговыми легочными инфильтратами проявляют себя различные по этиологии заболевания, в основе которых лежит бронхо-нодулярный процесс, который при рентгенологическом исследовании дает очагового характера тень, размерами не более 1 см в диаметре...

Примеры решения типовых задач. Пример 1.Степень диссоциации уксусной кислоты в 0,1 М растворе равна 1,32∙10-2   Пример 1.Степень диссоциации уксусной кислоты в 0,1 М растворе равна 1,32∙10-2. Найдите константу диссоциации кислоты и значение рК. Решение. Подставим данные задачи в уравнение закона разбавления К = a2См/(1 –a) =...

Определение трудоемкости работ и затрат машинного времени На основании ведомости объемов работ по объекту и норм времени ГЭСН составляется ведомость подсчёта трудоёмкости, затрат машинного времени, потребности в конструкциях, изделиях и материалах (табл...

Гидравлический расчёт трубопроводов Пример 3.4. Вентиляционная труба d=0,1м (100 мм) имеет длину l=100 м. Определить давление, которое должен развивать вентилятор, если расход воздуха, подаваемый по трубе, . Давление на выходе . Местных сопротивлений по пути не имеется. Температура...

Огоньки» в основной период В основной период смены могут проводиться три вида «огоньков»: «огонек-анализ», тематический «огонек» и «конфликтный» огонек...

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