Уроки, алгоритмы, программы, примеры

Вход на сайт

Материалы по разделам

Построения
на плоскости (2D)
Графика
в пространстве (3D)
Вычислительная
геометрия
Физическое
моделирование
Фрактальная
графика

Новые комментарии

Очень интересно! ии сайт крутой жалко что умирает(
У Вас число превысит максимальное число int. Можно использовать в Вашем случае uint, но лучше все переписать на double.
Добавление к программе строки glutReshapeFunc(changeSize); приводит к тому, что треугольник перестаёт совсем отрисовываться.
Выдаёт ошибку glut32.dll не найден! При том, что он лежит в System32! Всё решил) Нужно отправить не в System32, а в System.
Спасибо за статью. Я не Ваш студент. Но мне она помогла написать функцию для Канторова множества на Python для черепашки: import turtle def kanter(x, y, d):     if d > 1:         turtle...

Счетчики и рейтинг

Рейтинг@Mail.ru Яндекс.Метрика
Скриншот к примеру
Среда программирования: 
Qt
Статья по теме: 

Создание сцены при помощи функций OpenGL и языка GLSL для построение трёхмерных объектов в среде Qt Creater.

Код программы: 

Содержание mainglwidget.h
#ifndef MAINGLWIDGET_H
#define MAINGLWIDGET_H
 
#include <QGLWidget>
#include <QMouseEvent>
#include <QMatrix4x4>
#include <QGLShaderProgram>
#include <QCoreApplication>
#include <math.h>
#include <iostream>
#include <QVector>
#include <QPair>
 
#define CUBE_GRAN 1.0f
//четное
#define EARTH_SIZE 10
#define COUNT_TREE 12
using namespace std;
class MainGLWidget : public QGLWidget
{
 
public:
    MainGLWidget(QWidget *);
    void run();
private:
    int sunAngle = 270;
    int angleSpeed = 1;
    QVector<QPair<int, QPointF>> trees; //высота дерева и его координата
    QVector<int> cloudE = {1,0,1,1,0,0,1,1,0,1}; //какие сферы будут рисоваться
    QPointF cloudP = {5,5}; //позиция облака
    QPointF cloudS = {1,0.5}; //шаг облака
    QVector<QVector3D> dropVector; //вектор капель
    // Матрица поворота
    QMatrix4x4 rotateMatrix;
 
    // Позиция указателя мыши
    QPoint mousePosition;
    double k = 0.03; //на сколько уменьшать/увеличивать изображение
 
    // Процедура для изменения матрицы проектирования
    void resetProjection();
 
    // Процедура для изменения видовой матрицы
    void resetModelView();
 
    // Инициализация шейдеров
    void initShader(void);
    void initTextures();
 
    void initializeGL();
    void resizeGL(int nWidth, int nHeight);
    void paintGL();
    void mouseMoveEvent(QMouseEvent* m_event);
    void mousePressEvent(QMouseEvent* m_event);
    void keyPressEvent(QKeyEvent* key_event);
    void wheelEvent(QWheelEvent *event);
    void closeEvent(QCloseEvent *event);
 
    void glEarth();
    void glHome();
    void glSun();
    void glTrees();
    void glCloud();
    void glDrop();
 
    void stepCloud();
    void upLight();
 
    // Матрица видового преобразования
    QMatrix4x4 modelViewMatrix;
 
    // Матрица проектирования
    QMatrix4x4 projectMatrix;
 
    QGLShaderProgram shader_program;
 
    //айдишники того что передается в шейдеры
    int vertexLocation;
    int matrixLocation;
    int colorLocation;
    int imposterCheckLocation;
    int defAlways;
 
    int normLoc;
    int normMatrLoc;
    int lightPos;
    int defCLoc;
    int texLoc;
    GLuint texs[3];
};
 
#endif // MAINGLWIDGET_H
 
Содержание mainglwidget.cpp
#include "mainglwidget.h"
#include <GL/glu.h>
#include <QDebug>
#include <QMatrix4x4>
#include <iostream>
 
using namespace std
;
MainGLWidget::MainGLWidget(QWidget *parent)
    : QGLWidget(QGLFormat(), parent)
{
    setWindowTitle("Home in forest");
    setWindowState(Qt::WindowFullScreen); //развернуть на весь экран
    for (int i = -9; i<10; i+=3) //сгенерировать деревья
    {
        for (int j=-9;j<10;j+=3)
        {
            if((i<-8 or i>-5) and(j<-8 or j>-5)) //не рисовать деревья там, где стоит домик
                if(rand()%3)
                    trees.push_back({rand()%3+4, {i+(rand()%4)*0.25, j+(rand()%4)*0.25}}); //записать случайную координату в вектор
        }
    }
}
 
void MainGLWidget::initializeGL()
{
    // Включение сортировки по глубине, чтобы то, что ближе, отрисовывалось ближе, а то, что дальше, дальше
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_TEXTURE_2D); //включить текстуры
 
    // Инициализируем видовую матрицу
    resetModelView();
    //Инициализируем шейдеры
    initShader();
    initTextures();
}
 
