本文使用Qt进行操作演示。
注意:
坐标原点位于屏幕中心
坐标参数:0.0f - 1.0f
颜色参数:0.0f - 1.0f
OpenGL提供了几种用于绘制几何图形的绘制模式。下面是一些常用的绘制模式:
点(GL_POINTS):绘制单个点。
线(GL_LINES):绘制一系列相互独立的线段。
线带(GL_LINE_STRIP):绘制一系列连接在一起的线段,其中每个线段的起点都是前一个线段的终点。
线环(GL_LINE_LOOP):与线带类似,但会在最后一个点和第一个点之间绘制一条线段,形成闭合的图形。
三角形(GL_TRIANGLES):绘制一系列相互独立的三角形。
三角形带(GL_TRIANGLE_STRIP):绘制一系列连接在一起的三角形,其中每个三角形的前两个顶点是前一个三角形的后两个顶点。
三角形扇形(GL_TRIANGLE_FAN):绘制一系列共享一个公共顶点的三角形。
除了上述绘制模式,还有其他一些高级的绘制模式,如四边形、多边形等。此外,还可以使用索引缓冲对象(Index Buffer Objects,简称IBO)来指定绘制的顺序,从而实现更复杂的绘制。
绘制模式可以通过以下方式设置:
glDrawArrays(GL_TRIANGLES, 0, numVertices);
其中,第一个参数指定绘制的模式,第二个参数指定要绘制的顶点的起始位置,第三个参数指定要绘制的顶点数量。
// An highlighted block
#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H
#include
#include
#include
class MyOpenGLWidget : public QOpenGLWidget,protected QOpenGLFunctions // 可直接使用QOpenGLFunctions中的OpenGL函数
{
Q_OBJECT
public:
explicit MyOpenGLWidget (QWidget * parent = 0);
protected:
void initializeGL();
void paintGL();
void resizeGL(int width,int height);
private:
QOpenGLShaderProgram * program; // 着色器程序
};
#endif // MYOPENGLWIDGET_H
#include "myopenglwidget.h"
MyOpenGLWidget::MyOpenGLWidget(QWidget *parent)
: QOpenGLWidget(parent)
{
}
void MyOpenGLWidget::initializeGL()
{
initializeOpenGLFunctions(); //调用该函数来初始化OpenGL函数,以便在后续使用OpenGL的函数。
QSurfaceFormat format;
format.setSamples(4); // 设置采样数为4(可根据需要进行调整)
setFormat(format);
glEnable(GL_MULTISAMPLE); // 启用多重采样
//创建一个顶点着色器对象,并将其指针赋值给vShader变量。第一个参数QOpenGLShader::Vertex表示创建的是一个顶点着色器对象,第二个参数this表示将当前窗口或部件作为父对象。
QOpenGLShader *vShader = new QOpenGLShader(QOpenGLShader::Vertex, this);
//定义了一个字符串变量vsrc,用于存储顶点着色器代码。
const char* vsrc =
"attribute vec4 vPosition; \n" //定义了一个属性变量vPosition,用于接收传入的顶点坐标。
"void main(){\n" //定义了一个主函数,其功能是将传入的顶点坐标赋值给内置变量gl_Position,从而确定此顶点的屏幕位置。
" gl_Position = vPosition;\n"
"}\n";
vShader->compileSourceCode(vsrc); //将顶点着色器代码编译成可执行代码,并将结果存储在vShader对象中。如果编译失败,则会抛出异常。
//创建一个片段着色器对象,并将其指针赋值给fShader变量。第一个参数QOpenGLShader::Fragment表示创建的是一个片段着色器对象,第二个参数this表示将当前窗口或部件作为父对象。
QOpenGLShader *fShader = new QOpenGLShader(QOpenGLShader::Fragment, this);
const char* fsrc =
"void main(){\n"
" gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);\n" // 将输出的颜色设置为黄色
"}\n";
fShader->compileSourceCode(fsrc); //将片段着色器代码编译成可执行代码,并将结果存储在fShader对象中。如果编译失败,则会抛出异常。
program = new QOpenGLShaderProgram; //创建一个着色器程序对象,并将其指针赋值给program变量。
program->addShader(vShader); //将之前创建并编译好的顶点着色器对象添加到着色器程序中。
program->addShader(fShader); //将之前创建并编译好的片段着色器对象添加到着色器程序中。
program->link(); //链接着色器程序,将顶点着色器和片段着色器关联起来,并生成最终的可执行程序。
program->bind(); //绑定着色器程序,使其成为当前OpenGL上下文中的活动程序。
}
void MyOpenGLWidget::paintGL()
{
glEnable(GL_MULTISAMPLE);
glClearColor(0.0f, 0.0f, 1.0f, 1.0f); //设置清除颜色缓冲区时使用的颜色,这里设置为白色。
glClear(GL_COLOR_BUFFER_BIT); //清除颜色缓冲区,将之前设定的清除颜色填充整个窗口。
GLfloat vertices[] = { //定义了一个包含矩形顶点坐标的数组。
-0.8f, -0.8f,
0.8f, -0.8f,
0.0f, 0.8f
};
GLuint vPosition = program->attributeLocation("vPosition"); //获取顶点着色器中属性变量vPosition的位置。
//将顶点数据与属性变量关联起来。vPosition表示属性变量的位置,2表示每个顶点有两个分量,GL_FLOAT表示每个分量的数据类型为浮点型,GL_FALSE表示不需要进行归一化处理,0表示相邻顶点间的偏移量,vertices表示顶点数据数组。
glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(vPosition); //启用顶点属性数组。
glDrawArrays(GL_TRIANGLE_FAN, 0, 3); //使用顶点数组绘制图元。GL_TRIANGLE_FAN表示绘制三角形扇,0表示从数组中的第一个顶点开始绘制,4表示绘制的顶点数量。
}
void MyOpenGLWidget::resizeGL(int w, int h)
{
glViewport(0, 0, w, h);
}
对代码进行修改,绘制点(将paintGL函数中代码替换如下):
// 定义顶点数据
GLfloat points[] = {
0.0f, 0.0f, 0.0f, // 第一个点的位置
0.5f, 0.5f, 0.0f, // 第二个点的位置
-0.5f, -0.5f, 0.0f // 第三个点的位置
};
// 创建顶点缓冲对象(VBO)并将顶点数据传入
GLuint vbo; //定义一个无符号整数变量vbo,用于存储VBO的标识符。
glGenBuffers(1, &vbo); //生成一个新的VBO,并将其标识符存储在vbo变量中。
glBindBuffer(GL_ARRAY_BUFFER, vbo); //绑定(激活)VBO,告诉OpenGL后续的操作都是针对这个VBO的。这里使用GL_ARRAY_BUFFER作为目标,表示这个VBO中存储的是顶点数据。
//将数据复制到VBO中。sizeof(points)表示点数组占用的字节数,points是指向点数组的指针。GL_STATIC_DRAW表示这个VBO中的数据将被修改很少,并且会被频繁地用于渲染操作。
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
// 启用顶点属性数组
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, 0);
// 绘制独立的点
glDrawArrays(GL_POINTS, 0, 3);
// 禁用顶点属性数组
glDisableClientState(GL_VERTEX_ARRAY);
绘制线段:(只需修改绘制模式)
// 绘制一条直线
glDrawArrays(GL_LINES, 0, 2);
//绘制多条直线
//首先顶点数要够
GLfloat lines[] = {
0.0f, 0.0f, 0.0f, // 第一条线起点
0.5f, 0.5f, 0.0f, // 第一条线终点
-0.5f, -0.5f, 0.0f, // 第二条线起点
-1.0f,1.0f,0.0f // 第二条线终点
};
//其余不动
glDrawArrays(GL_LINES, 0, sizeof(points)/sizeof(GLfloat)*3); //*3因为每个点有三个坐标x,y,z
#include "myopenglwidget.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyOpenGLWidget w;
w.resize(400,300);
w.show();
return a.exec();
}
QOpenGLShader *fShader = new QOpenGLShader(QOpenGLShader::Fragment, this);
const char* fsrc =
"void main(){\n"
" gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);\n" // 将输出的颜色设置为黄色
"}\n";
fShader->compileSourceCode(fsrc); //将片段着色器代码编译成可执行代码,并将结果存储在fShader对象中。如果编译失败,则会抛出异常。
GLfloat vertices[] = { //定义了一个包含矩形顶点坐标的数组。
-0.8f, -0.8f,
0.8f, -0.8f,
0.0f, 0.8f
};
glDrawArrays(GL_TRIANGLE_FAN, 0, 3); //使用顶点数组绘制图元。GL_TRIANGLE_FAN表示绘制三角形扇,0表示从数组中的第一个顶点开始绘制,4表示绘制的顶点数量。
其余不变:
void MyOpenGLWidget::paintGL()
{
glEnable(GL_MULTISAMPLE);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f); //设置清除颜色缓冲区时使用的颜色,这里设置为白色。
glClear(GL_COLOR_BUFFER_BIT); //清除颜色缓冲区,将之前设定的清除颜色填充整个窗口。
GLfloat vertices[] = { //定义了一个包含矩形顶点坐标的数组。
-0.9f, 0.9f,
0.1f, 0.9f,
-0.9f, 0.5f,
0.0f,0.0f,
-0.9f,0.0f,
-0.9f,-0.5f,
};
GLuint vPosition = program->attributeLocation("vPosition"); //获取顶点着色器中属性变量vPosition的位置。
//将顶点数据与属性变量关联起来。vPosition表示属性变量的位置,2表示每个顶点有两个分量,GL_FLOAT表示每个分量的数据类型为浮点型,GL_FALSE表示不需要进行归一化处理,0表示相邻顶点间的偏移量,vertices表示顶点数据数组。
glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(vPosition); //启用顶点属性数组。
glDrawArrays(GL_TRIANGLE_FAN, 0, 3); //使用顶点数组绘制图元。GL_TRIANGLE_FAN表示绘制三角形扇,0表示从数组中的第一个顶点开始绘制,4表示绘制的顶点数量。
glDrawArrays(GL_TRIANGLE_FAN, 3, 3);
qDebug()<
在 glDrawArrays函数中,第一个参数是绘制模式,第二个参数是顶点数组中起始下标,第三个参数是绘制使用的顶点个数.
绘制独立的三角形还是需要用特定模式:
glDrawArrays(GL_TRIANGLES, 0, sizeof(vertices)/(sizeof(GLfloat)*2));
其余不变:
void MyOpenGLWidget::initializeGL()
{
initializeOpenGLFunctions();
// 创建顶点着色器对象和片段着色器对象
QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
const char *vsrc =
"attribute vec4 vPosition;\n"
"void main() {\n"
" gl_Position = vPosition;\n"
"}\n";
vshader->compileSourceCode(vsrc);
QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
const char *fsrc =
"uniform vec4 uColor;\n"
"void main() {\n"
" gl_FragColor = uColor;\n"
"}\n";
fshader->compileSourceCode(fsrc);
// 创建着色器程序,并链接顶点着色器和片段着色器
program = new QOpenGLShaderProgram(this);
program->addShader(vshader);
program->addShader(fshader);
program->link();
}
void MyOpenGLWidget::paintGL()
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
GLfloat vertices[] = {
-0.9f, 0.9f,
0.1f, 0.9f,
-0.9f, 0.5f,
0.0f, 0.0f,
-0.9f, 0.0f,
-0.9f,-0.5f
};
GLuint vPosition = program->attributeLocation("vPosition");//获取 attribute 变量 vPosition 的位置
program->bind();//绑定着色器程序
glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(vPosition);
program->setUniformValue("uColor", QVector4D(1.0f, 0.0f, 0.0f, 1.0f)); // 设置第一个三角形的颜色为红色
glDrawArrays(GL_TRIANGLES, 0, 3);
program->setUniformValue("uColor", QVector4D(0.0f, 0.0f, 1.0f, 1.0f)); // 设置第二个三角形的颜色为蓝色
glDrawArrays(GL_TRIANGLES, 3, 3);
变化之处:
1.创建片段着色器时需要把颜色替换成一个变量
2.绘制图像之前对赵色器的颜色进行设置修改