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

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

OpenGL ES 1. Текстурирование на примере






В данном примере показано как создать текстурированный многогранник в Android OpenGL ES на примере пирамид. Применен объектно-ориентированный подход. Пирамида разбита на отдельные самостоятельные объекты (полигоны) - треугольники и прямоугольник, внутри которых содержатся собственные свойства полигонов - координаты вершин и текстур, а также определен метод позволяющий вращать полигоны в пространстве.

Используемые классы:

· Texture - класс текстуры. При создании объекта данного класса в память загружется графический файл, соответствующий данной текстуре, а также присваивается уникальное имя для обращения к текстуре. Таким образом, текстура однозначно связывается с картинкой.

· Triangle - класс треугольника. Знает координаты своих вершин и координаты текстур, присвоенных вершинам. При помощи метода rotate можно поворачивать треугольник вокруг любой оси. При этом собственные координаты вершин будут меняться. К треугольнику можно привязать текстуру методом setTextureName, а также отвязать её если сделать имя текстуры равной нулю. Для правильной сортировки полигонов при рисовании полупрозрачной пирамиды в треугольник встроены координаты центра, которые также изменяются при вращении треугольника. Содержит метод draw, рисующий треугольник на экране.

· Quadr - прямоугольник для дна пирамиды. Описывается аналогично треугольнику. При создании прямоугольника задаются координаты трёх вершин, а четвертая рассчитывается автоматически как сумма двух векторов образованных тремя вершинами, т.к. все четыре вершины должны лежать в одной плоскости.

· Pyramid - пирамида, собранная из четырех треугольников и одного прямоугольника. Все пять полигонов жестко связаны по координатам вершин. Определены методы вращающие пирамиду относительно осей, соединяющих её центр и вершины. Каждая грань пирамиды может быть залита отдельной текстурой, а также текстура может быть общей для всех граней пирамиды. Для этого перегружен метод setTextureName.

------------------------------------------------------------------------------------------------------------
Перейдем от теории к практике. Создадим класс Texture, описывающий двумерную текстуру
------------------------------------------------------------------------------------------------------------
package com.blogspot.andmonahov.pyramid;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;
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 idpicture){
int[] names=new int[1];
// генерирует массив свободных имен текстур, состоящий из одного элемента
gl.glGenTextures(1, names, 0);
// запомним имя текстуры
name=names[0];
// имя текстуры - это ее уникальный номер, по которому можно к ней обращаться
// имя текстуры будем хранить в поле name для получения имени из других классов
//позже напишем метод getName
// установим выравнивание
gl.glPixelStorei(GL10.GL_UNPACK_ALIGNMENT,1);

// команда glBindTexture устанавливает текстуру с номером name
// в качестве текущей активной текстуры
gl.glBindTexture(GL10.GL_TEXTURE_2D, name);
// в дальнейшем все настройки действуют на текущую активную текстуру
// устанавливаем параметры текстуры
// включаем автоматическую генерацию мип-мапов всех уровней
gl.glTexParameterx(GL11.GL_TEXTURE_2D,
GL11.GL_GENERATE_MIPMAP, GL11.GL_TRUE);
// устанавливаем фильтры
gl.glTexParameterf(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_MIN_FILTER,
GL10.GL_LINEAR_MIPMAP_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_MAG_FILTER,
GL10.GL_LINEAR);
// если текстура не полностью закрывает рисуемый полигон
// устанавливаем режим повтора рисунка текстуры
gl.glTexParameterx(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
gl.glTexParameterx(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_WRAP_T,
GL10.GL_REPEAT);
//загружаем картинку с идентификаторм idpicture
// idpicture - это уникальный номер картинки в R.java
Bitmap bitmap = BitmapFactory.decodeResource
(context.getResources(), idpicture);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
// удаляем картину из памяти
bitmap.recycle();
// т.о. текущая текстура с именем name связана с картинкой idpicture
}

public int getName(){
return name;
}
}

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

В нашем примере будем рисовать текстурированную пирамиду, поэтому нам понадобятся два класса треугольник для боковых граней пирамиды и прямоугольник для основания. Создадим класс Triangle, описывающий треугольник:

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

package com.blogspot.andmonahov.pyramid;

import java.nio.*;

import javax.microedition.khronos.opengles.GL10;

