Показаны сообщения с ярлыком openGl. Показать все сообщения
Показаны сообщения с ярлыком openGl. Показать все сообщения

суббота, 4 августа 2012 г.

Помещение актёров на сцену OpenGl Qt

В прошлом посте я рассказал про создание OpenGl окна. Сегодня я расскажу , как туда поместить объект. Сначала создадим окно , как описано тут http://alexkutsan.blogspot.com/2012/04/opengl-qt.html .

Всё не так сложно.
Изменять я буду  функцию paintGL(). В ней происходит отрисовка.Вызывается она всякий раз, когда окно перерисовывается. Мы нарисуем  8 угольник. Определим его вершины:


Да, мы можем заставить компьютер считать все эти косинусы и синусы, но зачем? Компьютер будет раскладывать в ряд каждое выражение. Лучше попросим любого 7-миклассника посчитать нам эти значения. Он нам с первого взгляда всё выведет (стыдно, да?)


Ближе к коду.


void SceneGL::paintGL(){
  glClear(GL_COLOR_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
  glBegin(GL_POLYGON);
      glVertex3f( 0.5f, 1.0f,0.0f);
      glVertex3f(1.0f,0.5f,  0.0f);
      glVertex3f( 1.0f,-0.5f,0.0f);

      glVertex3f(0.5f,-1.0f,0.0f);
      glVertex3f(-0.5f,-1.0f,0.0f);
      glVertex3f(-1.0f,-0.5f,0.0f);

      glVertex3f(-1.0f,0.5f,0.0f);
      glVertex3f(-0.5f,1.0f,0.0f);
   glEnd();
}



Немного описания.

Мы работаем уже в матричной модели. Изменяем ведь саму модель - glMatrixMode(GL_MODELVIEW);

Мы очищаем буфер цветов -  glClear(GL_COLOR_BUFFER_BIT); , ведь у нас появляются здесь цвета( пока-что только белый)

Загружаем единичную матрицу -  glLoadIdentity(); . Никаких трансформаций над матрицей мы не делаем, поэтому этот шаг не обязателен,но делать его принято. Попробуйте вставить
...
glRotated(30,0,0,1);
glBegin(GL_POLYGON);
...
Вы  увидите, что матрица повернётся относительно единичной. Теперь уберите  glLoadIdentity();. Видите? Матрица поворачивается всякий раз при перерисовке окна относительно прошлого её состояния. Это потому, что функция glRotated(30,0,0,1); не поворачивает объект, это мы с вами думаем, что она поворачивает объект. glRotated умножает текущую матрицу на матрицу поворота, параметры которой мы задаём.

Всё серо и грустно.
Давайте добавим радости - добавим цвета.
Перед каждой точкой будем задавать цвет функцией glColor3f. Её параметры - RGB (0.0f-1.0f);
  glBegin(GL_POLYGON);
       glColor3f(1,0,0);
      glVertex3f( 0.5f, 1.0f,-1.0f);
       glColor3f(0,1,0);
      glVertex3f(1.0f,0.5f,  -1.0f);
       glColor3f(0,0,1);
      glVertex3f( 1.0f,-0.5f,-1.0f);

       glColor3f(1,0,1);
      glVertex3f(0.5f,-1.0f,-1.0f);
       glColor3f(1,1,0);
      glVertex3f(-0.5f,-1.0f,-1.0f);
       glColor3f(1,1,1);
      glVertex3f(-1.0f,-0.5f,-1.0f);

       glColor3f(0.5,0.5,0.5);
      glVertex3f(-1.0f,0.5f,-1.0f);
       glColor3f(0,0.5,1);
      glVertex3f(-0.5f,1.0f,-1.0f);
      glEnd();



 
И результат:



Хочу, чтоб всё вертелось!
Когда мы смотрим на объект, мы смотрим на него сверху.
Для простоты , сейчас мы повертим его относительно оси Z.
Если вы посмотрите код выше, то увидите, что наш 6-угольник находился в плоскости Z на уровне  -  -1. Давайте это изменим, и поставим его на уровень 0. И воспользуемся функцией смещения glTranslated(0,0,-3); Тем самым, мы отведём от глаз шестиугольник на 3 шага.

Для того, чтоб повернуть этот шестиугольник , используется функция   glRotatef. Она принимает 4 параметра:
angel - угол на который нужно повернуть объект.
x - поворачивать относительно Ох?
y - поворачивать относительно Оу?
z - поворачивать относительно Oz?

Давайте создадим private переменную  int rot; И создадим public slot void update();
Внутри update напишем.
void SceneGL::update()
{
    rot++;
    updateGL();
}

Теперь, изменим код initializeGL
void SceneGL::initializeGL(){
    glClearColor(0.0f,0.0f,0.0f,1.0f);
    glEnable(GL_DEPTH_TEST);
    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(update()));
    timer->start(10);
    
}

