OpenGL: Матрицы

В этом уроке мы рассмотрим понятие «матрицы» OpenGL. Код взяи из первого урока (инициализация).

Небольшое изменение в файле init.cpp:
В функцию IntializeOpenGL () мы добавили включение теста глубины.
Это позволяет рисовать фигуры друг над другом с правильным учитыванием глубины.
То есть будет отрисован только ближайший к камере обьект.

Функция InitializeOpenGL () в файле Init.cpp теперь выглядит так:

void InitializeOpenGL(int width, int height)
{
g_hDC = GetDC(g_hWnd);
if (!bSetupPixelFormat(g_hDC))
PostQuitMessage (0);g_hRC = wglCreateContext(g_hDC);
wglMakeCurrent(g_hDC, g_hRC);glEnable(GL_DEPTH_TEST);    // Включаем тест глубиныSizeOpenGLScreen(width, height);
}

 

Файл main.cpp затронули более серьезные изменения:

///////////////////////////////// DRAW TRIANGLE \\\\*
/////
/////       Добавляем функцию, рисующую треугольник с центром в точке(X,Y,Z).
/////
///////////////////////////////// DRAW TRIANGLE \\\\*void DrawTriangle(float x, float y, float z, float width, float height)
{
//Мы можем очень легко нарисовать треугольник в заданной позиции.
//Эта ф-я очень простая, лучше сосредоточьтесь на коде матриц, который будет ниже.// Три точки, образующие 3угольник, будут вычислены из переданных в ф-ю координат, а
// размеры будут вычислятся исходя из переданных высоты и ширины.glBegin(GL_TRIANGLES);              //это начало рисования.

glColor3ub(255,0,0);            //Сделаем верхнюю вершину красной
glVertex3f(x, y+height, z);     //Верхняя вершина

glColor3ub(0,255,0);            //Зеленая вершина
glVertex3f(x+width, yheight,z);    //Правая вершина

glColor3ub(0,0,255);            //Синяя вершина
glVertex3f(xwidth, yheight, z);   //Левая вершина
glEnd();    //Закончили отрисовку
}

///////////////////////////////// RENDER SCENE \\\\*
/////
/////         И изменим функцию, рендерящую сцену:
/////
///////////////////////////////// RENDER SCENE \\\\*

void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  //Очистим экран и буфер глубины
glLoadIdentity();       //Сбросим матрицу

//Эта функция устанавливает позицию и направление камеры
//    Позиция        Направление          Вертикальный вектор
gluLookAt(0,0,6,        0,0,0,              0,1,0);

//Ниже мы собственно начинаем  использовать матрицы.
//Что такое матрицы? Не вдаваясь в подробности, матрицы содержат разные системы координат.
//И вы в любой момент можете изменить систему координат.
//
//Вызывая glPushMatrix, вы начинаете использовать другую систему координат, не ту, что предидущая.
//Это значит, что вызывая glRotatef/glTranslatef, вы воздействуете только на полигоны, отрисовывающиеся
//в текущей матрице. Потом вы вызываете glPopMatrix (), и текущая матрица «выдавливается» из стека, и вы возвращаетесь в
//предидущую матрицу.
//
//При инициализации мы попадаем в главную игровую матрицу.
//Если мы «push-нем» другую матрицу и сделаем преобразования в ней, эти изменения никак не
//скажутся на объектах, находящихся вне её.
//
// Ниже я более детально обьясню понятиематриц.
//Одно из преимуществ OpenGL — то, что мы не должны вникать в суть работы матриц, API делает это за нас.
//
//С другой стороны, я рекомендую создать матрицу хоть однажды самостоятельно, иначе
//вы не будете знать, что происходит внутри OpenGL.

//Рендерим треугольник нашей функцией.
DrawTriangle(0,0,0,1,1);

//Теперь нарисуем ещё 1 треугольник, но немного сдвинем его.
//Нам нужно сдвинуть только ЭТОТ треугольник, не затрагивая остальной мир
// — давайте нарисуем его в отдельной матрице.

glPushMatrix();
//теперь у нас «выделенная» матрица; нарисуем в нём такой же треугольник, немного сдвинутый в сторону.
//Устанавливаем позицию, куда будет сдвинут треугольник:
glTranslatef(1,0, — 1);
//И рисуем его
DrawTriangle(0,0,0,1,1);
glPopMatrix();      //Освобождаем текущую матрицу и возвращаемся к предидущей