void MainGLWidget::initShader(void)
{
    // Текст вершинного шейдера
    shader_program.addShaderFromSourceFile(QGLShader::Vertex, ":/vertexShader.vsh");
 
    // Текст фрагментного шейдера
    shader_program.addShaderFromSourceFile(QGLShader::Fragment, ":/fragmentShader.fsh");
 
    if (shader_program.link() == false)
        qDebug() << shader_program.log();
 
    // Достаем идентификатор массива вершин
    vertexLocation = shader_program.attributeLocation("vertex");
 
    texLoc = shader_program.attributeLocation("texture");
 
    // Достаем идентификатор матрицы
    matrixLocation = shader_program.uniformLocation("matrix");
 
    // Идентификатор цвета
    colorLocation =  shader_program.uniformLocation("color");
 
    defAlways =  shader_program.uniformLocation("defAlways");
 
    normLoc = shader_program.attributeLocation("normal");
    normMatrLoc =  shader_program.uniformLocation("normalMatrix");
    lightPos =  shader_program.uniformLocation("lightPos");
    defCLoc =  shader_program.uniformLocation("defC");
}
 
void MainGLWidget::initTextures()
{
    QImage texture;
    glGenTextures(5, texs); //сгенерировать внутри шейдера место под текстуры
 
    texture.load(":/UP.png"); //загрузить изображение в память
    texture = convertToGLFormat(texture); //преобразовать изображение к gl-формату
    glBindTexture(GL_TEXTURE_2D, texs[0]); //выбираем текстуру [0]
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    //загрузить текстуру в слот в шейдере
    glTexImage2D(GL_TEXTURE_2D, 0, 3, GLsizei(texture.width()), GLsizei(texture.height()), 0, GL_RGBA, GL_UNSIGNED_BYTE, texture.bits());
 
    texture.load(":/Wall.png"); //загрузить изображение в память
    texture = convertToGLFormat(texture); //преобразовать изображение к gl-формату
    glBindTexture(GL_TEXTURE_2D, texs[1]); //выбираем текстуру [1]
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    //загрузить текстуру в слот в шейдере
    glTexImage2D(GL_TEXTURE_2D, 0, 3, GLsizei(texture.width()), GLsizei(texture.height()), 0, GL_RGBA, GL_UNSIGNED_BYTE, texture.bits());
 
    texture.load(":/Earth.png"); //загрузить изображение в память
    texture = convertToGLFormat(texture); //преобразовать изображение к gl-формату
    glBindTexture(GL_TEXTURE_2D, texs[2]); //выбираем текстуру [2]
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    //загрузить текстуру в слот в шейдере
    glTexImage2D(GL_TEXTURE_2D, 0, 3, GLsizei(texture.width()), GLsizei(texture.height()), 0, GL_RGBA, GL_UNSIGNED_BYTE, texture.bits());
}
 
void MainGLWidget::resizeGL(int width, int height) //изменение зоны рисования
{
    glViewport(0, 0, width, height);
    //перегенерируем матрицу проектирования
    resetProjection();
}
 
// Внутри данной подпрограммы происходит рисование объектов
void MainGLWidget::paintGL()
{
    // Очистка буфера глубины и буфера цвета
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    resetModelView(); //новая видовая матрица
    glEarth(); //рисует землю
    glHome(); //рисует дом
    glSun(); //рисует солнце и луну
    glTrees(); //рисует деревья
    glCloud(); //рисует облако
    glDrop(); //рисует дождь
}
 
void MainGLWidget::resetProjection()
{
    projectMatrix.setToIdentity(); //заполнить матрицу единицами
    // Умножение на матрицу перспективного проектирования
    projectMatrix.perspective(30.0, (float)width() / height(), 0.1, 20); //проецирует на плоскость так, чтобы картинка была объемной
}
 
// Процедура для изменения видовой матрицы
void MainGLWidget::resetModelView()
{
    modelViewMatrix.setToIdentity(); //инициализировать единичной матрицей
 
    //двигаем сцену, чтобы ее было видно
    modelViewMatrix.translate(0, 0, -3);
    //скалируем координаты, чтобы было удобнее отрисовывать и передвигать объекты
    modelViewMatrix.scale(k, k, k); //увеличивать/уменьшать сцену
    modelViewMatrix.rotate(20, 1, 0, 0); //поворачивает сцену
    modelViewMatrix *= rotateMatrix.transposed(); //реализация вращения
}
 
// Обработчик события перемещения указателя мыши (событие происходит при зажатой кнопке мыши)
void MainGLWidget::mouseMoveEvent(QMouseEvent* m_event)
{
    // Вычислим, на сколько переместился курсор мыши между двумя событиями mouseMoveEvent
    QPoint dp = m_event->pos() - mousePosition;
    // Изменим матрицу поворота в соответствии с тем, как пользователь переместил курсор мыши
    rotateMatrix.rotate(-dp.x()/5., 0, 1, 0);
    rotateMatrix.rotate(-dp.y()/5., 1, 0, 0);
    // Сохраним текущую позицию мыши
    mousePosition = m_event->pos();
    // Обновим матрицу аффинных преобразований
    resetModelView();
    updateGL(); // Перерисовать окно
}
 
void MainGLWidget::mousePressEvent(QMouseEvent* m_event)
{
    //Сохраняем позицию после нажатия что бы картинка не дергалась
    mousePosition = m_event->pos();
}
 