import android.opengl.Matrix;
public class Triangle {
// определение полей класса координаты первой точки треугольника

private float x1,y1,z1;

// координаты второй точки треугольника

private float x2,y2,z2;

// координаты третьей точки треугольника

private float x3,y3,z3;
// координаты вектора нормали т.к. три точки треугольника всегда лежат

// в одной плоскости достаточно задать координаты одного вектора нормали для всех трех точек
private float nx,ny,nz;
// координаты центра треугольника они будут нам нужны в дальнейшем

//для сортировки треугольников по расстоянию до камеры
private float xcenter,ycenter,zcenter;
// OpenGl не принимает координаты в виде чисел float
// Внешние данные должны быть переданы в OpenGL в байтовых буферах
// поэтому определим три буфера буфер координат вершин
private FloatBuffer vertexBuffer;
// буфер вектора нормали
private FloatBuffer normalBuffer;
// буфер координат текстур
private FloatBuffer texcoordBuffer;
// треугольник может быть заполнен какой либо текстурой
// поэтому создадим поле для хранения имени текстуры
//внутри класса треугольника
private int textureName;


// конструктор

public Triangle(float x1, float y1, float z1, float x2,
float y2, float z2, float x3, float y3, float z3){
// треугольник однозначно описывается тремя точками поэтому в момент его создания в конструктор должны
//быть переданы координаты точек порядок точек 1,2,3 должен соответствовать обходу треугольника

// против часовой стрелки присваиваем координаты точкам

this.x1=x1;

this.y1=y1;

this.z1=z1;

this.x2=x2;

this.y2=y2;

this.z2=z2;

this.x3=x3;

this.y3=y3;

this.z3=z3;

// подготавливаем буфер вершин каждая вершина треугольника содержит три коодинаты x,y,z типа float

// каждая координата типа float занимает 4 байта, итого 12 байт на вершину три вершины используют 3*12=36 байт

ByteBuffer b1 = ByteBuffer.allocateDirect(36);

b1.order(ByteOrder.nativeOrder());

vertexBuffer = b1.asFloatBuffer();

// подготавливаем буфер нормалей

ByteBuffer b2 = ByteBuffer.allocateDirect(36);

b2.order(ByteOrder.nativeOrder());
normalBuffer = b2.asFloatBuffer();

// пересчет нормалей и центра, заполнение буферов координат и нормалей

recount(); //этот метод описан ниже

// подготавливаем буфер координат текстур каждой вершине треугольника присвоены две координаты текстур s и t

// каждая координата занимает 4 байта как число типа float итого 8 байт на вершину, 24 байта не треугольник

ByteBuffer b4 = ByteBuffer.allocateDirect(24);

b4.order(ByteOrder.nativeOrder());

texcoordBuffer = b4.asFloatBuffer();

// заполняем буфер текстур выполняем обход вершин против часовой стрелки

// текстурные координаты верхней точки

texcoordBuffer.put(0.5f); // s

texcoordBuffer.put(1); // t

// текстурные коодинаты левой нижней точки

texcoordBuffer.put(0); // s

texcoordBuffer.put(0); // t

// текстурные координаты правой нижней точки

texcoordBuffer.put(1); // s

texcoordBuffer.put(0); // t

// установим текущую позицию буфера на его начало

texcoordBuffer.position(0);

// при создании треугольника ему еще не присвоена текстура поэтому ставим

textureName = 0;

// присвоить имя текстуры можно через метод setTextureName

}

// описание методов класса при изменении координат вершин треугольника

// изменяются координаты вектора нормали и координаты центра

// поэтому создадим метод который будет их пересчитывать и заполнять буферы новыми координатами

private void recount(){

//заполняем буфер вершин значением координат точек

vertexBuffer.position(0);

// для вершины 1

vertexBuffer.put(x1);

vertexBuffer.put(y1);

vertexBuffer.put(z1);

// для вершины 2

vertexBuffer.put(x2);

vertexBuffer.put(y2);

vertexBuffer.put(z2);

// для вершины 3

vertexBuffer.put(x3);

vertexBuffer.put(y3);

vertexBuffer.put(z3);

vertexBuffer.position(0);

// нормаль может быть получена путем векторного произведения двух векторов - из точки 1 в точку 2 и из точки 2 в точку 3

float dx1=x2-x1;

float dy1=y2-y1;

float dz1=z2-z1;

float dx2=x3-x2;

float dy2=y3-y2;

float dz2=z3-z2;

nx=dy1*dz2-dy2*dz1;

ny=dx2*dz1-dx1*dz2;

nz=dx1*dy2-dx2*dy1;

// приведение вектора нормали к единичной длине выполнять не будем это выполнит OpenGL

normalBuffer.position(0);

// заполняем буфер нормалей, нормаль одинакова для всех трех вершин для вершин 1,2,3 одно и тоже три раза

for (int i=1;i<4;i++){

normalBuffer.put(nx);

normalBuffer.put(ny);

normalBuffer.put(nz);

}

normalBuffer.position(0);

// вычисляем центр треугольника

xcenter=(x1+x2+x3)/3;

ycenter=(y1+y2+y3)/3;

zcenter=(z1+z2+z3)/3;

}

// метод, устанавливающий для использования имя текстуры

public void setTextureName(int name){

textureName=name;

}

// нам могут понадобиться координаты вершин и центра треугольника

// поэтому опишем методы, возвращающие их

public float getx1(){ return x1;}

public float gety1(){ return y1;}

public float getz1(){ return z1;}

public float getx2(){ return x2;}

public float gety2(){ return y2;}

public float getz2(){ return z2;}

public float getx3(){ return x3;}

public float gety3(){ return y3;}

public float getz3(){ return z3;}

public float getxcenter(){ return xcenter;}

public float getycenter(){ return ycenter;}

public float getzcenter(){ return zcenter;}

// создадим метод, который поворачивает треугольник

// относительно вектора заданного двумя точками xa,ya,za и xb,yb,zb на угол angle против часовой стрелки

public void rotate(float angle,

float xa, float ya, float za,

float xb, float yb, float zb){

// создаем матрицу вращения

float [] rotatematrix=new float[16];

// передаем в метод setRotateM угол и три координаты вектора, образованного двумя точками a-b

Matrix.setRotateM(rotatematrix, 0, angle, xb-xa, yb-ya, zb-za);

// в результате получаем заполненную матрицу вращения rotatematrix

// для нахождения новых координат точек после поворота будем использовать метод multiplyMV

// умножения матрицы на вектор размером в 4 элемента зададим вектор, соединяющий точку a и вершину 1 треугольника

float [] oldvector1={x1-xa,y1-ya,z1-za,1};

// получаем новый вектор после поворота

float [] newvector=new float [4];

Matrix.multiplyMV(newvector,0,rotatematrix,0,oldvector1,0);

// добавляем к полученному вектору координаты точки a в результате получаем новые координаты точки 1

x1=newvector[0]+xa;

y1=newvector[1]+ya;

z1=newvector[2]+za;

// аналогично получаем коодинаты точек 2 и 3 после поворота поворачиваем точку 2

float [] oldvector2={x2-xa,y2-ya,z2-za,1};

Matrix.multiplyMV(newvector, 0, rotatematrix, 0, oldvector2, 0);

x2=newvector[0]+xa;

y2=newvector[1]+ya;

z2=newvector[2]+za;

// поворачиваем точку 3

float [] oldvector3={x3-xa,y3-ya,z3-za,1};

Matrix.multiplyMV(newvector, 0, rotatematrix, 0, oldvector3, 0);

x3=newvector[0]+xa;

y3=newvector[1]+ya;

z3=newvector[2]+za;

// пересчитывам нормали, центр и заполняем буферы

recount();

}

// метод, рисующий треугольник на экране

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(GL10.GL_TEXTURE_2D);

// устанавливаем активной текстуру с именем textureName

gl.glBindTexture(GL10.GL_TEXTURE_2D, textureName);

// для учета освещения при использовании текстур включаем режим модуляции

// если вместо GL10.GL_MODULATE поставить GL10.GL_REPLACE эффект освещения исчезнет

gl.glTexEnvx(GL10.GL_TEXTURE_ENV,
GL10.GL_TEXTURE_ENV_MODE,
GL10.GL_MODULATE);

// включаем использование массивов текстур

gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

// указываем программе, что буфер с именем texcoordBuffer является буфером текстур

// первый параметр - это количество координат (две- s и t)

gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,texcoordBuffer);
}else{

// если имя текстуры пустое отключаем использование двумерных текстур

gl.glDisable(GL10.GL_TEXTURE_2D);

}

