qt opengl 畫球體
阿新 • • 發佈:2018-12-10
和一般寫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);
}