Как видите, мы запускаем таймер, и через каждые 10 миллисекунд будет выполняться update(), тем самым увеличивая переменную rot и перерисовывая сцену. Стоит изменить функцию paintGL
void SceneGL::paintGL(){
    glClear(GL_COLOR_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslated(0,0,-4);
    glRotatef(rot,0,0,1);
    ...
После загрузки единичной матрицы я поворачиваю сцену на rot градусов, а rot постоянно меняется таймером. Запускайте, любуйтесь.

Теперь, давайте повертим наш шести угольник не только относительно Z, а ещё относительно X и Y. Для этого изменим glRotatef(rot,0,0,1); на glRotatef(rot,1,1,1);. Для большей наглядности нарисуем Оси координат. Создайте private функцию

void SceneGL::drawAxis()
{
    glLineWidth(3.0f);
    // до вызова команды ширина равна 9 пикселю по умолчанию
    // устанавливаем цвет последующих примитивов
    glColor4f(1.00f, 0.00f, 0.00f, 1.0f);
    // ось x кvoid Scene3D::drawAxis()
    {
        glLineWidth(3.0f);
        // до вызова команды ширина равна 9 пикселю по умолчанию

        // устанавливаем цвет последующих примитивов
        glColor4f(1.00f, 0.00f, 0.00f, 1.0f);
        // ось x красного цвета
        glBegin(GL_LINES); // построение линии
        glVertex3f( 9.0f,  0.0f,  0.0f); // первая точка
        glVertex3f(-9.0f,  0.0f,  0.0f); // вторая точка
        glEnd();

        QColor halfGreen(0, 128, 0, 255);
        qglColor(halfGreen);
        glBegin(GL_LINES);
        // ось y зеленого цвета
        glVertex3f( 0.0f,  9.0f,  0.0f);
        glVertex3f( 0.0f, -9.0f,  0.0f);

        glColor4f(0.00f, 0.00f, 1.00f, 9.0f);
        // ось z синего цвета
        glVertex3f( 0.0f,  0.0f,  9.0f);
        glVertex3f( 0.0f,  0.0f, -9.0f);
        glEnd();
    }

}

Теперь изменим функцию paintGL вот так:
    ...
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslated(0,0,-4);
    glRotatef(30,1,1,0);
    drawAxis();
    glRotatef(rot,1,1,1);
    ...
и функцию initializeGL
void SceneGL::initializeGL(){
    glClearColor(0.0f,0.0f,0.0f,1.0f);
    glEnable(GL_DEPTH_TEST);
    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(update()));
    timer->start(10);

}
Обратите внимание на glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); и glEnable(GL_DEPTH_TEST);. Я включил тест глубины, если его не включить, то openGl не будет учитывать дальность объектов. Виден будет объект, которые нарисуется первым. С включённым тестом глубины будет виден тот объект, который ближе к наблюдателю(к нам). Ещё я поместил сюда второй glRotatef, который поворачивает сцену на 30 градусов по X и Y - это даст нам удобный угол просмотра. После этого я рисую оси и поворачиваю сцену на rot градусов по всем осям, и рисую 6-угольник. Благодоря этой последовательности прорисовки, оси у меня остаются всегда в 30 градусах, а объект крутится.
Итог получается вот такой:
 
 В следующий раз я расскажу как сделать управляемую сцену, чтоб мы в ней могли перемещаться динамически. Ещё я хочу рассказать, как с помощью примитивов нарисовать сферу. На сегодня всё.Спасибо всем, кто это прочёл. Исходники можно получить здесь : Arctors.zip