void MainGLWidget::keyPressEvent(QKeyEvent *event)
{
    // Закрыть окно при нажатии клавиши Escape
    if (event->key() == Qt::Key_Escape)
        exit(0);
    if ((event->key() == 1067) or (event->key() == Qt::Key_S))
        if (angleSpeed)
            angleSpeed = 0;
        else
            angleSpeed = 1;
}
 
void MainGLWidget::wheelEvent(QWheelEvent *event)
{
    k += event->delta()/10000.;
    if (k>0.99)
        k=1.0;
    if (k<0.001)
        k=0.001;
    update();
}
 
void MainGLWidget::closeEvent(QCloseEvent *event)
{
    exit(0);
}
 
void MainGLWidget::glEarth()
{    
    static const float vertices[6*4][3] =
                    {{ CUBE_GRAN,  CUBE_GRAN,  CUBE_GRAN}, { CUBE_GRAN,  CUBE_GRAN, -CUBE_GRAN}, { -CUBE_GRAN, CUBE_GRAN,  -CUBE_GRAN},{ -CUBE_GRAN,  CUBE_GRAN,  CUBE_GRAN},
                     { CUBE_GRAN,  -CUBE_GRAN,  CUBE_GRAN}, { CUBE_GRAN,  -CUBE_GRAN, -CUBE_GRAN}, { -CUBE_GRAN, -CUBE_GRAN,  -CUBE_GRAN}, { -CUBE_GRAN,  -CUBE_GRAN,  CUBE_GRAN},
                     { CUBE_GRAN,  CUBE_GRAN,  CUBE_GRAN}, { CUBE_GRAN,  CUBE_GRAN, -CUBE_GRAN}, { CUBE_GRAN,  -CUBE_GRAN, -CUBE_GRAN}, { CUBE_GRAN,  -CUBE_GRAN,  CUBE_GRAN},
                     { CUBE_GRAN,  CUBE_GRAN, -CUBE_GRAN}, { -CUBE_GRAN, CUBE_GRAN,  -CUBE_GRAN}, { -CUBE_GRAN, -CUBE_GRAN,  -CUBE_GRAN}, { CUBE_GRAN,  -CUBE_GRAN, -CUBE_GRAN},
                     { -CUBE_GRAN, CUBE_GRAN,  -CUBE_GRAN}, { -CUBE_GRAN,  CUBE_GRAN,  CUBE_GRAN}, { -CUBE_GRAN,  -CUBE_GRAN,  CUBE_GRAN},  { -CUBE_GRAN, -CUBE_GRAN,  -CUBE_GRAN},
                    { -CUBE_GRAN,  CUBE_GRAN,  CUBE_GRAN}, { CUBE_GRAN,  CUBE_GRAN,  CUBE_GRAN}, { CUBE_GRAN,  -CUBE_GRAN,  CUBE_GRAN}, { -CUBE_GRAN,  -CUBE_GRAN,  CUBE_GRAN},
                     }; //1 кубик из платформы, на которой все держится
 
    static const float normals[6*4][3] =
    {{0.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 1.0, 0.0},
     {0.0, -1.0, 0.0},{0.0, -1.0, 0.0},{0.0, -1.0, 0.0},{0.0, -1.0, 0.0},
     {1.0, 0.0, 0.0},{1.0, 0.0, 0.0},{1.0, 0.0, 0.0},{1.0, 0.0, 0.0},
     {0.0, 0.0, -1.0},{0.0, 0.0, -1.0},{0.0, 0.0, -1.0},{0.0, 0.0, -1.0},
     {-1.0, 0.0, 0.0},{-1.0, 0.0, 0.0},{-1.0, 0.0, 0.0},{-1.0, 0.0, 0.0},
     {0.0, 0.0, 1.0},{0.0, 0.0, 1.0},{0.0, 0.0, 1.0},{0.0, 0.0, 1.0},
    }; //нормали для граней кубика, чтобы определить освещение
    float tex[6*4][2]{
        {0.25, 0.3333333}, {0.5, 0.3333333}, {0.5, 0.6666666}, {0.25, 0.6666666},
        {0.75, 0.3333333}, {1.0, 0.3333333}, {1.0, 0.6666666}, {0.75, 0.6666666},
        {0.5, 0.6666666},  {0.5, 0.3333333}, {0.75, 0.3333333}, {0.75, 0.6666666},
        {0.25, 0.3333333}, {0.25, 0.6666666}, {0.0, 0.6666666},  {0.0, 0.3333333},
        {0.25, 0.6666666}, {0.5, 0.6666666}, {0.5, 1.0}, {0.25, 1.0},
        {0.5, 0.3333333}, {0.25, 0.3333333}, {0.25, 0.0}, {0.5, 0.0},
    }; //текстурные координаты
    shader_program.bind(); //включение шейдера
    upLight(); //задаем свет
    glBindTexture(GL_TEXTURE_2D, texs[2]); //выбираем текстуру земли
    shader_program.setAttributeArray(vertexLocation, (float*)vertices, 3); //передача массива вершин в шейдер
    shader_program.setAttributeArray(normLoc, (float*)normals, 3); //передача массива нормалей в шейдер
    shader_program.setAttributeArray(texLoc, (float*)tex, 2); //передача текстурных координат в шейдер
 
    shader_program.setUniformValue(defAlways, false); //включить проверку на выделение граней кубика
 
    shader_program.enableAttributeArray(vertexLocation); //включить масив вершин, переданный в шейдер
    shader_program.enableAttributeArray(normLoc); //включить масив нормалей, переданный в шейдер
    shader_program.enableAttributeArray(texLoc); //включить текстурные координаты, переданный в шейдер
 
    shader_program.setUniformValue(colorLocation, QColor(162, 101, 62)); //передать свет земли в шейдер
   for (int k=0; k<EARTH_SIZE-1; ++k) //идем по уровням земли
   {
    for (int i=0; i<EARTH_SIZE-k; ++i) //ближе/дальше
    {
        for (int j=0; j<EARTH_SIZE-k; ++j) //вправо/влево
        {
            QMatrix4x4 m_xyz;
            m_xyz.translate((EARTH_SIZE-k-1) - j*2, -k*2, (EARTH_SIZE-k-1) - i*2); //поставить кубик на нужное место
            //m_xyz.rotate(90*(k+i+j%5), 0, 1, 0);
            //передача значений переменных в шейдер
            //matrixLocation - айдишник переменной внутри шейдера,
            //projectMatrix - матрица проектирования,
            //modelViewMatrix - матрица для положения сцены,
            //m_xyz - матрица для положения конкретного кубика
            shader_program.setUniformValue(matrixLocation, projectMatrix*modelViewMatrix*m_xyz);
            shader_program.setUniformValue(normMatrLoc, m_xyz); //передать матрицу нормалей в шейдер
            glDrawArrays(GL_QUADS,0 ,6*4); //отрисовка всего переданного
        }
    }
   }
 
    shader_program.disableAttributeArray(vertexLocation); //выключение массива вершин
 
    shader_program.release(); //отрисовка всего переданного
}
 
