OpenGL开发学习之 --着色器之彩色三角形
一、摘要
1.着色器是使用一种叫GLSL的类C语言写成的。GLSL是为图形计算量身定制的,它包含一些针对向量和矩阵操作的有用特性。
2.和其他编程语言一样,GLSL有数据类型可以来指定变量的种类。GLSL中包含C等其它语言大部分的默认基础数据类型:int、float、double、uint和bool。GLSL也有两种容器类型,它们会在这个教程中使用很多,分别是向量(Vector)和矩阵(Matrix)
3.向量
4.虽然着色器是各自独立的小程序,但是它们都是一个整体的一部分,出于这样的原因,我们希望每个着色器都有输入和输出,这样才能进行数据交流和传递。GLSL定义了in和out关键字专门来实现这个目的。每个着色器使用这两个关键字设定输入和输出,只要一个输出变量与下一个着色器阶段的输入匹配,它就会传递下去。但在顶点和片段着色器中会有点不同。
5.顶点着色器应该接收的是一种特殊形式的输入,否则就会效率低下。顶点着色器的输入特殊在,它从顶点数据中直接接收输入。为了定义顶点数据该如何管理,我们使用location这一元数据指定输入变量,这样我们才可以在CPU上配置顶点属性,layout (location = 0)。顶点着色器需要为它的输入提供一个额外的layout标识,这样我们才能把它链接到顶点数据。
6.Uniform是一种从CPU中的应用向GPU中的着色器发送数据的方式,但uniform和顶点属性有些不同。首先,uniform是全局的(Global)。全局意味着uniform变量必须在每个着色器程序对象中都是独一无二的,而且它可以被着色器程序的任意着色器在任意阶段访问。第二,无论你把uniform值设置成什么,uniform会一直保存它们的数据,直到它们被重置或更新。
7.目录结构
二、代码
opengl.h
#ifndef OPENGL_H
#define OPENGL_H
#pragma once
#include <QOpenGLWidget>
#include <QDebug>
#include <QOpenGLFunctions_3_3_Core>
#include "shader.h"
#include <QOpenGLWidget>
namespace Ui {
class opengl;
}
class opengl : public QOpenGLWidget
{
public:
opengl();
~opengl();
GLuint a;
protected:
virtual void initializeGL();
virtual void resizeGL(int w, int h);
virtual void paintGL();
private:
Shader *ourShader;
QOpenGLFunctions_3_3_Core *core;
GLuint VBO, VAO;
};
#endif // OPENGL_H
opengl.cpp
#include "opengl.h"
#include <QtDebug>
opengl::opengl()
{
}
opengl::~opengl()
{
}
/*
*function:负责初始化
*/
void opengl::initializeGL(){
//着色器部分
core = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
ourShader = new Shader(":/shader/texshadersource.vert",":/shader/fragmentshadersource.frag");
//VAO,VBO数据部分
GLfloat vertices[] = {
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);//两个参数,第一个为需要创建的缓存数量。第二个为用于存储单一ID或多个ID的GLuint变量或数组的地址
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), (void*)0);
core->glEnableVertexAttribArray(0);
core->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3*sizeof(GLfloat)));
core->glEnableVertexAttribArray(1);
core->glBindBuffer(GL_ARRAY_BUFFER, 0);
core->glBindVertexArray(0);
core->glClearColor(0.1f, 0.5f, 0.3f, 1.0f);
}
void opengl::resizeGL(int w, int h){
core->glViewport(0, 0, w, h);
}
void opengl::paintGL(){
core->glClear(GL_COLOR_BUFFER_BIT);
ourShader->use();
core->glBindVertexArray(VAO);
core->glDrawArrays(GL_TRIANGLES, 0, 3);
}
shader.h
#include "opengl.h"
#include <QtDebug>
opengl::opengl()
{
}
opengl::~opengl()
{
}
/*
*function:负责初始化
*/
void opengl::initializeGL(){
//着色器部分
core = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
ourShader = new Shader(":/shader/texshadersource.vert",":/shader/fragmentshadersource.frag");
//VAO,VBO数据部分
GLfloat vertices[] = {
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);//两个参数,第一个为需要创建的缓存数量。第二个为用于存储单一ID或多个ID的GLuint变量或数组的地址
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), (void*)0);
core->glEnableVertexAttribArray(0);
core->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3*sizeof(GLfloat)));
core->glEnableVertexAttribArray(1);
core->glBindBuffer(GL_ARRAY_BUFFER, 0);
core->glBindVertexArray(0);
core->glClearColor(0.1f, 0.5f, 0.3f, 1.0f);
}
void opengl::resizeGL(int w, int h){
core->glViewport(0, 0, w, h);
}
void opengl::paintGL(){
core->glClear(GL_COLOR_BUFFER_BIT);
ourShader->use();
core->glBindVertexArray(VAO);
core->glDrawArrays(GL_TRIANGLES, 0, 3);
}
shader.cpp
#include "shader.h"
Shader::Shader(const QString& vertexPath, const QString& fragmentPath){
QOpenGLShader vertexShader(QOpenGLShader::Vertex);
bool success = vertexShader.compileSourceFile(vertexPath);
if(!success){
qDebug() << "ERROR::SHADER::VERTEX::COMPILATION_FAILED" << endl;
qDebug() << vertexShader.log() << endl;
}
QOpenGLShader fragmentShader(QOpenGLShader::Fragment);
success =fragmentShader.compileSourceFile(fragmentPath);
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(){
}
三、重点问题原因以及解决办法
a.可能由于工作电脑没有独显导致(后面换个有显卡的电脑后解决) -> illegal non-ASCII character编码错误
b.shader在第一行没有进行独行回车导致 -> error C0204: version directive must be first statement and may not be repeated
c.shader文件的相对路径地址和绝对路径地址要注意
其中代码学习教程以及遇到问题解决办法所参考文章的链接附在下方:
源码参考:
https://learnopengl-cn.readthedocs.io/zh/latest/01%20Getting%20started/05%20Shaders/
https://blog.youkuaiyun.com/z136411501/article/details/79879537
解决问题参考:
https://blog.youkuaiyun.com/perfer258/article/details/116697601
https://blog.youkuaiyun.com/z136411501/article/details/83306516