Читать дальше......

вторник, 10 апреля 2012 г.

OpenGl вместе с Qt самое начало.Кроссплатформенно

Информации по open gl огромное множество, но она не структурирована и если вы ещё ничего не знаете об Open Gl. Нужно потратить немножно нервов и времени чтоб войти. Под Win всё достаточно просто, есть отличные уроки отNehe под линукс порог входа чуть выше, если покопаться можно найти замечательные туториалы, но надо покопаться. И Почти все они сразу рисуют что-то относительно сложное. Я же хочу сделать может цикл уроков(если меня хватит). Описать свой путь осваивания Open Gl.Конечно, полезно брать сразу сложные примеры, это сложно, но оно даст свои результаты. Так было со мной, начинал я осваивать с икосаэдра. Но это подход имеет множество недостатков. Когда вы его используете, от вас остаётся недопонятым не 1 десяток функций, и их параметров, которые используются в программе, но вы не понимаете их значения, потому что не вы это писали. И после большого количества мучений и удачных и неудачных попыток сразу создавать сложные красивые OpenGl программы. Я решил попробовать планомерно шаг за шагом с самого начала пройтись осторожно медленно добавляя функцию за функций, эксперементируя с её параметрами. И проходиться хочу с вами, дабы вам было легче освоить OpenGl, пусть не так быстро но куда более стойко и уверенно.
И начнём мы с основ основ - создание openGl окна. Кому интересно добро пожаловать под кат.




И так. вперёд и с песней. ничего не боимся.
Основы это конечно хорошо, но с вашего позволения я не буду описывать как устанавливтаь ОС. Пользоваться мы будем Qtcreator. В первом уроке нам достаточно пока-что лишь qmake.

Начнём писать мы программу с файла проекта. И так,создайте папку у себя GlForm.
А в ней файлик GLForm.pro
с таким содержанием:


QT =core gui opengl
TARGET = GlForm
TEMPLATE = app
LIBS += -L/usr/local/lib -lGLU
SOURCES  = main.cpp\
        scenegl.cpp
HEADERS =\
        scenegl.h


В этом файле я указываю Qt что она будет использовать это core(ядро Qt без него никуда),и opengl. Иначе мы не сможем инклуднуть нужные нам библиотеки.
Дальше я указываю TAGET = название проекта. И SOURCES и HEADERS - список исходных файлов проекта. А так-же в LIBS я включаю библиотеку lGLU, без которой мы не сможем пользоваться многими функциями, которые по умолчанию не включены в qt opengl

Перейдём к созданию файла main.cpp

#include "QApplication"
#include "scenegl.h"

int main(int argc, char *argv[])
{
        QApplication app(argc, argv);
        SceneGL scene;
        scene.setWindowTitle("Hello Gl window");
        scene.show();
        return app.exec();
}


Мы подключаем библиотеку QApplication , ведь это не просто C++ а qt с++. И ещё библиотеку "scenegl.h" которую сейчас создадим. В main мы прописываем  QApplication app(argc, argv); это инициализирует приложение Qt. И создаём и показываем класс формочки который вот вот уже создадим. Мне очень нравится идея называть то поле на котором буду происходить действия - сценой. Собственно я и назвал. ИМХО.
Давайте наконец опишем сцену на которой будет всё рисоваться в файле scenegl.h

#ifndef SCENEGL_H
#define SCENEGL_H

#include <QGLWidget>
#include <GL/glu.h>
class SceneGL : public QGLWidget
{
    Q_OBJECT
public:
    explicit SceneGL(QWidget *parent = 0);
 protected:
  void initializeGL();
  void resizeGL(int nWidth,int nHeight);
  void paintGL();  
signals:
    
public slots:
    
};

