本文使用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);
其中,第一个参数指定绘制的模式,第二个参数指定要绘制的顶点的起始位置,第三个参数指定要绘制的顶点数量。
1.绘制三角形
代码如下:
myopenglwidget.h
// An highlighted block
#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>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
myopenglwidget.cpp
#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
main.cpp
#include "myopenglwidget.h"
#include <QApplication>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表示绘制的顶点数量。
2.绘制两个三角形
其余不变:
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()<<sizeof(vertices)/(sizeof(GLfloat)*2);
// glDrawArrays(GL_TRIANGLE_FAN, 3, sizeof(vertices)/sizeof(GLfloat)*3);
}
在 glDrawArrays函数中,第一个参数是绘制模式,第二个参数是顶点数组中起始下标,第三个参数是绘制使用的顶点个数.
绘制独立的三角形还是需要用特定模式:
- 一步到位
glDrawArrays(GL_TRIANGLES, 0, sizeof(vertices)/(sizeof(GLfloat)*2));
3.绘制两个不同颜色的三角形
其余不变:
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.绘制图像之前对赵色器的颜色进行设置修改