// рисуем треугольник, последний параметр - это количество точек треугольника (т.е. три)

gl.glDrawArrays(GL10.GL_TRIANGLES,0,3);

}
} // конец класса

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

Таким образом мы создали класс, описывающий треугольник в трехмерном пространстве, научили его поворачиваться на произвольный угол относительно любой оси и хранить внутри себя ссылку на имя текстуры. Аналогично создается класс прямоугольника Quadr.

------------------------------------------------------------------------------------------------------------
package com.blogspot.andmonahov.pyramid;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.Matrix;


public class Quadr {
private float x1,y1,z1,x2,y2,z2,x3,y3,z3,x4,y4,z4;
private float nx,ny,nz;
private float xcenter,ycenter,zcenter;
private FloatBuffer vertexBuffer,normalBuffer,texcoordBuffer;
private int textureName;
public Quadr(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3){
// присваиваем координаты трем точкам, четвертую найдем т.к. все четыре точки должны лежать в одной плоскости
this.x1=x1;
this.y1=y1;
this.z1=z1;
this.x2=x2;
this.y2=y2;
this.z2=z2;
this.x3=x3;
this.y3=y3;
this.z3=z3;
// подготавливаем буфер вершин
ByteBuffer b1 = ByteBuffer.allocateDirect(4*12);
b1.order(ByteOrder.nativeOrder());
vertexBuffer = b1.asFloatBuffer();
// подготавливаем буфер нормалей
ByteBuffer b2 = ByteBuffer.allocateDirect(4*12);
b2.order(ByteOrder.nativeOrder());
normalBuffer = b2.asFloatBuffer();
recount(); // пересчет нормалей и центра, поиск 4-ой точки подготавливаем и заполняем буфер координат текстур
ByteBuffer b4 = ByteBuffer.allocateDirect(4*8);
b4.order(ByteOrder.nativeOrder());
texcoordBuffer = b4.asFloatBuffer();
texcoordBuffer.put(0);
texcoordBuffer.put(1);
texcoordBuffer.put(0);
texcoordBuffer.put(0);
texcoordBuffer.put(1);
texcoordBuffer.put(0);
texcoordBuffer.put(1);
texcoordBuffer.put(1);
texcoordBuffer.position(0);
}
// метод перезаписывает буфер вершин и буфер нормалей, вычисляет центр прямоугольника
private void recount(){
// ищем четвертую точку
x4=x1-x2+x3;
y4=y1-y2+y3;
z4=z1-z2+z3;
// заполняем буфер вершин значением координат точек
vertexBuffer.position(0);
// для вершины 1
vertexBuffer.put(x1);
vertexBuffer.put(y1);
vertexBuffer.put(z1);
// для вершины 2
vertexBuffer.put(x2);
vertexBuffer.put(y2);
vertexBuffer.put(z2);
// для вершины 3
vertexBuffer.put(x3);
vertexBuffer.put(y3);
vertexBuffer.put(z3);
// для вершины 4
vertexBuffer.put(x4);
vertexBuffer.put(y4);
vertexBuffer.put(z4);
vertexBuffer.position(0);
// вычисляем нормаль
float dx1=x2-x1;
float dy1=y2-y1;
float dz1=z2-z1;
float dx2=x3-x2;
float dy2=y3-y2;
float dz2=z3-z2;
nx=dy1*dz2-dy2*dz1;
ny=dx2*dz1-dx1*dz2;
nz=dx1*dy2-dx2*dy1;
/заполняем буфер нормалей, нормаль одинакова для всех четырех вершин
normalBuffer.position(0);
// для вершин 1,2,3,4 одно и тоже 4 раза
for (int i=1;i<5;i++){
normalBuffer.put(nx);
normalBuffer.put(ny);
normalBuffer.put(nz);
}
normalBuffer.position(0);
// вычисляем центр
xcenter=(x1+x2+x3+x4)/4;
ycenter=(y1+y2+y3+y4)/4;
zcenter=(z1+z2+z3+z4)/4;
}
// методы возвращающие координаты вершин и центра
public float getx1(){ return x1;}
public float gety1(){ return y1;}
public float getz1(){ return z1;}

public float getx2(){ return x2;}
public float gety2(){ return y2;}
public float getz2(){ return z2;}

public float getx3(){ return x3;}
public float gety3(){ return y3;}
public float getz3(){ return z3;}

public float getx4(){ return x4;}
public float gety4(){ return y4;}
public float getz4(){ return z4;}

public float getxcenter(){ return xcenter;}
public float getycenter(){ return ycenter;}
public float getzcenter(){ return zcenter;}
// метод, поворачивающий прямоугольник
public void rotate(float angle,
float xa, float ya, float za,
float xb, float yb, float zb){
// создаем матрицу вращения
float [] rotatematrix=new float[16];
// передаем в метод setRotateM угол и три координаты вектора, образованного двумя точками a-b
Matrix.setRotateM(rotatematrix, 0, angle, xb-xa, yb-ya, zb-za);
// в результате получаем заполненную матрицу вращения rotatematrix для нахождения новых координат точек после поворота
// будем использовать метод multiplyMV умножения матрицы на вектор размером в 4 элемента
// зададим вектор, соединяющий точку a и вершину 1
float [] oldvector1={x1-xa,y1-ya,z1-za,1};
// получаем новый вектор после поворота
float [] newvector=new float [4];
Matrix.multiplyMV(newvector,0,rotatematrix,0,oldvector1,0);
// добавляем к полученному вектору координаты точки a в результате получаем новые координаты точки 1
x1=newvector[0]+xa;
y1=newvector[1]+ya;
z1=newvector[2]+za;
// аналогично получаем коодинаты точек 2 и 3 после поворота поворачиваем точку 2
float [] oldvector2={x2-xa,y2-ya,z2-za,1};
Matrix.multiplyMV(newvector, 0, rotatematrix, 0, oldvector2, 0);
x2=newvector[0]+xa;
y2=newvector[1]+ya;
z2=newvector[2]+za;
// поворачиваем точку 3
float [] oldvector3={x3-xa,y3-ya,z3-za,1};
Matrix.multiplyMV(newvector, 0, rotatematrix, 0, oldvector3, 0);
x3=newvector[0]+xa;
y3=newvector[1]+ya;
z3=newvector[2]+za;
// новая точка 4 ищется методом recount пересчитываем нормали, центр и заполняем буферы
recount();
}
// метод, устанавливающий для использования имя текстуры
public void setTextureName(int name){
textureName=name;
}
//метод, рисующий прямоугольник
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(GL10.GL_TEXTURE_2D);
// устанавливаем активной текстуру с именем textureName
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureName);
// для учета освещения при использовании текстур включаем режим модуляции
gl.glTexEnvx(GL10.GL_TEXTURE_ENV,
GL10.GL_TEXTURE_ENV_MODE,
GL10.GL_MODULATE);
// включаем использование массивов текстур
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
// указываем программе, что буфер с именем texcoordBuffer является буфером текстур
gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,texcoordBuffer);
} else{
gl.glDisable(GL10.GL_TEXTURE_2D);
}
//рисуем прямоугольник
gl.glDrawArrays(GL10.GL_TRIANGLE_FAN,0,4);
}
} // конец класса

