Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: JAkutenshi от Декабрь 14, 2014, 13:13



Название: Шейдеры. Присоединение и применение.
Отправлено: JAkutenshi от Декабрь 14, 2014, 13:13
Доброго времени суток.

Материала много на тему шейдеров и их подключения, но либо не работает ибо пример старый, либо в упор не могу найти ответа на вопрос (смотрел пример Cube и где написано присоединение и компиляция шейдера - никак не пойму ТТ). Впрочем, был найден один вполне рабочий пример, но, хм, шейдер-то там не работает, хотя. кажется, компилируется. Итак:

GLWidget.h
Код:
#ifndef GLWIDGET_H
#define GLWIDGET_H

#include <QGLWidget>
#include <QGLShaderProgram>

class GLWidget : public QGLWidget
{
    Q_OBJECT

    float cameraX;
    float cameraY;
    float cameraZ;

    float alpha;
    float theta;

    float pressX;
    float pressY;

    float cameraDistance;

    QGLShaderProgram *shaderProgram;
public:
    explicit GLWidget(QWidget *parent = 0);

    void initializeGL();
    void resizeGL(int w, int h);
    void paintGL();

    void mouseMoveEvent(QMouseEvent *event);
    void mousePressEvent(QMouseEvent *event);
    void wheelEvent(QWheelEvent *event);

    void initShaders();
signals:

public slots:

};

#endif // GLWIDGET_H


GLWidget.ccp
Код:
#include "glwidget.h"
#include <GL/glu.h>
#include <QWheelEvent>
#include <QMouseEvent>
#include <QDebug>
#include <QFileInfo>
#include <qmath.h>
#include "teapot.h"
#include <QOpenGLVertexArrayObject>

GLWidget::GLWidget(QWidget *parent) :
    QGLWidget(parent)
{
    shaderProgram = new QGLShaderProgram( this );

    cameraDistance = 10;
    cameraX = 0;
    cameraY = 0;
    cameraZ = cameraDistance;

    alpha = M_PI / 6;
    theta = M_PI / 6;
}

void GLWidget::initializeGL() {
    glClearColor(0, 0, 0, 1);
    initShaders();
}

void GLWidget::resizeGL(int w, int h) {
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-w/2, w/2, -h/2, h/2, -w, w);
    glViewport(0, 0, w, h);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void GLWidget::paintGL() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(90, 1,
                   0.01,
                   height());
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    //glEnable(GL_CULL_FACE);
    glClearDepth(1.0);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);


    float x = cameraDistance * cos(alpha) * sin(theta);
    float y = cameraDistance * sin(alpha);
    float z = cameraDistance * cos(alpha) * cos(theta);
    gluLookAt(x, y, z,
              0, 0, 0,
              0, 1, 0);

    /*GLUquadricObj *quadric = gluNewQuadric();
    glColor4ub (176, 50, 153, 115);
    gluQuadricDrawStyle(quadric, (GLenum)GLU_SMOOTH);
    gluSphere(quadric, 1, 40, 40);
    glTranslatef(0, -1, 0);*/
    drawingTeapot();


    //рисуем статичные оси координат
    glBegin(GL_LINES);
      glColor3ub(255, 255, 255);
      glVertex3f(-300, 0, 0);
      glVertex3f(300, 0, 0);
      glVertex3f(0, -300, 0);
      glVertex3f(0, 300, 0);
      glVertex3f(0, 0, -300);
      glVertex3f(0, 0, 300);
    glEnd();
    //подписи к ним
    renderText(270, 0, 0, "X");
    renderText(0, 270, 0, "Y");
    renderText(0, 0, 270, "Z");
    //стол
    glBegin(GL_TRIANGLE_STRIP);
        glColor3ub(167, 58, 13);
        glVertex3f(10, 0, 10);
        glVertex3f(10, 0, -10);
        glVertex3f(-10, 0, 10);
        glVertex3f(-10, 0, -10);
    glEnd();


    glFlush();
}



void GLWidget::wheelEvent(QWheelEvent *event) {
    int d = cameraDistance - (event->delta()) / 120;
    if (d > 1) {
        cameraDistance = d;
        updateGL();
    }
}

void GLWidget::mousePressEvent(QMouseEvent *event) {
    pressX = event->x();
    pressY = event->y();
}

