qt opengl 画球体

和一般写opengl的程序一样,就直接出代码不多说。

        在qt中我使用qopenglwidget来操作opengl程序,声明如下

#ifndef WIDGET_H
#define WIDGET_H

#include <QOpenGLWidget>
#include "ballshader.h"
class Widget : public QOpenGLWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();

protected:
    void initializeGL() override;
    void paintGL() override;
    void resizeGL(int w, int h) override;
    void wheelEvent(QWheelEvent *event) override;

private:
    BallShader m_shader; //球渲染器
    QMatrix4x4 m_pMatrix,m_modelMatrix; //投影矩阵、基本转换矩阵
    QVector3D m_eye,m_target; //视点,和视点中心
};

#endif // WIDGET_H

实现文件如下

#include "widget.h"
#include <QWheelEvent>

Widget::Widget(QWidget *parent)
    : QOpenGLWidget(parent),
      m_eye(0,0,1), //初始视点位置
      m_target(0,0,-1) //初始观察目标位置
{
}

Widget::~Widget()
{

}

void Widget::initializeGL()
{
    m_shader.initialize(0.8); //初始化半径为0.8的球体数据
}

void Widget::paintGL()
{
    m_modelMatrix.rotate(30,0,1,0); //每次刷新绕y轴旋转30度

    QMatrix4x4 camera;
    camera.lookAt(m_eye,m_target,QVector3D{0,1,0}); //生成摄像机矩阵
    m_shader.render(QOpenGLContext::currentContext()->extraFunctions(),m_pMatrix,camera,m_modelMatrix); //渲染
}

void Widget::resizeGL(int w, int h)
{
    m_pMatrix.setToIdentity(); //重置为单位矩阵
    m_pMatrix.perspective(60.0f,GLfloat(w)/h,0.01f,100.0f); //设置投影
}

void Widget::wheelEvent(QWheelEvent *event)
{
    if (! event->pixelDelta().isNull()) {
        m_eye.setZ(m_eye.z() + event->pixelDelta().y()); //重置视点z值
    } else if (!event->angleDelta().isNull()) {
        m_eye.setZ(m_eye.z() + (event->angleDelta() / 120).y()); //重置视点z值
    }

    event->accept();
    update();
}

渲染器部分如下

#ifndef BALLSHADER_H
#define BALLSHADER_H

#include <QOpenGLExtraFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#define PI 3.14159265f

class BallShader
{
public:
    BallShader() = default;
    void initialize(float r);
    void render(QOpenGLExtraFunctions *f,QMatrix4x4 &projM,QMatrix4x4 & camera,QMatrix4x4 &model);

private:
    QOpenGLShaderProgram m_program;
    QOpenGLBuffer m_vbo;
    QVector<GLfloat> m_points;
    float m_r;
};

#endif // BALLSHADER_H
#include "ballshader.h"

void BallShader::initialize(float r)
{
    m_program.addCacheableShaderFromSourceFile(QOpenGLShader::Vertex,"vsrc.vsh");
    m_program.addCacheableShaderFromSourceFile(QOpenGLShader::Fragment,"fsrc.fsh");
    m_program.link();

    m_r = r;
    int angleSpan = 10; //弧度 = 角度 * PI / 180
    for(int vAngle = -90; vAngle < 90; vAngle = vAngle + angleSpan){ //生成球面顶点
        for(int hAngle = 0; hAngle <= 360; hAngle = hAngle + angleSpan){
            float x0 = r * ::cos(vAngle * PI / 180) * ::cos(hAngle * PI / 180);
            float y0 = r * ::cos(vAngle * PI / 180) * ::sin(hAngle * PI / 180);
            float z0 = r * ::sin(vAngle * PI / 180);

            float x1 = r * ::cos(vAngle * PI / 180) * ::cos((hAngle + angleSpan) * PI / 180);
            float y1 = r * ::cos(vAngle * PI / 180) * ::sin((hAngle + angleSpan) * PI / 180);
            float z1 = r * ::sin(vAngle * PI / 180);

            float x2 = r * ::cos((vAngle + angleSpan) * PI / 180) * ::cos((hAngle + angleSpan) * PI / 180);
            float y2 = r * ::cos((vAngle + angleSpan) * PI / 180) * ::sin((hAngle + angleSpan) * PI / 180);
            float z2 = r * ::sin((vAngle + angleSpan) * PI / 180);

            float x3 = r * ::cos((vAngle + angleSpan) * PI / 180) * ::cos(hAngle * PI / 180);
            float y3 = r * ::cos((vAngle + angleSpan) * PI / 180) * ::sin(hAngle * PI / 180);
            float z3 = r * ::sin((vAngle + angleSpan) * PI / 180);

            m_points << x1 << y1 << z1 << x3 << y3 << z3
                   << x0 << y0 << z0 << x1 << y1 << z1
                   << x2 << y2 << z2 << x3 << y3 << z3;
        }
    }
    m_vbo.create();
    m_vbo.bind();
    m_vbo.allocate(m_points.constData(),m_points.count() * sizeof GLfloat);
}

void BallShader::render(QOpenGLExtraFunctions *f, QMatrix4x4 &projM, QMatrix4x4 &camera, QMatrix4x4 &model)
{
    f->glClearColor(0.0, 0.0, 0.0, 0.0);
    f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    f->glEnable(GL_DEPTH_TEST);
    f->glEnable(GL_CULL_FACE);
    m_program.bind();
    m_vbo.bind();
    m_program.setUniformValue("uPMatrix",projM);
    m_program.setUniformValue("camMatrix",camera);
    m_program.setUniformValue("uMMatrix",model);
    m_program.setUniformValue("uR",m_r);
    m_program.enableAttributeArray(0);

    m_program.setAttributeBuffer(0,GL_FLOAT,0,3,0);
    f->glDrawArrays(GL_TRIANGLES,0,m_points.count() / 3);

    m_program.disableAttributeArray(0);
    m_vbo.release();
    m_program.release();
    f->glDisable(GL_DEPTH_TEST);
    f->glDisable(GL_CULL_FACE);
}

shader如下

#version 330
uniform mat4 uPMatrix,camMatrix,uMMatrix;
layout (location = 0) in vec3 aPosition;
smooth out vec3 vPosition; //将顶点坐标传递给片元着色器

void main(void)
{
    gl_Position = uPMatrix * camMatrix *uMMatrix * vec4(aPosition,1);
    vPosition = aPosition;
}
#version 330
uniform float uR; //球半径
in vec3 vPosition;
out vec4 fragColor;

void main(void)
{
    vec3 color;
    float n = 8.0; //x、y、z轴的分块数量
    float span = 2.0 * uR / n; //每块长度
    int i = int((vPosition.x + uR) / span); x轴所在层数
    int j = int((vPosition.y + uR) / span); y轴所在层数
    int k = int((vPosition.z + uR) / span); z轴所在层数
    int whichColor = int(mod(float(i+j+k),2.0)); //根据行列数取余,决定颜色
    if(whichColor == 1){
        color = vec3(0.678,0.231,0.129);
    }else{
        color = vec3(1.0,1.0,1.0);
    }
    fragColor = vec4(color,0);
}

     gitlab地址:https://gitlab.com/gitHubwhl562916378/ball

猜你喜欢

转载自blog.csdn.net/wanghualin033/article/details/82713150