------------------------------------------------------------------------------------------------------------
Соберем из треугольников и прямоугольника пирамиду
------------------------------------------------------------------------------------------------------------
package com.blogspot.andmonahov.pyramid;
import javax.microedition.khronos.opengles.GL10;
public class Pyramid {
private float xcenter;
private float ycenter;
private float zcenter;
public Triangle [] triangle=new Triangle[4]; // массив боковых треугольников
public Quadr quadr; // квадрат дна
// конструктор
public Pyramid (float x, float y, float z, float l, float h) {
//x,y,z координаты центра основания
//l пол-ширины основания
//h высота
//создаем боковые треугольники
triangle[0]=new Triangle(x,y+h,z, x-l,y,z+l, x+l,y,z+l);
triangle[1]=new Triangle(x,y+h,z, x+l,y,z+l, x+l,y,z-l);
triangle[2]=new Triangle(x,y+h,z, x+l,y,z-l, x-l,y,z-l);
triangle[3]=new Triangle(x,y+h,z, x-l,y,z-l, x-l,y,z+l);
//создаем основание пирамиды
quadr=new Quadr(x-l,y,z+l, x-l,y,z-l, x+l,y,z-l);
recount(); // пересчитаем центр
}
// пересчет координат центра
public void recount(){
xcenter=(triangle[0].getx1()+triangle[0].getx2()+triangle[0].getx3()+
triangle[2].getx2()+triangle[2].getx3())/5;
ycenter=(triangle[0].gety1()+triangle[0].gety2()+triangle[0].gety3()+
triangle[2].gety2()+triangle[2].gety3())/5;
zcenter=(triangle[0].getz1()+triangle[0].getz2()+triangle[0].getz3()+
triangle[2].getz2()+triangle[2].getz3())/5;
}
// для того, чтобы повернуть пирамиду относительно вектора a-b
// на угол angle достаточно повернуть боковые треугольники и квадрат дна
public void rotate(float angle,
float xa, float ya, float za,
float xb, float yb, float zb){
// вызываем методы вращения треугольников четырех треугольников
for (int i=0; i<4; i++){
triangle[i].rotate(angle, xa, ya, za, xb, yb, zb);
}
// вызываем метод вращения квадрата дна
quadr.rotate(angle, xa, ya, za, xb, yb, zb);
// пересчитываем центр пирамиды
recount();
}
// частные случаи метода rotate поворачивает пирамиду относительно оси центр-вершина
public void rotatecenter0 (float angle){
rotate(angle, xcenter, ycenter, zcenter,
triangle[0].getx1(),triangle[0].gety1(), triangle[0].getz1());
}
// аналогично получаем методы поворачивающие пирамиду относительно оси центр-нижний угол
public void rotatecenter1 (float angle){
rotate(angle, xcenter, ycenter, zcenter,
triangle[0].getx2(), triangle[0].gety2(), triangle[0].getz2());
}
public void rotatecenter2 (float angle){
rotate(angle, xcenter, ycenter, zcenter,
triangle[0].getx3(), triangle[0].gety3(), triangle[0].getz3());
}
public void rotatecenter3 (float angle){
rotate(angle, xcenter, ycenter, zcenter,
triangle[2].getx2(), triangle[2].gety2(), triangle[2].getz2());
}
public void rotatecenter4 (float angle){
rotate(angle, xcenter, ycenter, zcenter,
triangle[2].getx3(), triangle[2].gety3(), triangle[2].getz3());
}
// если грани пирамиды надо закрасить разными текстурами применяем этот метод
public void setTextureName(int name1, int name2, int name3, int name4, int name5){
// устанавливаем текстуру боковых треугольников
triangle[0].setTextureName(name1);
triangle[1].setTextureName(name2);
triangle[2].setTextureName(name3);
triangle[3].setTextureName(name4);
// устанавливаем текстуру дна
quadr.setTextureName(name5);
}
// если всю пирамиду надо закрасить одной текстурой применяем этот метод
public void setTextureName(int name){
// устанавливаем текстуру боковых треугольников
triangle[0].setTextureName(name);
triangle[1].setTextureName(name);
triangle[2].setTextureName(name);
triangle[3].setTextureName(name);
// устанавливаем текстуру дна
quadr.setTextureName(name);
}
// рисуем пирамиду
public void draw (GL10 gl){
// рисуем боковые треугольники
for (int i=0; i<4; i++){
triangle[i].draw(gl);
}
// рисуем дно пирамиды
quadr.draw(gl);
}
}//конец класса

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