void MainGLWidget::glHome()
{
    float verUp[2*4][3]={
        {0.0,  4.0,  2.0},{0.0,  4.0,  -2.0},{-2.0,  2.0,  -2.0},{-2.0,  2.0,  2.0},
        {0.0,  4.0,  2.0},{0.0,  4.0,  -2.0},{2.0,  2.0,  -2.0},{2.0,  2.0,  2.0},
    }; //задаем вершины для крыши дома
    float normUp[2*4][3]={
        {-0.5,  0.5,  0.0},{-0.5,  0.5,  0.0},{-0.5,  0.5,  0.0},{-0.5,  0.5,  0.0},
        {0.5,  0.5,  0.0},{0.5,  0.5,  0.0},{0.5,  0.5,  0.0},{0.5,  0.5,  0.0},
    }; //задаем нормали для крыши дома
    float texUp[][2]{
         {0.0, 0.0},{4.0, 0.0},{4.0, 1.0},{0.0, 1.0},
         {0.0, 0.0},{4.0, 0.0},{4.0, 1.0},{0.0, 1.0},
 
    }; //задаем текстуры для крыши дома
 
    //приведение координат к интервалу [-1, 1]
    for (int i = 0; i < 2*4; ++i)
    {
        for (int j = 0; j < 3; ++j)
        {
            verUp[i][j] = verUp[i][j]/4;
        }
    }
 
    float verRoof[2*4][3]{
        {-2.0,  2.0,  2.0},{0.0,  4.0,  2.0},{2.0,  2.0,  2.0},
        {-2.0,  2.0,  -2.0},{0.0,  4.0,  -2.0},{2.0,  2.0,  -2.0},
    }; //задаем вершины для треугольников под крышей дома
    float normRoof[2*4][3]{
        {0.0,  0.0,  1.0},{0.0,  0.0,  1.0},{0.0,  0.0,  1.0},
        {0.0,  0.0,  -1.0},{0.0,  0.0,  -1.0},{0.0,  0.0,  -1.0},
    }; //задаем нормали для треугольников под крышей дома
    float texRoof[][2]{
         {0.3, 0.0},{0.5, 1.0},{0.7, 0.0},
         {0.3, 0.0},{0.5, 1.0},{0.7, 0.0},
 
    }; //задаем текстуры для треугольников под крышей дома
 
    //приведение координат к интервалу [-1, 1]
    for (int i = 0; i < 2*4; ++i)
    {
        for (int j = 0; j < 3; ++j)
        {
            verRoof[i][j] = verRoof[i][j]/4;
        }
    }
 
    float verWall[][3] = {
        {-2.0,  0.0,  2.0}, {-0.3,  0.0,  2.0}, {-0.3,  2.0,  2.0}, {-2.0,  2.0,  2.0},
        {-2.0,  0.0,  2.0}, {-2.0,  0.0,  -2.0}, {-2.0,  2.0,  -2.0}, {-2.0,  2.0,  2.0},
        {-2.0,  2.0,  -2.0}, {2.0,  2.0,  -2.0}, {2.0,  0.0,  -2.0}, {-2.0,  0.0,  -2.0},
        {2.0,  0.0,  -2.0}, {2.0,  2.0,  -2.0}, {2.0,  2.0,  2.0}, {2.0,  0.0,  2.0},
        {0.3,  0.0,  2.0},{2.0,  0.0,  2.0},{2.0,  2.0,  2.0},{0.3,  2.0,  2.0},
 
    }; //задаем вершины для стен дома
 
    float normWall[][3] = {
        {0.0,  0.0,  1.0},{0.0,  0.0,  1.0},{0.0,  0.0,  1.0},{0.0,  0.0,  1.0},
        {-1.0,  0.0,  0.0},{-1.0,  0.0,  0.0},{-1.0,  0.0,  0.0},{-1.0,  0.0,  0.0},
        {0.0,  0.0,  -1.0},{0.0,  0.0,  -1.0},{0.0,  0.0,  -1.0},{0.0,  0.0,  -1.0},
        {1.0,  0.0,  0.0},{1.0,  0.0,  0.0},{1.0,  0.0,  0.0},{1.0,  0.0,  0.0},
        {0.0,  0.0,  1.0},{0.0,  0.0,  1.0},{0.0,  0.0,  1.0},{0.0,  0.0,  1.0},
    }; //задаем нормали для стен дома
 
    float texWall[][2]{
        {0.0, 0.0},{1.0, 0.0},{1.0, 1.0},{0.0, 1.0},
        {0.0, 0.0},{1.0, 0.0},{1.0, 1.0},{0.0, 1.0},
        {0.0, 0.0},{1.0, 0.0},{1.0, 1.0},{0.0, 1.0},
        {0.0, 1.0},{0.0, 0.0},{1.0, 0.0},{1.0, 1.0},
        {0.0, 0.0},{1.0, 0.0},{1.0, 1.0},{0.0, 1.0},
    }; //задаем текстуры для стен дома
 
    //приведение координат к интервалу [-1, 1]
    for (int i = 0; i < 5*4; ++i)
    {
        for (int j = 0; j < 3; ++j)
        {
            verWall[i][j] = verWall[i][j]/2;
        }
    }
 
    shader_program.bind(); //активация шейдера
 
    upLight(); //подключение света
 
    shader_program.setAttributeArray(vertexLocation, (float*)verWall, 3); //передача массива вершин в шейдер
    shader_program.setAttributeArray(normLoc, (float*)normWall, 3); //передача массива нормалей в шейдер
    shader_program.setAttributeArray(texLoc, (float*)texWall, 2); //передача текстурных координат в шейдер
 
    shader_program.setUniformValue(defAlways, true); //включаем дефолтный цвет
 
    shader_program.enableAttributeArray(vertexLocation); //включить массив вершин, переданный в шейдер
    shader_program.enableAttributeArray(normLoc); //включить массив нормалей, переданный в шейдер
    shader_program.enableAttributeArray(texLoc); //включить текстурные координаты, переданный в шейдер
 
    shader_program.setUniformValue(colorLocation, QColor(162, 101, 62)); //включаем цвет
 
    QMatrix4x4 r_t;
    r_t.setToIdentity(); //идентифицируем единичной матрицей
    r_t.translate(-EARTH_SIZE/2.,0,-EARTH_SIZE/2.); //перемещает дом в левый дальний угол
    QMatrix4x4 sc;
    sc.scale(2, 2, 2); //увеличивает координаты после их уменьшения до интервала [-1, 1]
 
    //передача значений переменных в шейдер
    //matrixLocation - айдишник переменной внутри шейдера,
    //projectMatrix - матрица проектирования,
    //modelViewMatrix - матрица для положения сцены
    //r_t - положение дома
    //sc - матрица увеличенных координаты после их уменьшения до интервала [-1, 1]
    shader_program.setUniformValue(matrixLocation, projectMatrix*modelViewMatrix*r_t*sc);
    shader_program.setUniformValue(normMatrLoc, r_t); //передать матрицу нормалей и матрицу для их изменения при повороте
    glBindTexture(GL_TEXTURE_2D, texs[1]); //включаем текстуру для стен дома
    glDrawArrays(GL_QUADS,0 ,5*4); //отрисовка
 
    shader_program.setAttributeArray(vertexLocation, (float*)verRoof, 3); //передача массива вершин в шейдер
    shader_program.setAttributeArray(normLoc, (float*)normRoof, 3); //передача массива нормалей в шейдер
    shader_program.setAttributeArray(texLoc, (float*)texRoof, 2); //передача текстурных координат в шейдер
 
    shader_program.enableAttributeArray(vertexLocation); //включить массив вершин, переданный в шейдер
    shader_program.enableAttributeArray(normLoc); //включить массив нормалей, переданный в шейдер
    shader_program.enableAttributeArray(texLoc); //включить текстурные координаты, переданный в шейдер
 
    sc.scale(2, 2, 2); //увеличивает координаты после их уменьшения до интервала [-1, 1]
 
    //передача значений переменных в шейдер
    //matrixLocation - айдишник переменной внутри шейдера,
    //projectMatrix - матрица проектирования,
    //modelViewMatrix - матрица для положения сцены
    //r_t - положение дома
    //sc - матрица увеличенных координаты после их уменьшения до интервала [-1, 1]
    shader_program.setUniformValue(matrixLocation, projectMatrix*modelViewMatrix*r_t*sc);
    glDrawArrays(GL_TRIANGLES,0 ,2*3); //отрисовка
 
    glBindTexture(GL_TEXTURE_2D, texs[0]); //включаем текстуру для треугольников под крышей дома
 
    shader_program.setAttributeArray(vertexLocation, (float*)verUp, 3); //передача массива вершин в шейдер
    shader_program.setAttributeArray(normLoc, (float*)normUp, 3); //передача массива нормалей в шейдер
    shader_program.setAttributeArray(texLoc, (float*)texUp, 2); //передача текстурных координат в шейдер
 
    shader_program.enableAttributeArray(vertexLocation); //включить массив вершин, переданный в шейдер
    shader_program.enableAttributeArray(normLoc); //включить массив нормалей, переданный в шейдер
    shader_program.enableAttributeArray(texLoc); //включить текстурные координаты, переданный в шейдер
 
 
    glDrawArrays(GL_QUADS,0 ,2*4); //отрисовка
 
    shader_program.disableAttributeArray(vertexLocation); //выключение массива вершин
 
    shader_program.release(); //отрисовка всего, что передали в шейдер
}
 
