着色器
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QGLWidget> #include <QOpenGLShader> #include <QOpenGLShaderProgram> #include <QDebug> #include <QOpenGLFunctions> #include <QOpenGLFunctions_3_3_Core> #include <QTime> #include <QtMath> #include <QTimer> namespace Ui { class Widget; } class Triangle : public QGLWidget, protected QOpenGLFunctions { Q_OBJECT public: explicit Triangle(); ~Triangle(); protected: virtual void initializeGL(); virtual void paintGL(); virtual void resizeGL(int w, int h); private: GLuint shaderProgram; QOpenGLFunctions_3_3_Core *core; shader *ourShader; }; #endif // WIDGET_H
#include "widget.h" #include "ui_widget.h" GLuint VBO, VAO; const char *vertexShaderSource ="#version 330 core\n" "layout (location = 0) in vec3 aPos;\n" "void main()\n" "{\n" " gl_Position = vec4(aPos, 1.0);\n" "}\0"; const char *fragmentShaderSource = "#version 330 core\n" "out vec4 FragColor;\n" "uniform vec4 ourColor;\n" "void main()\n" "{\n" " FragColor = ourColor;\n" "}\n\0"; Triangle::Triangle() { } Triangle::~Triangle() { } void Triangle::initializeGL() { //着色器部分 core = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>(); if (!core) { qWarning() << "Could not obtain required OpenGL context version"; exit(1); } GLuint vertexShader = core->glCreateShader(GL_VERTEX_SHADER); core->glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr); core->glCompileShader(vertexShader); // check for shader compile errors int success; char infoLog[512]; core->glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); if (!success) { core->glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog); qDebug() << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << endl; } // fragment shader GLuint fragmentShader; fragmentShader = core->glCreateShader(GL_FRAGMENT_SHADER); core->glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr); core->glCompileShader(fragmentShader); core->glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); if (!success) { core->glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog); qDebug() << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << endl; } shaderProgram = core->glCreateProgram(); core->glAttachShader(shaderProgram, vertexShader); core->glAttachShader(shaderProgram, fragmentShader); core->glLinkProgram(shaderProgram); core->glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); if (!success) { core->glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog); qDebug() << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << endl; } core->glDeleteShader(vertexShader); core->glDeleteShader(fragmentShader); float vertices[] = { // positions // colors 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom right -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // bottom left 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // top }; core->glGenVertexArrays(1, &VAO); core->glGenBuffers(1, &VBO); core->glBindVertexArray(VAO); core->glBindBuffer(GL_ARRAY_BUFFER, VBO); core->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); core->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), nullptr); core->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), (void*)(3 * sizeof(float))); core->glEnableVertexAttribArray(0); QTimer *timer = new QTimer(this); timer->setInterval(100); connect(timer, &QTimer::timeout, this, [=](){ repaint();}); timer->start(); } void Triangle::paintGL() { core->glClearColor(0.2f, 0.3f, 0.3f, 1.0f); core->glClear(GL_COLOR_BUFFER_BIT); core->glUseProgram(shaderProgram); core->glBindVertexArray(VAO); float timeValue = QTime(0,0,0).msecsTo(QTime::currentTime())/1000.0f; float greenValue = qSin(timeValue) / 2.0f + 0.5f; qDebug()<<"greenValue"<<greenValue; int vertexColorLocation = core->glGetUniformLocation(shaderProgram, "ourColor"); core->glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f); core->glDrawArrays(GL_TRIANGLES, 0, 3); core->glUseProgram(0); } void Triangle::resizeGL(int w, int h) { core->glViewport(0, 0, w, h); }
更多属性
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QGLWidget> #include <QOpenGLShader> #include <QOpenGLShaderProgram> #include <QDebug> #include <QOpenGLFunctions> #include <QOpenGLFunctions_3_3_Core> #include <QTime> #include <QtMath> #include <QTimer> #include "shader.h" namespace Ui { class Widget; } class Triangle : public QGLWidget, protected QOpenGLFunctions { Q_OBJECT public: explicit Triangle(); ~Triangle(); protected: virtual void initializeGL(); virtual void paintGL(); virtual void resizeGL(int w, int h); private: GLuint shaderProgram; QOpenGLFunctions_3_3_Core *core; shader *m_shader; }; #endif // WIDGET_H
#include "widget.h" #include "ui_widget.h" GLuint VBO, VAO; const char *vertexShaderSource ="#version 330 core\n" "layout (location = 0) in vec3 aPos;\n" "layout (location = 1) in vec3 aColor;\n" "out vec3 ourColor;\n" "void main()\n" "{\n" " gl_Position = vec4(aPos, 1.0);\n" " ourColor = aColor;\n" "}\0"; const char *fragmentShaderSource = "#version 330 core\n" "out vec4 FragColor;\n" "in vec3 ourColor;\n" "void main()\n" "{\n" " FragColor = vec4(ourColor, 1.0f);\n" "}\n\0"; Triangle::Triangle() { } Triangle::~Triangle() { } void Triangle::initializeGL() { //着色器部分 core = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>(); if (!core) { qWarning() << "Could not obtain required OpenGL context version"; exit(1); } GLuint vertexShader = core->glCreateShader(GL_VERTEX_SHADER); core->glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr); core->glCompileShader(vertexShader); // check for shader compile errors int success; char infoLog[512]; core->glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); if (!success) { core->glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog); qDebug() << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << endl; } // fragment shader GLuint fragmentShader; fragmentShader = core->glCreateShader(GL_FRAGMENT_SHADER); core->glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr); core->glCompileShader(fragmentShader); // check for shader compile errors core->glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); if (!success) { core->glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog); qDebug() << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << endl; } // link shaders shaderProgram = core->glCreateProgram(); core->glAttachShader(shaderProgram, vertexShader); core->glAttachShader(shaderProgram, fragmentShader); core->glLinkProgram(shaderProgram); core->glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); if (!success) { core->glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog); qDebug() << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << endl; } core->glDeleteShader(vertexShader); core->glDeleteShader(fragmentShader); float vertices[] = { // positions // colors 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom right -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // bottom left 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // top }; core->glGenVertexArrays(1, &VAO); core->glGenBuffers(1, &VBO); core->glBindVertexArray(VAO); core->glBindBuffer(GL_ARRAY_BUFFER, VBO); core->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); //position attribute core->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), nullptr); core->glEnableVertexAttribArray(0); //color attribute core->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), (void*)(3 * sizeof(float))); core->glEnableVertexAttribArray(1); } void Triangle::paintGL() { core->glClearColor(0.2f, 0.3f, 0.3f, 1.0f); core->glClear(GL_COLOR_BUFFER_BIT); core->glUseProgram(shaderProgram); core->glBindVertexArray(VAO); core->glDrawArrays(GL_TRIANGLES, 0, 3); core->glUseProgram(0); } void Triangle::resizeGL(int w, int h) { core->glViewport(0, 0, w, h); }
自己的着色器
#ifndef SHADER_H #define SHADER_H #include <QObject> #include <QDebug> #include <QOpenGLShader> #include <QOpenGLShaderProgram> #include <QString> class shader : public QObject { Q_OBJECT public: shader(const QString& vertexSourcePath, const QString &fragmentSourcePath); ~shader(); QOpenGLShaderProgram shaderProgram; void use() { shaderProgram.bind(); } signals: public slots: }; #endif // SHADER_H
#include "shader.h" shader::shader(const QString &vertexSourcePath, const QString &fragmentSourcePath) { QOpenGLShader vertexShader(QOpenGLShader::Vertex); bool success = vertexShader.compileSourceFile(vertexSourcePath); if(!success){ qDebug() << "ERROR::SHADER::VERTEX::COMPILATION_FAILED" << endl; qDebug() << vertexShader.log() << endl; } QOpenGLShader fragmentShader(QOpenGLShader::Fragment); success =fragmentShader.compileSourceFile(fragmentSourcePath); if(!success){ qDebug() << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED" << endl; qDebug() << fragmentShader.log() << endl; } shaderProgram.addShader(&vertexShader); shaderProgram.addShader(&fragmentShader); success = shaderProgram.link(); if(!success){ qDebug() << "ERROR::SHADER::PROGRAM::LINKING_FAILED" << endl; qDebug() << shaderProgram.log() << endl; } } shader::~shader() { }
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QGLWidget> #include <QOpenGLShader> #include <QOpenGLShaderProgram> #include <QDebug> #include <QOpenGLFunctions> #include <QOpenGLFunctions_3_3_Core> #include <QTime> #include <QtMath> #include <QTimer> #include "shader.h" namespace Ui { class Widget; } class Triangle : public QGLWidget, protected QOpenGLFunctions { Q_OBJECT public: explicit Triangle(); ~Triangle(); protected: virtual void initializeGL(); virtual void paintGL(); virtual void resizeGL(int w, int h); private: // GLuint shaderProgram; QOpenGLFunctions_3_3_Core *core; shader *ourShader; }; #endif // WIDGET_H
#include "widget.h" #include "ui_widget.h" GLuint VBO, VAO; const char *vertexShaderSource ="#version 330 core\n" "layout (location = 0) in vec3 aPos;\n" "layout (location = 1) in vec3 aColor;\n" "out vec3 ourColor;\n" "void main()\n" "{\n" " gl_Position = vec4(aPos, 1.0);\n" " ourColor = aColor;\n" "}\0"; const char *fragmentShaderSource = "#version 330 core\n" "out vec4 FragColor;\n" "in vec3 ourColor;\n" "void main()\n" "{\n" " FragColor = vec4(ourColor, 1.0f);\n" "}\n\0"; Triangle::Triangle() { } Triangle::~Triangle() { } void Triangle::initializeGL() { //着色器部分 core = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>(); if (!core) { qWarning() << "Could not obtain required OpenGL context version"; exit(1); } ourShader = new shader(":/vertexshadersource.vert", ":/fragmentshadersource.frag"); GLuint vertexShader = core->glCreateShader(GL_VERTEX_SHADER); core->glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr); core->glCompileShader(vertexShader); // check for shader compile errors int success; char infoLog[512]; core->glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); if (!success) { core->glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog); qDebug() << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << endl; } // fragment shader GLuint fragmentShader; fragmentShader = core->glCreateShader(GL_FRAGMENT_SHADER); core->glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr); core->glCompileShader(fragmentShader); // check for shader compile errors core->glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); if (!success) { core->glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog); qDebug() << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << endl; } // link shaders // shaderProgram = core->glCreateProgram(); // core->glAttachShader(shaderProgram, vertexShader); // core->glAttachShader(shaderProgram, fragmentShader); // core->glLinkProgram(shaderProgram); // core->glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); // if (!success) { // core->glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog); // qDebug() << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << endl; // } core->glDeleteShader(vertexShader); core->glDeleteShader(fragmentShader); float vertices[] = { // positions // colors 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom right -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // bottom left 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // top }; core->glGenVertexArrays(1, &VAO); core->glGenBuffers(1, &VBO); core->glBindVertexArray(VAO); core->glBindBuffer(GL_ARRAY_BUFFER, VBO); core->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); //position attribute core->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), nullptr); core->glEnableVertexAttribArray(0); //color attribute core->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), (void*)(3 * sizeof(float))); core->glEnableVertexAttribArray(1); } void Triangle::paintGL() { core->glClearColor(0.2f, 0.3f, 0.3f, 1.0f); core->glClear(GL_COLOR_BUFFER_BIT); ourShader->use(); // core->glUseProgram(shaderProgram); core->glBindVertexArray(VAO); core->glDrawArrays(GL_TRIANGLES, 0, 3); core->glUseProgram(0); } void Triangle::resizeGL(int w, int h) { core->glViewport(0, 0, w, h); }
着色器练习
- 修改顶点着色器让三角形上下颠倒:
#version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aColor; out vec3 ourColor; void main(){ gl_Position = vec4(aPos.x, -aPos.y, aPos.z, 1.0f); ourColor = aColor; }
- 使用uniform定义一个水平偏移量,在顶点着色器中使用这个偏移量把三角形移动到屏幕右侧:
void Triangle::paintGL() { core->glClearColor(0.2f, 0.3f, 0.3f, 1.0f); core->glClear(GL_COLOR_BUFFER_BIT); ourShader->use(); ourShader->shaderProgram.setUniformValue("xOffset", 0.5f); // core->glUseProgram(shaderProgram); core->glBindVertexArray(VAO); core->glDrawArrays(GL_TRIANGLES, 0, 3); core->glUseProgram(0); } //vertexshadersource.vert #version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aColor; out vec3 ourColor; uniform float xOffset; void main(){ gl_Position = vec4(aPos.x + xOffset, -aPos.y, aPos.z, 1.0f); ourColor = aColor; }
- 使用
out
关键字把顶点位置输出到片段着色器,并将片段的颜色设置为与顶点位置相等(来看看连顶点位置值都在三角形中被插值的结果)。做完这些后,尝试回答下面的问题:为什么在三角形的左下角是黑的?:fragmentshadersource.frag #version 330 core out vec4 FragColor; //in vec3 ourColor; in vec3 ourPosition; void main(void) { FragColor = vec4(ourPosition, 1.0f); } vertexshadersource.vert #version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aColor; out vec3 ourPosition; void main(){ gl_Position = vec4(aPos, 1.0f); ourPosition = aPos; } /* Answer to the question: Do you know why the bottom-left side is black? -- -------------------------------------------------------------------- Think about this for a second: the output of our fragment's color is equal to the (interpolated) coordinate of the triangle. What is the coordinate of the bottom-left point of our triangle? This is (-0.5f, -0.5f, 0.0f). Since the xy values are negative they are clamped to a value of 0.0f. This happens all the way to the center sides of the triangle since from that point on the values will be interpolated positively again. Values of 0.0f are of course black and that explains the black side of the triangle. */ 位置做了颜色,左下角是-0.5,-0.5,0.0。然后颜色没有负的。就是0,0,0了黑色。 中间又有颜色是因为其他角不是黑的
无欲速,无见小利。欲速,则不达;见小利,则大事不成。