Трансформации в OpenGL ES

Координатная система

OpenGL использует правостороннюю координатную систему. Это значит, что ось x идет слева направо, ось y — снизу вверх, а ось z — из глубины экрана в сторону передней части экрана.



Перемещение (Translate)

Синтаксис:

public abstract void glTranslatef (float x, float y, float z)



Перемещения влияют на все вершины полигона в равной степени в рамках отдельной оси и отражают простые действия «суммирования» и «вычитания».

Пример: начальная точка имеет координаты {x:-2, y:1}. Мы хотим переместить ее в точку {x:1, y:3}, поэтому добавляем {x:3, y:2}.

Расчеты:

{x:-2, y:1} + {x:3, y:2} = {x:-2 + 3, y:1 + 2} = {x:1, y:3}.

В трехмерном пространстве находясь в точке {x:1, y:1, z:0}, мы добавляем {x:0, y:0, z:-3} и в результате будем находиться в точке {x:1, y:1, z:-3}.

Для того, чтобы увидеть площадь на экране, необходимо добавить {x:0, y:0, z:-4} к текущей позиции. Код:

// Translates 4 units into the screen.
gl.glTranslatef(0, 0, -4); 

Вращение (Rotate)

Синтаксис:

public abstract void glRotatef(float angle, float x, float y, float z)



Вращение матрицы, где x, y и z — координаты вектора вращения, angle — угл вращения.

Несколько моментов:
1. Значение угла задается в градусах (не в радианах).
2. При нескольких вращениях порядок трансформаций играет роль. Для того, чтобы отменить вращение для glRotatef(angle, x, y, z), необходимо использовать glRotatef(angle, -x, -y, -z) или glRotatef(-angle, x, y, z).

Но если вы хотите применить несколько вращений:

gl.glRotatef(90f, 1.0f, 0.0f, 0.0f); 
gl.glRotatef(90f, 0.0f, 1.0f, 0.0f); 
gl.glRotatef(90f, 0.0f, 0.0f, 1.0f); 



И хотите востановить начальное состояние, вы не можете использовать такой же подход:

gl.glRotatef(90f, -1.0f, 0.0f, 0.0f); 
gl.glRotatef(90f, 0.0f, -1.0f, 0.0f); 
gl.glRotatef(90f, 0.0f, 0.0f, -1.0f); 



Вы должны использовать трансформации в обратном порядке:

gl.glRotatef(90f, 0.0f, 0.0f, -1.0f); 
gl.glRotatef(90f, 0.0f, -1.0f, 0.0f); 
gl.glRotatef(90f, -1.0f, 0.0f, 0.0f); 

Перемещение и вращение (Translate & Rotate)

Здесь также важно помнить, что порядок трансформаций играет важную роль.

Есть вы сначала перемещаете фигуру, а затем вращаете ее, то поворот будет осуществляться после перемещения:



Если вы вначале вращаете фигуру, а затем перемещаете, то перемещение будет производиться для новой (наклоненной) системы координат:



Масштабирование (Scale)

Синтаксис:

public abstract void glScalef (float x, float y, float z) 

Масштабирование — это умножение вектора на скаляр.

На рисунке показано масштабирование в два раза — gl.glScalef(2f, 2f, 2f).



Перемещение и масштабирование (Translate & Scale)

Если вы перемещаете объект перед масштабированием, то вы получите следующую картину (перемещаем на 2 единицы и уменьшаем в 2 раза):

gl.glTranslatef(2, 0, 0); 
gl.glScalef(0.5f, 0.5f, 0.5f); 



Если же вы масштабируете объект до перемещения вы получите отличный от предыдущего результат — после масштабирования вы переместитесь всего лишь на 1 единицу.

gl.glScalef(0.5f, 0.5f, 0.5f); 
gl.glTranslatef(2, 0, 0); 



Load Identity, push и pop matrix

Когда вы используете трансформации, вы не используете одинаковые условия, а применяете их к предыдущему состоянию объекта. Вам необходимо сбрасывать (reset) позиции.

glLoadIdentity:

public abstract void glLoadIdentity() 

glLoadIdentity заменяет текущую матрицу на единичную:

1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1

glPushMatrix:

public abstract void glPushMatrix() 

glPushMatrix делает копию текущей матрицы и отправляет ее в стэк. Это означает, что все последующие изменения вы будете делать для копии.

glPopMatrix:

public abstract void glPopMatrix() 

Для возвращения к предыдущей матрице используют команду glPushMatrix.

Хорошая практика — вызывать glLoadIdentity в начале каждого фрейма и после этого использовать glPushMatrix и glPopMatrix.

Используем все вместе

Итак, имеем три плоскости — A, B и C. Масштабируем их так, чтобы B была на 50% меньше чем A и C — меньше на 50%, чем B. Потом A будем вращать посредине экрана, B должна вращаться вокруг A и, наконец, C заставим вращаеться вокруг B и одновременно вокруг своего центра с бОльшей скоростью.

Код будет выглядеть следующим образом:

public void onDrawFrame(GL10 gl) {
	// Clears the screen and depth buffer.
	gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
	// Replace the current matrix with the identity matrix
	gl.glLoadIdentity();
	// Translates 10 units into the screen.
	gl.glTranslatef(0, 0, -10); 

	// SQUARE A
	// Save the current matrix.
	gl.glPushMatrix();
	// Rotate square A counter-clockwise.
	gl.glRotatef(angle, 0, 0, 1);
	// Draw square A.
	square.draw(gl);
	// Restore the last matrix.
	gl.glPopMatrix();

	// SQUARE B
	// Save the current matrix
	gl.glPushMatrix();
	// Rotate square B before moving it, making it rotate around A.
	gl.glRotatef(-angle, 0, 0, 1);
	// Move square B.
	gl.glTranslatef(2, 0, 0);
	// Scale it to 50% of square A
	gl.glScalef(.5f, .5f, .5f);
	// Draw square B.
	square.draw(gl);			

	// SQUARE C
	// Save the current matrix
	gl.glPushMatrix();
	// Make the rotation around B
	gl.glRotatef(-angle, 0, 0, 1);
	gl.glTranslatef(2, 0, 0);
	// Scale it to 50% of square B
	gl.glScalef(.5f, .5f, .5f);
	// Rotate around it's own center.
	gl.glRotatef(angle*10, 0, 0, 1);
	// Draw square C.
	square.draw(gl);

	// Restore to the matrix as it was before C.
	gl.glPopMatrix();
	// Restore to the matrix as it was before B.
	gl.glPopMatrix();

	// Increse the angle.
	angle++;
}

    public class OpenGLRenderer implements Renderer {
	private Square square;
	private float angle; // Don't forget to add this.
        ...

Ссылки
Оригинальная статья
OpenGL ES 1.1 Reference Pages
Скачать исходный код примера
  • 0
  • 16 февраля 2010, 15:40
  • admin

Комментарии (0)

RSS свернуть / развернуть

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.