void MainGLWidget::glSun()
{
    shader_program.bind(); //активация шейдера
    QMatrix4x4 ballMatr; //матрица для перемещения
    ballMatr.setToIdentity(); //идентифицировать матрицу еденицами
    ballMatr.rotate(sunAngle, 2, 0.5, 0); //поворот
    ballMatr.translate(-EARTH_SIZE/2.,EARTH_SIZE*2,0); //перенос на нужную позицию
 
    //передача значений переменных в шейдер
    //defCLoc - айдишник переменной в шейдер
    shader_program.setUniformValue(defCLoc, true);
    shader_program.setUniformValue(defAlways, true);
 
 
    //matrixLocation - айдишник переменной внутри шейдера,
    //projectMatrix - матрица проектирования,
    //modelViewMatrix - матрица для положения сцены
    //ballMatr - для расположения солнца
    shader_program.setUniformValue(matrixLocation, projectMatrix*modelViewMatrix*ballMatr);
    shader_program.setUniformValue(colorLocation, QColor(255, 207, 72)); //передача цвета в шейдер
 
    GLUquadricObj *ball = gluNewQuadric();  //объект, в котором мы рисуем луну
 
    ballMatr.translate(EARTH_SIZE, -EARTH_SIZE*4,0); //координаты, на которые нужно перенести луну
    //matrixLocation - айдишник переменной внутри шейдера,
    //projectMatrix - матрица проектирования,
    //modelViewMatrix - матрица для положения сцены
    //ballMatr - для расположения луны
    shader_program.setUniformValue(matrixLocation, projectMatrix*modelViewMatrix*ballMatr);
    shader_program.setUniformValue(colorLocation, QColor(189, 208, 228)); //передача цвета шейдер
    gluSphere(ball, CUBE_GRAN*2., 64, 64); //отрисовка луны
 
    gluDeleteQuadric(ball); //удаляем объект, в котором рисовали
    shader_program.setUniformValue(defCLoc, false); //передаем значения в шейдер и изменяем true на false
    shader_program.release(); //отрисовка всего переданного в шейдер
}
 