void GLWidget::mouseMoveEvent(QMouseEvent *event) {
    if (pressY - event->y() > 0) {if (alpha + 0.01 < M_PI / 2) { alpha += 0.01; } }
    else if (pressY - event->y() < 0) { if ( -M_PI / 2 < alpha - 0.01) { alpha -= 0.01; }  }
    if (pressX - event->x() > 0) { theta += 0.01; }
    else if (pressX - event->x() < 0) { theta -= 0.01; }

    int x = cameraDistance * cos(alpha) * sin(theta);
    int y = cameraDistance * sin(alpha);
    int z = cameraDistance * cos(alpha) * cos(theta);

    pressX = event->x();
    pressY = event->y();
    updateGL();
}

void GLWidget::initShaders() {

    // Compile vertex shader
    shaderProgram->addShaderFromSourceFile( QGLShader::Vertex, ":/vShader.vsh" );

    // Compile fragment shader
    shaderProgram->addShaderFromSourceFile( QGLShader::Fragment, ":/fShader.fsh" );


/*
    // Compile vertex shader
    shaderProgram->addShaderFromSourceFile( QGLShader::Vertex, ":/vShader.glsl" );

    // Compile fragment shader
    shaderProgram->addShaderFromSourceFile( QGLShader::Fragment, ":/fShader.glsl" );
*/
    // Bind vertex array object
    QOpenGLVertexArrayObject *vao = new QOpenGLVertexArrayObject( this );
    vao->bind();

    // Bind shader pipeline for use
    shaderProgram->link();
    shaderProgram->bind();
}

Прошу помощи, как правильно загружать и применять шейдерные программы в Qt?
Что не так в моем коде (uniform не используется, пока что шейдер примитивный на установку цвета)?
Если есть пример как правильно написать это - можно? Я просмотрел прилично материала, но далеко не все оказалось подходящим.

Спасибо!

P.S. Хм, таки нашел где в Cube это делается. Буду разбираться, но вопрос, пожалуй, еще открыт


Название: Re: Шейдеры. Присоединение и применение.
Отправлено: JAkutenshi от Декабрь 14, 2014, 13:47
Все-таки никак. Делаю по примеру, шейдер не применяется.

Код:
#include "glwidget.h"
#include <GL/glu.h>
#include <QWheelEvent>
#include <QMouseEvent>
#include <QDebug>
#include <QFileInfo>
#include <qmath.h>
#include "teapot.h"
#include <QOpenGLVertexArrayObject>

GLWidget::GLWidget(QWidget *parent) :
    QGLWidget(parent)
{
    shaderProgram = new QGLShaderProgram( this );

    cameraDistance = 10;
    cameraX = 0;
    cameraY = 0;
    cameraZ = cameraDistance;

    alpha = M_PI / 6;
    theta = M_PI / 6;
}

void GLWidget::initializeGL() {
    glClearColor(0, 0, 0, 1);
    initShaders();
}

void GLWidget::resizeGL(int w, int h) {
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-w/2, w/2, -h/2, h/2, -w, w);
    glViewport(0, 0, w, h);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void GLWidget::paintGL() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(90, 1,
                   0.01,
                   height());
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    //glEnable(GL_CULL_FACE);
    glClearDepth(1.0);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);


    float x = cameraDistance * cos(alpha) * sin(theta);
    float y = cameraDistance * sin(alpha);
    float z = cameraDistance * cos(alpha) * cos(theta);
    gluLookAt(x, y, z,
              0, 0, 0,
              0, 1, 0);

    /*GLUquadricObj *quadric = gluNewQuadric();
    glColor4ub (176, 50, 153, 115);
    gluQuadricDrawStyle(quadric, (GLenum)GLU_SMOOTH);
    gluSphere(quadric, 1, 40, 40);
    glTranslatef(0, -1, 0);*/
    //drawingTeapot();


    //рисуем статичные оси координат
    glBegin(GL_LINES);
      //glColor3ub(255, 255, 255);
      glVertex3f(-300, 0, 0);
      glVertex3f(300, 0, 0);
      glVertex3f(0, -300, 0);
      glVertex3f(0, 300, 0);
      glVertex3f(0, 0, -300);
      glVertex3f(0, 0, 300);
    glEnd();
    //подписи к ним
    renderText(270, 0, 0, "X");
    renderText(0, 270, 0, "Y");
    renderText(0, 0, 270, "Z");
    //стол
    glBegin(GL_TRIANGLE_STRIP);
        //glColor3ub(167, 58, 13);
        glVertex3f(10, 0, 10);
        glVertex3f(10, 0, -10);
        glVertex3f(-10, 0, 10);
        glVertex3f(-10, 0, -10);
    glEnd();


    glFlush();
}



void GLWidget::wheelEvent(QWheelEvent *event) {
    int d = cameraDistance - (event->delta()) / 120;
    if (d > 1) {
        cameraDistance = d;
        updateGL();
    }
}