Рисование осуществляется в классе, реализующем интерфейс GLSurfaceView.Renderer. Создадим такой класс MyClassRenderer. Предварительно поместим в каталоги res\drawable-hdpi, res\drawable-ldpi, res\drawable-mdpi какие-нибудь картинки с именами icon1.jpg, icon2.jpg, icon3.jpg, icon4.jpg, icon5.jpg. Эти фалы будут загружаться в качестве текстур.

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

package com.blogspot.andmonahov.pyramid;

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 поясню позже)

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, 1f};

// цвета отраженного зеркального света

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 tex1,tex2,tex3,tex4,tex5;

//пирамиды

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);

//загружаем текстуры

tex1=new Texture(gl,context, R.drawable.icon1);

tex2=new Texture(gl,context, R.drawable.icon2);

tex3=new Texture(gl,context, R.drawable.icon3);

tex4=new Texture(gl,context, R.drawable.icon4);

tex5=new Texture(gl,context, R.drawable.icon5);

//привязываем текстуры к пирамидам грани ближней пирамиды закрасим разными текстурами

p1.setTextureName(tex1.getName(),tex2.getName(),
tex3.getName(),tex4.getName(),tex5.getName());

// грани дальней пирамиды закрасим одинаковой текстурой

p2.setTextureName(tex1.getName());

}
}//конец класса

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