void MainGLWidget::glTrees()
{
    shader_program.bind(); //включить шейдер
 
    shader_program.setUniformValue(defAlways, true); //передача значений переменных в шейдер
    GLUquadricObj *cylinder = gluNewQuadric(); //создаем объект, в котором будем рисовать
    QMatrix4x4 r_90;
    r_90.rotate(-90, 1, 0 ,0); //развернуть цилиндры в вертикальное положение
 
    for(auto tree:trees)
    {
        shader_program.setUniformValue(colorLocation, QColor(255, 136, 0)); //передача цвета в шейдер
        QMatrix4x4 position_m;
        position_m.translate(tree.second.x(),0,  tree.second.y()); //сдвинуть дерево на позицию, заданную в массиву
        //передача значений переменных в шейдер
        //matrixLocation - айдишник переменной внутри шейдера,
        //projectMatrix - матрица проектирования,
        //modelViewMatrix - матрица для положения сцены
        //position_m - сдвинуть на место, в котором должно стоять дерево
        //r_90 - развернуть вертикально
        shader_program.setUniformValue(matrixLocation, projectMatrix*modelViewMatrix*position_m*r_90);
 
        //normMatrLoc - матрица нормалей
        //position_m - сдвинуть на место, в котором должно стоять дерево
        //r_90 - развернуть вертикально
        shader_program.setUniformValue(normMatrLoc, position_m*r_90);
        //отрисовка цилиндра(ствола)
        gluCylinder(cylinder, 0.2f, 0.2f, tree.first, 64, 64);
 
        shader_program.setUniformValue(colorLocation, QColor(0, 255, 0)); //передача цвета в шейдер
        for (float i = 1.5; i<=tree.first;i+=0.5)
        {
            QMatrix4x4 h_m;
            h_m.translate(tree.second.x(), i, tree.second.y()); //сдвинуть конус на нужную позицию
 
            //передача значений переменных в шейдер
            //matrixLocation - айдишник переменной внутри шейдера,
            //projectMatrix - матрица проектирования,
            //modelViewMatrix - матрица для положения сцены
            //h_m - сдвинуть на место, в котором должно стоять дерево
            //r_90 - развирнуть вертикально
            shader_program.setUniformValue(matrixLocation, projectMatrix*modelViewMatrix*h_m*r_90);
            gluCylinder(cylinder, 0.5+0.3f*(tree.first-i), 0.0f, 0.5f, 64, 64); //отрисовать конус(иголочки)
        }
    }
    gluDeleteQuadric(cylinder); //удаляем объект, при помощи которого рисовали
 
    shader_program.release(); //отрисовка всего, переданного в шейдер
}
 