void GLWidget::mousePressEvent(QMouseEvent *event) {
    pressX = event->x();
    pressY = event->y();
}

void GLWidget::mouseMoveEvent(QMouseEvent *event) {
    if (pressY - event->y() > 0) {if (alpha + 0.01 < M_PI / 2) { alpha += 0.01; } }
    else if (pressY - event->y() < 0) { if ( -M_PI / 2 < alpha - 0.01) { alpha -= 0.01; }  }
    if (pressX - event->x() > 0) { theta += 0.01; }
    else if (pressX - event->x() < 0) { theta -= 0.01; }

    int x = cameraDistance * cos(alpha) * sin(theta);
    int y = cameraDistance * sin(alpha);
    int z = cameraDistance * cos(alpha) * cos(theta);

    pressX = event->x();
    pressY = event->y();
    updateGL();
}

void GLWidget::initShaders() {
/*
    // Compile vertex shader
    shaderProgram->addShaderFromSourceFile( QGLShader::Vertex, ":/vShader.vsh" );

    // Compile fragment shader
    shaderProgram->addShaderFromSourceFile( QGLShader::Fragment, ":/fShader.fsh" );



    // Compile vertex shader
    shaderProgram->addShaderFromSourceFile( QGLShader::Vertex, ":/vShader.glsl" );

    // Compile fragment shader
    shaderProgram->addShaderFromSourceFile( QGLShader::Fragment, ":/fShader.glsl" );

    // Bind vertex array object
    QOpenGLVertexArrayObject *vao = new QOpenGLVertexArrayObject( this );
    vao->bind();

    // Bind shader pipeline for use
    shaderProgram->link();
    shaderProgram->bind();
    */

    /*// Compile vertex shader
    if (!shaderProgram->addShaderFromSourceFile(QGLShader::Vertex, ":/vShader.glsl"))
        close();

    // Compile fragment shader
    if (!shaderProgram->addShaderFromSourceFile(QGLShader::Fragment, ":/fShader.glsl"))
        close();

        */

    if (!shaderProgram->addShaderFromSourceCode(QGLShader::Vertex,
                                                "void main(void)\n"
                                                "{gl_FragColor = vec4(0.4, 0.5, 0, 1);}"))
        close();

    // Compile fragment shader
    if (!shaderProgram->addShaderFromSourceCode(QGLShader::Fragment,
                                                "void main(void)\n"
                                                "{gl_Position = ftransform();}"))
        close();

    // Link shader pipeline
    if (!shaderProgram->link())
        close();

    // Bind shader pipeline for use
    if (!shaderProgram->bind())
        close();
}

Результат:
(https://pp.vk.me/c623825/v623825266/eb8f/0D2gGPtJ0OM.jpg)

Должен быть болотный цвет по-идее.
ЧЯДНТ?


Название: Re: Шейдеры. Присоединение и применение.
Отправлено: Igors от Декабрь 14, 2014, 16:06
Во всяком случае перепутали местами тексты вертексного и фрагментного шейдеров (это фрагментный отвечает за gl_FragColor). И сразу логи компиляции шейдеров в консоль чтобы не вслепую.

Ну и все эти игрища хороши с OpenGL 4 (на худой конец 3.2). А для более ранних карт - ой чижело  :'(


Название: Re: Шейдеры. Присоединение и применение.
Отправлено: JAkutenshi от Декабрь 14, 2014, 16:25
Да, на геймдеве уже поправили, стыдно за ляп - недосмотрел. Но сути не поменяло, шейдер не грузит.

Вопрос от отчаяния: есть шансы сделать тени через shadow map за день-полтора? ТТ

"Поправил, но шейдер все так же не применяется. Лог пустой, в qDebug():
getProcAddress: Unable to resolve 'glProgramParameteri'
getProcAddress: Unable to resolve 'glProgramParameteriEXT'
"" <- log();
getProcAddress: Unable to resolve 'glProgramParameteri'
getProcAddress: Unable to resolve 'glProgramParameteriEXT'
getProcAddress: Unable to resolve 'glProgramParameteri'
getProcAddress: Unable to resolve 'glProgramParameteriEXT'
getProcAddress: Unable to resolve 'glProgramParameteri'
getProcAddress: Unable to resolve 'glProgramParameteriEXT'"


Название: Re: Шейдеры. Присоединение и применение.
Отправлено: Igors от Декабрь 14, 2014, 17:35
Вопрос от отчаяния: есть шансы сделать тени через shadow map за день-полтора? ТТ
А что значит "сделать" на OpenGL? Найти пример и переписать - другого в этом царстве тупости нет. Так что все зависит от умения искать  :)

"Поправил, но шейдер все так же не применяется. Лог пустой, в qDebug():
getProcAddress: Unable to resolve 'glProgramParameteri'
getProcAddress: Unable to resolve 'glProgramParameteriEXT'
Ну так до шейдера точно дело не дойдет. Печатайте glGetString(GL_VERSION). Может там совсем не четверка


Название: Re: Шейдеры. Присоединение и применение.
Отправлено: JAkutenshi от Декабрь 14, 2014, 17:39
Ну, я нашел прилично примеров, но боюсь криворучность поломает все. Впрочем, придется как-то сделать - выбора-то нет~

Там не четверка.
3.1.0 - Build 8.15.10.2345
Шейдеры же вроде после 2-го апдейта гля появились, нет?

Компилируются они кстати нормально, пишет что ошибок нет.

Перевел на основной GPU NVidia : 4.4.0 NVIDIA 344.11


Название: Re: Шейдеры. Присоединение и применение.
Отправлено: Igors от Декабрь 15, 2014, 09:56
Там не четверка.
3.1.0 - Build 8.15.10.2345
Шейдеры же вроде после 2-го апдейта гля появились, нет?
Не знаю истории, но на старенькой карте с OpenGL 2.1 по крайней мере вертексный и фрагментный шейдеры у меня ходят. Хотя нет многих новых возможностей.

Если не ошибаюсь glPrоgramParameter требует 4 или даже чуть выше. И ftransform тоже проверьте на совместимость. В общем спецификации никто не отменял. Распечатайте QGLFormat к чему там он присосался. Ну и Qt лучше ставить "десктопный OpenGL" чтобы не упираться в ES и.т.п.

Компилируются они кстати нормально, пишет что ошибок нет.

Перевел на основной GPU NVidia : 4.4.0 NVIDIA 344.11
Не понял что "перевел"? Подсуньте ошибку в шейдере, должно вякнуть в логе


Название: Re: Шейдеры. Присоединение и применение.
Отправлено: __Heaven__ от Декабрь 15, 2014, 09:58
Код:
void GLWidget::initShaders() {
/*
    // Compile vertex shader
    shaderProgram->addShaderFromSourceFile( QGLShader::Vertex, ":/vShader.vsh" );

    // Compile fragment shader
    shaderProgram->addShaderFromSourceFile( QGLShader::Fragment, ":/fShader.fsh" );



    // Compile vertex shader
    shaderProgram->addShaderFromSourceFile( QGLShader::Vertex, ":/vShader.glsl" );

    // Compile fragment shader
    shaderProgram->addShaderFromSourceFile( QGLShader::Fragment, ":/fShader.glsl" );

    // Bind vertex array object
    QOpenGLVertexArrayObject *vao = new QOpenGLVertexArrayObject( this );
    vao->bind();

    // Bind shader pipeline for use
    shaderProgram->link();
    shaderProgram->bind();
    */

    /*// Compile vertex shader
    if (!shaderProgram->addShaderFromSourceFile(QGLShader::Vertex, ":/vShader.glsl"))
        close();

    // Compile fragment shader
    if (!shaderProgram->addShaderFromSourceFile(QGLShader::Fragment, ":/fShader.glsl"))
        close();

        */

    if (!shaderProgram->addShaderFromSourceCode(QGLShader::Vertex,
                                                "void main(void)\n"
                                                "{gl_FragColor = vec4(0.4, 0.5, 0, 1);}"))
        close();

    // Compile fragment shader
    if (!shaderProgram->addShaderFromSourceCode(QGLShader::Fragment,
                                                "void main(void)\n"
                                                "{gl_Position = ftransform();}"))
        close();

    // Link shader pipeline
    if (!shaderProgram->link())
        close();

    // Bind shader pipeline for use
    if (!shaderProgram->bind())
        close();
}
Здесь явно что-то лишнее. К программе подключается по одному шейдеру каждого типа, в вашем случае вершинный и фрагментный. Далее программа линкуется и прикручивается к контексту (bind). У вас же по 2 раза шейдер добавили, слинковали прикрутили, снова 2 раза добавили, снова слинковали и т.д.
Попробуйте в текст шейдеров добавить ещё директиву #version 130.


Название: Re: Шейдеры. Присоединение и применение.
Отправлено: __Heaven__ от Декабрь 15, 2014, 10:10
У вас нет обращений к программе из метода paint. В данный момент вы рисуете с помощью OpenGL 1.x. Шейдерная программа просто болтается в памяти.