// Точно так же нарисуем третий треугольник, сдвинутый уже влево.
// Смотрите: отсчет начинается не от нулевых координат, а от второго треугольника,
// поэтому сдвигаем влево на «-2»
glPushMatrix();
glTranslatef(2,0, — 1);
DrawTriangle(1,0,0,1,1);
glPopMatrix();

//Это самый простой пример использования матриц в OpenGL.
//Они вам понадобятся почти во всём, что вы будете делать.
//Причина использования матриц — это намного быстрее и удобнее, чем
//вращение / перемещение каждой точки вручную.

//Теперь посмотрим, много ли вы поняли.
//Что случится, если последний нарисованный треугольник вызвать не (0,0,0,1,1), а (1,0,0,1,1) ?
//Где он будет отрисован? Ответ — в (0,0, -1). Вы спросите, почему?
//Потому что мы передвинули треугольник в (-1,0, -1). Это не перенесло треугольник
//в заданные координаты, а сдвинуло его на заданный отрезок.
//Так что вышло, что координаты мы правильно сдвинули влево, но нарисовали треугольник на единицу правее...
//И треугольник остался в центре, за первым. Попробуйте сами, если не верите мне ;)

SwapBuffers(g_hDC);
}

 

Матрицы — крутая штука, ага? Они позволяют вам делать многое, но с немногим объемом кода.
А это то, что нам нужно, не так ли? ;)

Вот пример гомогенной (homogeneous) матрицы 4×4:
[ 1 0 0 0 ]
[ 0 1 0 0 ]
[ 0 0 1 0 ]
[ 0 0 0 1 ]
Напомнило что-то с уроков математики? Да, это матрица идентичности (identity matrix).

Перемещения для x, y и z сохранены в этих слотах:
[ 1 0 0 x ]
[ 0 1 0 y ]
[ 0 0 1 z ]
[ 0 0 0 1 ]

А вот слоты изменения размера (scaling) для x,y,z:
[ x 0 0 0 ]
[ 0 y 0 0 ]
[ 0 0 z 0 ]
[ 0 0 0 1 ]

Если мы поместим их вместе, то получим одну матрицу, которая
осуществляет вращение и изменение размера:
[ x 0 0 x2 ] //X Y Z — scale-значения, x2 y2 z3 — translation-значения
[ 0 y 0 y2 ]
[ 0 0 z z2 ]
[ 0 0 0 1 ]

Эта матрица имеет 4 строки и 4 столбца
Так она будет выглядеть в кач-ве массива:

float matrix[16] или float matrix[4][4];

Хочу объяснить ещё одну вещь — вы можете делать с матрицами то же самое, что и с пространствами имен C/C++ {} . Пример:

glPushMatrix();
glTranslate(0, 1, 0);
DrawTriangle(0, 0, 0, 1, 1);glPushMatrix();glTranslate(0, 1, 0);
DrawTriangle(0, 0, 0, 1, 1);glPopMatrix();

glPopMatrix();

 

Первый треугольник будет нарисован в (0,1,0) — это просто. Но где будет нарисован второй?
Раз и навсегда запомните, что glTranslatef () не устанавливает координаты отрисовки, а сдвигает обьект на указанный отрезок!
Так как мы уже сдвинули текущую матрицу на (0,1,0), а матрица второго треугольника работает ИЗ неё, второй треугольник будет сдвинут на (0,2,0).

До того, как мы сделали какие-либо вращения/перемещения, инициализированная матрица «чиста».
Это значит, что если мы передвинемся на (x,y,z) — обьект просто передвинется на этот отрезок.
Но если мы передвинем следующий объект, то он будет передвигатся уже не от начала координат, а от точки предыдущего сдвига, пока мы не вызовем glLoadIdentity ().

Может, так будет проще представить: int X=0;

Потом вы указываете: x+=2;

X был «чист», пока вы не добавили к нему двойку. Теперь X изменён, и если вы укажете: X+=2; снова, X уже не будет 2, теперь он будет 4.

Хоть и не в точности, но это похоже на то, как работают матрицы.

Исходные коды к уроку

Понравилась статья? Поделиться с друзьями: