вторник, 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 игрушки? Это позже и очень очень скоро. На этот пост хватит создания окна. Позже рассмотрим помещение фигур в это окно.Пока можете поиграться с параметрами цвета очистки экрана.


3 комментария:

  1. "};" это так и нужно???????
    Скачал и установил
    Qt SDK version 1.2.1 а в нем:

    Qt libraries version 4.8.1
    Qt Creator IDE version 2.4.1

    Все скопировал и вставил, все по вашей инструкции...
    Выдает ошибок 200 сборки
    Вы если я тут скрины повешу, вы сможете мне помочь запустить программу?

    ОтветитьУдалить
    Ответы
    1. Я извиняюсь, прописал правильный Path в настройках Windows и все заработало.
      Очень спасибо за, действительно, вводную статью.

      Удалить
    2. Всегда пожалуйста. Можете продолжить смотреть более интересные вещи.http://alexkutsan.blogspot.com/2012/08/opengl-qt.html

      Удалить