Название: Re: Шейдеры. Присоединение и применение.
Отправлено: Igors от Декабрь 15, 2014, 10:59
У вас нет обращений к программе из метода paint. В данный момент вы рисуете с помощью OpenGL 1.x. Шейдерная программа просто болтается в памяти.
Ну тогда уже в памяти карты :) Но я не понял - а какие обращения должны быть? Установка uniform переменных - так их пока нет. И в чем разница между рисованием 1.х и выше? По-моему так и так шейдер должен работать


Название: Re: Шейдеры. Присоединение и применение.
Отправлено: __Heaven__ от Декабрь 15, 2014, 11:07
glVertex3f не задействует шейдер


Название: Re: Шейдеры. Присоединение и применение.
Отправлено: __Heaven__ от Декабрь 15, 2014, 11:09
Вот пример  (http://www.prog.org.ru/index.php?topic=27475.msg199283#msg199283)простой программы на шейдерах


Название: Re: Шейдеры. Присоединение и применение.
Отправлено: __Heaven__ от Декабрь 15, 2014, 11:19
Во всяком случае перепутали местами тексты вертексного и фрагментного шейдеров (это фрагментный отвечает за gl_FragColor). И сразу логи компиляции шейдеров в консоль чтобы не вслепую.
Ой, да. Не сразу заметил. Присоединяюсь.
Вообще, при компиляции в stderr должна была высыпаться ошибка (В QtCreator 3 вкладка "Вывод приложения").
На википедии написано, что
Цитировать
ftransform() больше не поддерживается GLSL с версии 1.40 и GLSL ES с версии 1.0. Теперь программисты должны управлять матрицами проекции и трансформации модели в соответствии со стандартом OpenGL 3.1.
ссылка (https://ru.wikipedia.org/w/index.php?title=OpenGL_Shading_Language)


Название: Re: Шейдеры. Присоединение и применение.
Отправлено: Igors от Декабрь 15, 2014, 11:35
glVertex3f не задействует шейдер
Чего это? По-моему у меня работает (кстати в том самом случае - не нашел лучшего способа вывода с фейсетными нормалями). glVertex3f - это всего лишь способ передачи данных (пусть устаревший)

Вот пример  (http://www.prog.org.ru/index.php?topic=27475.msg199283#msg199283)простой программы на шейдерах
Ага, версия 4.2 - и вот она, "простота" :) А остальные "идут лесом" (в терминах молодежи) или как?


Название: Re: Шейдеры. Присоединение и применение.
Отправлено: __Heaven__ от Декабрь 15, 2014, 12:05
glVertex3f - это всего лишь способ передачи данных (пусть устаревший)
Да, проверил - работает. Ошибался. При неиспользовании шейдерной программы рисует белым. Так что, автор, проблема в нескомпилированной программе, точнее в перепутанных типах шейдеров.
Ага, версия 4.2 - и вот она, "простота" :) А остальные "идут лесом" (в терминах молодежи) или как?
Версию можно затереть и точка будет рисоваться.


Название: Re: Шейдеры. Присоединение и применение.
Отправлено: JAkutenshi от Декабрь 15, 2014, 14:35
Так, вчера был интересный в плане внезапных проблем и бесполезный в плане написанного полезного кода. Итак, тема моя на геймдеве, с обсуждением: http://www.gamedev.ru/code/forum/?id=196175

Если в кратком содержании прошедшей серии:
Простейший шейдер на изменение цвета в некий статичный вектор цвета в нем. Все просто. Но он не применялся. Все компилируется, ошибок нет, все радостно, но шейдер не работает.
Уважаемый форумчанин с геймдева Blew_zc собрал бинарник и передал его вместе с проектом. Какого было мое удивление, когда собранная программа рисовала нужное, а собранный проект на моей машине (по факту на моем Qt5.3, против его Qt4.6) снова не применяет шейдер!
Выше описанный человек помог разобраться с причиной сей "магии":
"В общем, renderText вызывает unbind шейдера (или bind какого-то своего, сейчас влом разбираться), так что вызов shaderProgram->bind() перед отрисовкой координатных осей и плоскости помог :) "

Или как вариант убрать надписи. Такие дела.
Мораль? "на фреймворк надейся, а сам не плошай. "

Всем спасибо, особенно, еще раз, Blew_zc, надеюсь, если у кого-то будет эта проблема, найдет свой ответ здесь.


Название: Re: Шейдеры. Присоединение и применение.
Отправлено: 8Observer8 от Декабрь 15, 2014, 23:35
Возможно вам будет интересен мой пример (http://www.cyberforum.ru/opengl/thread1316232-page3.html#post6991000) с применением шейдеров