opengl3维的贝塞尔曲线和平面的差不多,其实就是2维的贝塞尔曲线经过矩阵转换得到的。我们可以通过画多条贝塞尔曲线组合成一个漂亮的图形,我实现的是这样的
其渲染器实现如下
#ifndef BEZIERRENDER_H
#define BEZIERRENDER_H
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLExtraFunctions>
#include <QColor>
using BNPosition = QPair<GLfloat,GLfloat>;
class BezierRender
{
public:
BezierRender() = default;
void inititsize(QVector<BNPosition> points,float span,QColor c);
void render(QOpenGLExtraFunctions *f,QMatrix4x4 &pMatrix,QMatrix4x4 &vMatrix,QMatrix4x4 &mMatrix);
private:
QOpenGLShaderProgram program_;
QOpenGLBuffer vbo_;
QVector<GLfloat> vertPoints_,colorPoints_;
long jiecheng(int n);
};
#endif // BEZIERRENDER_H
#include <memory>
#include "bezierrender.h"
void BezierRender::inititsize(QVector<BNPosition> points, float span, QColor c)
{
program_.addCacheableShaderFromSourceFile(QOpenGLShader::Vertex,"vsrc.vert");
program_.addCacheableShaderFromSourceFile(QOpenGLShader::Fragment,"fsrc.frag");
program_.link();
int n = points.count() - 1;
if(n < 1){
return;
}
int steps = static_cast<int>(1.0f/span);
long *jiechengNA = new long[n+1];
for(int i = 0; i <= n; i++){
jiechengNA[i] = jiecheng(i);
}
for(int i = 0;i <= steps; i++){
float t=i*span;
if(t>1)
{
t=1;
}
float xf=0;
float yf=0;
float *tka = new float[n+1];
float *otka = new float[n+1];
for(int j = 0; j <= n; j++){
tka[j]=static_cast<float>(::pow(t,j));
otka[j]=static_cast<float>(::pow(1-t,j));
}
for(int k =0;k<=n;k++){
float xs=(jiechengNA[n]/(jiechengNA[k]*jiechengNA[n-k]))*tka[k]*otka[n-k];
xf=xf+points.at(k).first * xs;
yf=yf+points.at(k).second * xs;
}
vertPoints_ << xf << yf << 0.0;
colorPoints_ << c.redF() << c.greenF() << c.blueF();
delete tka;
delete otka;
}
QVector<GLfloat> alPoints;
alPoints << vertPoints_ << colorPoints_;
vbo_.create();
vbo_.bind();
vbo_.allocate(alPoints.data(),alPoints.count() * sizeof(GLfloat));
delete jiechengNA;
}
void BezierRender::render(QOpenGLExtraFunctions *f, QMatrix4x4 &pMatrix, QMatrix4x4 &vMatrix, QMatrix4x4 &mMatrix)
{
f->glEnable(GL_DEPTH_TEST);
f->glEnable(GL_CULL_FACE);
program_.bind();
vbo_.bind();
program_.setUniformValue("uPMatrix",pMatrix);
program_.setUniformValue("uVMatrix",vMatrix);
program_.setUniformValue("uMMatrix",mMatrix);
program_.enableAttributeArray(0);
program_.enableAttributeArray(1);
program_.setAttributeBuffer(0,GL_FLOAT,0,3,3*sizeof(GLfloat));
program_.setAttributeBuffer(1,GL_FLOAT,vertPoints_.count() * sizeof(GLfloat),3,3*sizeof(GLfloat));
f->glDrawArrays(GL_LINE_STRIP,0,vertPoints_.count() / 3);
program_.disableAttributeArray(0);
program_.disableAttributeArray(1);
vbo_.release();
program_.release();
f->glDisable(GL_DEPTH_TEST);
f->glDisable(GL_CULL_FACE);
}
long BezierRender::jiecheng(int n)
{
long result = 1;
if( n == 0){
return 1;
}
for(int i = 2; i <= n; i++){
result = result * i;
}
return result;
}
其shader实现如下
#version 330
uniform mat4 uPMatrix,uVMatrix,uMMatrix;
layout(location = 0) in vec3 aPosition;
layout(location = 1) in vec3 aColor;
smooth out vec4 vColor;
void main(void)
{
gl_Position = uPMatrix * uVMatrix * uMMatrix * vec4(aPosition,1);
vColor = vec4(aColor,1);
}
#version 330
in vec4 vColor;
out vec4 fragColor;
void main(void)
{
fragColor = vColor;
}
在使用时,我们需要通过矩阵转换来画多条曲线
#ifndef WIDGET_H
#define WIDGET_H
#include <QOpenGLWidget>
#include "bezierrender.h"
class Widget : public QOpenGLWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
protected:
void resizeGL(int w,int h) override;
void initializeGL() override;
void paintGL() override;
private:
BezierRender render_;
QMatrix4x4 pMatrix_;
QVector3D camera_;
};
#endif // WIDGET_H
#include "widget.h"
Widget::Widget(QWidget *parent)
: QOpenGLWidget(parent)
{
}
Widget::~Widget()
{
}
void Widget::resizeGL(int w, int h)
{
pMatrix_.setToIdentity();
pMatrix_.perspective(45,static_cast<float>(w)/h,0.01f,100.0f);
}
void Widget::initializeGL()
{
render_.inititsize(QVector<BNPosition>() << qMakePair(0.0,0.0)
<< qMakePair(0.4,-0.3) << qMakePair(0.4,0.3) << qMakePair(0.8,-0.6)
,0.05,Qt::white);
camera_.setX(0);
camera_.setY(0);
camera_.setZ(2);
}
void Widget::paintGL()
{
QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();
f->glClearColor(0.0, 0.0, 0.0, 0.0);
f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QMatrix4x4 vMatrix;
vMatrix.lookAt(camera_,QVector3D(0.0,0.0,0.0),QVector3D(0.0,1.0,0.0));
QMatrix4x4 mMatrix;
mMatrix.translate(0,0.4,0);
int n = 360 / 5;
for(int i = 0; i < n; i++){
QMatrix4x4 yangleMatrix;
yangleMatrix.rotate(i * 5,0,1,0);
render_.render(f,pMatrix_,vMatrix,yangleMatrix * mMatrix);
}
}
到此结束