void MainGLWidget::glCloud()
{
    shader_program.bind(); //включить обработку шейдером
    upLight(); //включить освещение
    QMatrix4x4 ballMatr; //позиция сферы в облаке
    shader_program.setUniformValue(colorLocation, QColor(30, 144, 255)); //передать цвет облака в шейдер
    GLUquadricObj *ball = gluNewQuadric(); //объект для отрисовки сферы
    shader_program.setUniformValue(defAlways, true); //цвет по умолчанию для сфер
    QMatrix4x4 c_m; //позиция всего облака
    c_m.setToIdentity(); //сделать матрицу единичной
    c_m.translate(cloudP.x(), 0, cloudP.y()); //перемещаем облако на нужную позицию
 
    float z = 2;
    for (int i=0;i<10;++i) //отрисовка ближней части облака
    {
        float x = -z*z+4; //парабола, чтобы облако было овальным, х - вправо/влево, z - ближе/дальше
        ballMatr.setToIdentity(); //сделать матрицу единичной
        ballMatr.translate(x,EARTH_SIZE,z); //переместить облако на нужную позицию
        shader_program.setUniformValue(matrixLocation, projectMatrix*modelViewMatrix*c_m*ballMatr); //передать матрицу преобразований в шейдер
        shader_program.setUniformValue(normMatrLoc, c_m*ballMatr); //матрица преобразования нормалей
        gluSphere(ball, CUBE_GRAN+0.25*(rand()%4), 64, 64); //отрисовка сферы, при каждой отрисовки грань куба будет от 1 до 1.75(для вида перемещения)
        z-=0.45; //шаг по параболе
    }
    z = -2;
    for (int i=0;i<10;++i) //отрисовка дальней части облака
    {
        float x = z*z-4; //парабола, чтобы облако было овальным, х - вправо/влево, z - ближе/дальше
        ballMatr.setToIdentity(); //сделать матрицу единичной
        ballMatr.translate(x,EARTH_SIZE,z); //переместить облако на нужную позицию
        shader_program.setUniformValue(matrixLocation, projectMatrix*modelViewMatrix*c_m*ballMatr); //передать матрицу преобразований в шейдер
        shader_program.setUniformValue(normMatrLoc, c_m*ballMatr); //матрица преобразования нормалей
        gluSphere(ball, CUBE_GRAN+0.25*(rand()%4), 64, 64); //отрисовка сферы, при каждой отрисовки грань куба будет от 1 до 1.75(для вида перемещения)
        z+=0.45; //шаг по параболе
    }
 
    for (int i=-2;i<3;++i) //верхняя часть облака по х(ближе/дальше)
    {
        for (int j=-1;j<2;++j) //верхняя часть облака по z(левее/правее)
        {
            if(cloudE[i+j+3]) //если cloudE[i] = 1, то нарисовать сферу из облака, иначе нет
            {
                ballMatr.setToIdentity(); //сделать матрицу единичной
                ballMatr.translate(i,EARTH_SIZE+j,0); //переместить облако на нужную позицию
                shader_program.setUniformValue(matrixLocation, projectMatrix*modelViewMatrix*c_m*ballMatr); //передать матрицу преобразований в шейдер
                shader_program.setUniformValue(normMatrLoc, c_m*ballMatr); //матрица преобразования нормалей
                gluSphere(ball, CUBE_GRAN+0.25*(rand()%4), 64, 64); //отрисовка сферы, при каждой отрисовки грань куба будет от 1 до 1.75(для вида перемещения)
            }
        }
    }
 
    gluDeleteQuadric(ball); //удалить объект для отрисовки
 
    shader_program.release(); //вызывает отрисовку шейдеров
}
 
void MainGLWidget::glDrop()
{
    for (int i=0;i<5; ++i) //на каждом шаге добавляется по 5 капелек
    {
        dropVector.push_back({cloudP.x()+1*(rand()%5-2), EARTH_SIZE, cloudP.y()+1*(rand()%5-2)}); //внутри облака капельки разбросаны рандомно
    }
 
    shader_program.bind(); //включить шейдер
    shader_program.setUniformValue(defAlways, true); //передать параметры в шейдерер, чтобы грани не закрашивались
    QMatrix4x4 dropMatr;
    QVector<QVector3D> newVec;
 
    shader_program.setUniformValue(colorLocation, QColor(0, 149,182)); //передать цвет в шейдер
    GLUquadricObj *ball = gluNewQuadric(); //объект, в котором рисуем
 
    for (auto &drop: dropVector)
    {
 
        dropMatr.setToIdentity(); //идентифицировать матрицу единицами
        dropMatr.translate(drop.x(), drop.y(), drop.z()); //переместить в нужное положение
        //передача значений переменных в шейдер
        //matrixLocation - айдишник переменной внутри шейдера,
        //projectMatrix - матрица проектирования,
        //modelViewMatrix - матрица для положения сцены
        //dropMatr - матрица капель
        shader_program.setUniformValue(matrixLocation, projectMatrix*modelViewMatrix*dropMatr);
        gluSphere(ball, 0.15, 64, 64); //отрисовка сфер (капель)
        QVector3D v;
 
        drop.setY(drop.y()-1); //чтобы по координате y сметится ниже(капелька падает)
        if (drop.y()>0.) //если еще не достигнута земля
            newVec.push_back(drop); //то записываем капельки, которые не достигли земли, в новый вектор
    }
    dropVector = newVec;
    gluDeleteQuadric(ball); //удалить объект для отрисовки
 
    shader_program.release(); //отрисовать все, что передали в шейдер
}
 