Рендерер будет создан и запущен в классе, расширяющем GLSurfaceView. Создадим такой класс MyClassSurfaceView.

------------------------------------------------------------------------------------------------------------
package com.blogspot.andmonahov.pyramid;
import android.content.Context;
import android.opengl.GLSurfaceView;
public class MyClassSurfaceView extends GLSurfaceView{
//создадим ссылку для хранения экземпляра нашего класса рендерера
private MyClassRenderer renderer;
// конструктор
public MyClassSurfaceView(Context context) {
// вызовем конструктор родительского класса GLSurfaceView
super(context);
// создадим экземпляр нашего класса MyClassRenderer
renderer = new MyClassRenderer(context);
// запускаем рендерер
setRenderer(renderer);
// установим режим циклического запуска метода onDrawFrame
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
// при этом запускается отдельный поток
// в котором циклически вызывается метод onDrawFrame
// т.е. бесконечно происходит перерисовка кадров
}
} // конец класса

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

Нам осталось только создать экземпляр класса MyClassSurfaceView в нашем Activity и установить вызов его через метод setContentView.

------------------------------------------------------------------------------------------------------------
package com.blogspot.andmonahov.pyramid;
import android.app.Activity;
import android.os.Bundle;
public class PyramidActivity extends Activity {
// создадим ссылку на экземпляр нашего класса MyClassSurfaceView
private MyClassSurfaceView mGLSurfaceView;
// переопределим метод onCreate
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//создадим экземпляр нашего класса MyClassSurfaceView
mGLSurfaceView = new MyClassSurfaceView(this);
//вместо вызова стандартного контента setContentView(R.layout.main);
//вызовем экземпляр нашего класса MyClassSurfaceView
setContentView(mGLSurfaceView);
// на экране появится поверхность для рисования в OpenGL ES
}
@Override
protected void onPause() {
super.onPause();
mGLSurfaceView.onPause();
}
@Override
protected void onResume() {
super.onResume();
mGLSurfaceView.onResume();
}
} // конец класса

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

