Array ( )
Вход:




Главная | OpenGL | GLSL | AI | Сеть | Примеры | Библиотека

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, y-height,z);    //Правая вершина

        glColor3ub(0,0,255);            //Синяя вершина
        glVertex3f(x-width, y-height, 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.
Хоть и не в точности, но это похоже на то, как работают матрицы.







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




Комментарии:

Войдите, чтобы оставить комментарий:












Яндекс.Метрика
 Яндекс цитирования.