此项目为Qt5所写,用到的是可编程管线的现代OpenGL,通过继承Qt中的QOpenGLWidget和QOpenGLExtraFunctions实现。只是一个最简单的坐标系,三条不同颜色的直线分别代表x, y, z轴,整体效果如下:
其实实现这个坐标系在老版本的OpenGL(freeglut,glut)中是很简单的,只需几行代码,但是在可编程管线中,由于要编写着色器,复杂程度就稍微高了一点。项目整体目录如下:
Coordinate.h
#include
class Coordinate : protected QOpenGLExtraFunctions
{
public:
Coordinate();
~Coordinate();
void init();
void drawX();
void drawY();
void drawZ();
private:
GLuint VBOX = 0;
GLuint VBOY = 0;
GLuint VBOZ = 0;
};
Coordinate.cpp
#include "coordinate.h"
Coordinate::Coordinate()
{
this->initializeOpenGLFunctions();
}
Coordinate::~Coordinate()
{
if(VBOX || VBOY || VBOZ)
{
glDeleteBuffers(1, &VBOX);
glDeleteBuffers(1, &VBOY);
glDeleteBuffers(1, &VBOZ);
}
}
void Coordinate::init()
{
float verticesX[] = {
0.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
};
float verticesY[] = {
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
float verticesZ[] = {
0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f
};
glGenBuffers(1, &VBOX);
glBindBuffer(GL_ARRAY_BUFFER, VBOX);
glBufferData(GL_ARRAY_BUFFER, sizeof(verticesX), verticesX, GL_STATIC_DRAW);
glGenBuffers(1, &VBOY);
glBindBuffer(GL_ARRAY_BUFFER, VBOY);
glBufferData(GL_ARRAY_BUFFER, sizeof(verticesY), verticesY, GL_STATIC_DRAW);
glGenBuffers(1, &VBOZ);
glBindBuffer(GL_ARRAY_BUFFER, VBOZ);
glBufferData(GL_ARRAY_BUFFER, sizeof(verticesZ), verticesZ, GL_STATIC_DRAW);
}
void Coordinate::drawX()
{
glBindBuffer(GL_ARRAY_BUFFER, VBOX);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glDrawArrays(GL_LINES, 0, 2);
}
void Coordinate::drawY()
{
glBindBuffer(GL_ARRAY_BUFFER, VBOY);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glDrawArrays(GL_LINES, 0, 2);
}
void Coordinate::drawZ()
{
glBindBuffer(GL_ARRAY_BUFFER, VBOZ);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glDrawArrays(GL_LINES, 0, 2);
}
Shader.h
#include
#include
#include
#include
class Shader {
public:
Shader(const QString& vertexSource, const QString& fragmentSource, const QString& geometrySource = NULL);
~Shader();
void use(){
shaderProgram->bind();
}
void setFloat(const QString& name, const GLfloat& value){
GLuint loc = shaderProgram->uniformLocation(name);
shaderProgram->setUniformValue(loc, value);
}
void setInteger(const QString& name, const GLint& value){
GLuint loc = shaderProgram->uniformLocation(name);
shaderProgram->setUniformValue(loc, value);
}
void setVector2f(const QString& name, const GLfloat& x, const GLfloat& y){
GLuint loc = shaderProgram->uniformLocation(name);
shaderProgram->setUniformValue(loc, QVector2D(x, y));
}
void setVector2f(const QString& name, const QVector2D& value){
GLuint loc = shaderProgram->uniformLocation(name);
shaderProgram->setUniformValue(loc, value);
}
void setVector3f(const QString& name, const GLfloat& x, const GLfloat& y, const GLfloat& z){
GLuint loc = shaderProgram->uniformLocation(name);
shaderProgram->setUniformValue(loc, QVector3D(x, y, z));
}
void setVector3f(const QString& name, const QVector3D& value){
GLuint loc = shaderProgram->uniformLocation(name);
shaderProgram->setUniformValue(loc, value);
}
void setVector4f(const QString& name, const GLfloat& x, const GLfloat& y, const GLfloat& z, const GLfloat& w){
GLuint loc = shaderProgram->uniformLocation(name);
shaderProgram->setUniformValue(loc, QVector4D(x, y, z, w));
}
void setVector4f(const QString& name, const QVector4D& value){
GLuint loc = shaderProgram->uniformLocation(name);
shaderProgram->setUniformValue(loc, value);
}
void setMatrix4f(const QString& name, const QMatrix4x4& value){
GLuint loc = shaderProgram->uniformLocation(name);
shaderProgram->setUniformValue(loc, value);
}
void setBool(const QString& name, const GLboolean& value){
GLuint loc = shaderProgram->uniformLocation(name);
shaderProgram->setUniformValue(loc, value);
}
private:
QOpenGLShaderProgram *shaderProgram;
};
Shader.cpp
#include "shader.h"
Shader::Shader(const QString& vertexSource, const QString& fragmentSource, const QString& geometrySource){
QOpenGLShader vertexShader(QOpenGLShader::Vertex);
bool success = vertexShader.compileSourceFile(vertexSource);
if(!success){
qDebug() << "ERROR::SHADER::VERTEX::COMPILATION_FAILED" << endl;
}
QOpenGLShader fragmentShader(QOpenGLShader::Fragment);
success = fragmentShader.compileSourceFile(fragmentSource);
if(!success){
qDebug() << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED" << endl;
}
QOpenGLShader geometryShader(QOpenGLShader::Geometry);
if(geometrySource != NULL){
success = geometryShader.compileSourceFile(geometrySource);
if(!success){
qDebug() << "ERROR::SHADER::GEOMETRY::COMPILATION_FAILED" << endl;
}
}
shaderProgram = new QOpenGLShaderProgram();
shaderProgram->addShader(&vertexShader);
shaderProgram->addShader(&fragmentShader);
if(geometrySource != NULL)
shaderProgram->addShader(&geometryShader);
success = shaderProgram->link();
if(!success){
qDebug() << "ERROR::SHADER::PROGRAM::LINKING_FAILED" << endl;
}
}
Widget.h
#include
#include
#include
#include
class Widget : public QOpenGLWidget, protected QOpenGLExtraFunctions
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
protected:
void initializeGL() override;
void resizeGL(int w, int h) override;
void paintGL() override;
private:
Coordinate *coordinate;
Shader *shaderX;
Shader *shaderY;
Shader *shaderZ;
};
Widget.cpp
#include "widget.h"
Widget::Widget(QWidget *parent) : QOpenGLWidget(parent)
{
this->setWindowTitle("Coordinate");
}
Widget::~Widget()
{
delete shaderX;
delete shaderY;
delete shaderZ;
}
void Widget::initializeGL(){
this->initializeOpenGLFunctions();
// load shaders
shaderX = new Shader(":/shaders/CoordinateX.vert",":/shaders/CoordinateX.frag");
shaderY = new Shader(":/shaders/CoordinateY.vert",":/shaders/CoordinateY.frag");
shaderZ = new Shader(":/shaders/CoordinateZ.vert",":/shaders/CoordinateZ.frag");
coordinate = new Coordinate();
coordinate->init();
// set projection and view matrix
QMatrix4x4 projection, view;
view.translate(QVector3D(0.0f, -0.5f, -3.0f)); // camera view
projection.perspective(45.0f, (GLfloat)width() / (GLfloat)height(), 0.1f, 100.0f);
shaderX->use();
shaderX->setMatrix4f("view", view);
shaderX->setMatrix4f("projection", projection);
shaderY->use();
shaderY->setMatrix4f("view", view);
shaderY->setMatrix4f("projection", projection);
shaderZ->use();
shaderZ->setMatrix4f("view", view);
shaderZ->setMatrix4f("projection", projection);
glEnable(GL_DEPTH_TEST);
}
void Widget::resizeGL(int w, int h)
{
glViewport(0, 0, w, h);
}
void Widget::paintGL()
{
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QMatrix4x4 model;
model.setToIdentity(); // Initializing, Set the rectangle to an identity matrix
model.rotate(-45.0f, 0.0f, 1.0f ,0.0f); // rotate coordinate system to aovid blocking z-axis
// draw x,y,z coordinate axis
shaderX->use();
shaderX->setMatrix4f("model", model);
coordinate->drawX();
shaderY->use();
shaderY->setMatrix4f("model", model);
coordinate->drawY();
shaderZ->use();
shaderZ->setMatrix4f("model", model);
coordinate->drawZ();
}
CoordinateX.vert
#version 330 core
layout (location = 0) in vec3 aPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main(){
gl_Position = projection * view * model * vec4(aPos, 1.0f);
}
CoordinateX.frag
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(0.0f, 1.0f, 0.0f, 1.0f);
}
y轴z轴着色器的代码和上面两个是一样的,除了FragColor中改了颜色,pro文件和main.cpp是自动生成的就不放代码了。很简单的一个坐标系,在每个轴末端加上一个小圆锥体效果会更好,有空尝试一下。
在"OpenGL画坐标系2"中增加了轴末端的四棱锥,效果更好,并且重构了代码,链接如下:https://blog.csdn.net/qq_37996632/article/details/103178120