void MainGLWidget::stepCloud()
{
    if(fabs(cloudP.x()) > 10.) //чтобы облако не вылезало за границы земли
        cloudS.setX(-cloudS.x()); //если координата больше, чем нужно, то поменять направление на противоположное
    if(fabs(cloudP.y()) > 10.) //чтобы облако не вылезало за границы земли
        cloudS.setY(-cloudS.y()); //если координата больше, чем нужно, то поменять направление на противоположное
    cloudP.setX(cloudS.x()+cloudP.x()); //изменение координат облака
    cloudP.setY(cloudS.y()+cloudP.y());
}
 
void MainGLWidget::upLight()
{
    QMatrix4x4 ballMatr;
    ballMatr.setToIdentity(); //идентифицировать матрицу единицами
    ballMatr.rotate(sunAngle, 1, 0, 0); //точечный источник света(солнце)
    ballMatr.translate(0,EARTH_SIZE*2,0); //вынести из центра сцена на удаление
    QVector4D vec(0.0, 0.0, -3.0, 1); //позиция источника света
    vec = ballMatr*vec; //перенос позиции источника света
    shader_program.setUniformValue(lightPos, vec); //передать в шейдер позицию света
}
 
void MainGLWidget::run() //основной цикл
{
    using namespace std::chrono;
    high_resolution_clock::time_point t1, t2;
    t1 = high_resolution_clock::now();
    duration<double, std::milli> time_span; //переменная, чтобы получить разность времени
    while(1)
    {
        t2 = high_resolution_clock::now();
        time_span = t2 - t1;
        while(time_span.count()<100)
        {
            QCoreApplication::processEvents(); //прокручивает очередь событий
            t2 = high_resolution_clock::now();
            time_span = t2 - t1;
        }
        QCoreApplication::processEvents();
        stepCloud(); //движение облака
        sunAngle += angleSpeed*2; //угол солцне
        updateGL(); //перерисовка
        t1 = t2; //следующий кадр
    }
}
 
Содержание fragmentShader.fsh
uniform vec4 color;
uniform bool defAlways;
uniform vec4 lightPos;
uniform bool defC;
 
varying vec4 fragPos;
varying vec4 fnormal;
varying vec2 fragTex;
 
uniform sampler2D Tex;
void main(void)
{
    float ambientStrength = 0.1;
 
    float specularStrength = 0.1;
    vec3 lightColor = vec3(0.4, 0.3, 0.2);
    vec4 ambient = vec4(ambientStrength * lightColor,1);
    vec4 lightDir = normalize(lightPos - fragPos);
    float power = max(dot(fnormal, lightDir), 0.0);
    vec4 diffuse = vec4(power * lightColor, 1);
 
    vec4 texColor = texture2D(Tex, fragTex);
    vec4 sumLight = ambient+diffuse;
 
    gl_FragColor = color*sumLight*texColor; // Цвет по умолчанию
    if (fragPos.y == 1.0)
        gl_FragColor = vec4(0.247, 0.6078, 0.043137, 1)*sumLight*texColor;
    if (abs(fragPos.y) > 0.95)
    	if (abs(fragPos.x) > 0.95)
           gl_FragColor = vec4(0.0, 0.0, 0.0, 1)*sumLight*texColor;
 
    if (abs(fragPos.y) > 0.95)
    	if (abs(fragPos.z) > 0.95)
           gl_FragColor = vec4(0.0, 0.0, 0.0, 1)*sumLight*texColor;
 
    if (abs(fragPos.z) > 0.95)
    	if (abs(fragPos.x) > 0.95)
           gl_FragColor = vec4(0.0, 0.0, 0.0, 1)*sumLight*texColor;
 
    if (defAlways)
        gl_FragColor = color*sumLight*texColor; // Цвет по умолчанию
    if (defC)
        gl_FragColor = color*texColor;
 
}
 
Содержание vertexShader.vsh
attribute vec4 vertex;
attribute vec4 normal;
attribute vec2 texture;
 
uniform mat4 matrix;
uniform mat4 normalMatrix;
 
varying vec4 fragPos;
varying vec4 fnormal;
varying vec2 fragTex;
void main(void)
{
   gl_Position = matrix * vertex; //итоговая позиция точки
   fragPos = vertex;
   fnormal = normalMatrix*normal;
   fragTex = texture;
}
 
Содержание main.cpp
#include <QApplication>
#include "mainglwidget.h"
#include "mainwindow.h"
#include <time.h>
 
int main(int argc, char *argv[])
{
    srand(time(nullptr));
    QApplication a(argc, argv);
    MainGLWidget w(nullptr);
    w.show();
    w.run();
    return a.exec();
}