#endif // SCENEGL_H
Как видите ничего сверх естественного. Я создаю класс который наследуется от QGLWidget, который в свою очередь наследуется от QWidget а этот от QObject.Это даёт право нашему объекту не просто рисоваться посылать сигналы и принимать их в слотах, захватывать мышку и прочее, а ещё и рисоваться с помощью openGl.
Мы должны переопределить 3 функции

#include "scenegl.h" SceneGL::SceneGL(QWidget *parent) : QGLWidget(parent) { }
void initializeGL();
  void resizeGL(int nWidth,int nHeight);
  void paintGL();
Названия говорят за себя

initializeGL() - вызывается 1 раз, при создании окошка, в неё надо запихнуть все начальные настройки OpenGl.
resizeGL(int nWidth,int nHeight) - вызывается при изменении размера окна, если вы не хотите чтоб ваш круг стал яйцом при растягивании окошка, то в этой функции надо кое чего написать.
Ну и paintGL() - в ней мы и будем рисовать, тут находится основной код.

А теперь последний и самый интересный штрих на этот пост, он и так уж затянулся.
Это реализация всех этих функций в файле scenegl.cpp



#include "scenegl.h"

SceneGL::SceneGL(QWidget *parent) :
    QGLWidget(parent)
{
}

void SceneGL::initializeGL(){
 
  glClearColor(0.0f,0.0f,0.0f,1.0f);
}
void SceneGL::resizeGL(int nWidth,int nHeight){
 glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
   gluPerspective(120.0, (GLdouble)nWidth / (GLdouble)nHeight, 0,1000.0);
  glViewport(0,0,(GLint)nWidth,(GLint)nHeight);
}


void SceneGL::paintGL(){
 glLoadIdentity();
  glClear(GL_COLOR_BUFFER_BIT);
} 
Что тут сделано? При создании окна в конструкторе не делается ничего, делать просто нечего.
Когда инициализируется OpenGl мы opengl-овской функцией устанавливаем цвет очистки экрана в чёрный, без прозрачности.(первые 3 параметра это RGB и четвёртый - прозрачность).Обратите внимание на способ записи числа 0.0f.Это встроенный тип GLfloat. Он сделан для стандартизации. Ведь OpenGl кросплатфорненно, а на разных платформах float может быть разным. А GLfloat везде одинаков.

При изменении размеров окна мы изменяем перспективу, это как раз нужно для отсуствия яйцеобразности ваших окружностей. У неё 4 параметра.
1 говорит нам насколько широк наш угол обзора.
2 говорит нам пропорции нашей сцены( бойтесь яйцеобразности)
3 указывает рамки самых близких к нам объектов, не может быть <0. Всё что будет выходить за рамки от нас рисоваться не будет. 4 указывает на рамки самых далёких объектов. Всё что выйдет за них тоже не будет рисоваться.И тоже не может быть <0. Так как рисовать то что за нами не только не имеет смысла, а ещё введёт людей в заблуждение.Вы же не видите ваш затылок перед глазами верно? Ещё одна функция это glViewport. Она определяет прямоугольник в который надо рисовать, ну естественно это начиная с нулей, заканчивая шириной и высотой нашего окошка. Ещё тут нас волнует glLoadIdentity. Она загружает единичную матрицу в память OpenGl. Затем что OpenGl это как автомат состояний, и все операции над ним сохраняются, И поэтому для отсутствия путаницы всегда удобно начинать отсчёт с нулей. В последней функции paintGL мы снова загружаем единичную матрицу, и очищаем экран тем цветом который задали при инициализации. Вот и пожалуй пока-что всё.
запустим qmake затем make и запустим исполняемый фаил
И увидим

Что не густо? А что вы хотели сразу писать 3d игрушки? Это позже и очень очень скоро. На этот пост хватит создания окна. Позже рассмотрим помещение фигур в это окно.Пока можете поиграться с параметрами цвета очистки экрана.


Читать дальше......