В результате получим две вращающиеся пирамиды







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



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

ТЕОРЕТИЧЕСКАЯ МЕХАНИКА Статика является частью теоретической механики, изучающей условия, при ко­торых тело находится под действием заданной системы сил...

Теория усилителей. Схема Основная масса современных аналоговых и аналого-цифровых электронных устройств выполняется на специализированных микросхемах...

Логические цифровые микросхемы Более сложные элементы цифровой схемотехники (триггеры, мультиплексоры, декодеры и т.д.) не имеют...

Краткая психологическая характеристика возрастных периодов.Первый критический период развития ребенка — период новорожденности Психоаналитики говорят, что это первая травма, которую переживает ребенок, и она настолько сильна, что вся последую­щая жизнь проходит под знаком этой травмы...

РЕВМАТИЧЕСКИЕ БОЛЕЗНИ Ревматические болезни(или диффузные болезни соединительно ткани(ДБСТ))— это группа заболеваний, характеризующихся первичным системным поражением соединительной ткани в связи с нарушением иммунного гомеостаза...

Решение Постоянные издержки (FC) не зависят от изменения объёма производства, существуют постоянно...

Плейотропное действие генов. Примеры. Плейотропное действие генов - это зависимость нескольких признаков от одного гена, то есть множественное действие одного гена...

Методика обучения письму и письменной речи на иностранном языке в средней школе. Различают письмо и письменную речь. Письмо – объект овладения графической и орфографической системами иностранного языка для фиксации языкового и речевого материала...

Классификация холодных блюд и закусок. Урок №2 Тема: Холодные блюда и закуски. Значение холодных блюд и закусок. Классификация холодных блюд и закусок. Кулинарная обработка продуктов...

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