• 150632

    文章

  • 1244

    评论

  • 13

    友链

  • 最近新加了换肤功能,大家多来逛逛吧~~~~
  • 喜欢这个网站的朋友可以加一下QQ群,我们一起交流技术。

基于QT的OpenGL教程学习17 -基于几何着色器实现catmull-rom样条曲线


这篇是在写几何着色器的时候,我看到其他博主写的使用几何着色器实现样条曲线,所以想自己也尝试实现下;当然再去做贝塞尔曲线没有什么意义。所以我这里实现另外一种过控制点的曲线:不过这次实现的是过控制点的曲线--catmull-rom样条;

公式推导可以参考下:公式推导

参考代码:参考

下面我在我原来的工程基础上添加新的类:CatmullRomSpline:

头文件如下:

#ifndef CATMULLROMSPLINE_H
#define CATMULLROMSPLINE_H


#include"shape.h"
class CatmullRomSpline:public Shape
{
    Q_OBJECT
public:
    CatmullRomSpline(int width,int height);
    ~CatmullRomSpline();
    virtual  void Render();
    virtual void Resize(int width, int height);
    virtual void SetTranslateVec(QVector3D vec);

};

#endif // CATMULLROMSPLINE_H

cpp文件如下:

#include "catmullromspline.h"
#include<QOpenGLFunctions>
#include<QOpenGLShaderProgram>
#include<QDebug>
#include"math.h"

CatmullRomSpline::CatmullRomSpline(int width,int height):
    Shape(width,height)
{
    m_vbo=nullptr;//顶点缓冲对象
    m_ebo=nullptr;//索引缓冲对象
    m_vao=nullptr;//顶点数组对象
    m_program=nullptr;
    initializeOpenGLFunctions();
    m_program = new QOpenGLShaderProgram(this);
    bool success = m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shader/CatmullRomSpline.vert");
    if (!success) {
        qDebug() << "vert: addShaderFromSourceFile failed!" << m_program->log();

    }

    //加载片段着色器程序
    success = m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shader/CatmullRomSpline.frag");
    if (!success) {
        qDebug() << " frag:addShaderFromSourceFile failed!" << m_program->log();

    }

    success = m_program->addShaderFromSourceFile(QOpenGLShader::Geometry, ":/shader/CatmullRomSpline.geom");
    if (!success) {
        qDebug() << "geo: addShaderFromSourceFile failed!" << m_program->log();
    }

    //链接着色器程序
    success = m_program->link();

    if(!success) {
        qDebug() << "shaderProgram link failed!" << m_program->log();
    }
    if(!success)return;
    float points[] = {
        -0.6f, -0.8f, 1.0f, 0.0f, 0.0f,
        -0.6f, -0.8f, 1.0f, 0.0f, 0.0f,//--
        -0.3f, -0.4f, 1.0f, 0.0f, 0.0f,//--
        0.3f, -0.4f, 1.0f, 0.0f, 0.0f,

        -0.6f, -0.8f, 1.0f, 0.0f, 0.0f,
        -0.3f, -0.4f, 1.0f, 0.0f, 0.0f,//--
        0.3f, -0.4f, 1.0f, 0.0f, 0.0f,
        0.6f, -0.8f, 1.0f, 0.0f, 0.0f,

        -0.3f, -0.4f, 1.0f, 0.0f, 0.0f,//--
        0.3f, -0.4f, 1.0f, 0.0f, 0.0f,
        0.6f, -0.8f, 1.0f, 0.0f, 0.0f,
        0.6f, -0.8f, 1.0f, 0.0f, 0.0f
    };

    m_vao=new QOpenGLVertexArrayObject;
    m_vbo=new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);

    QOpenGLVertexArrayObject::Binder vaobind(m_vao);
    m_vbo->create();
    m_vbo->bind();
    m_vbo->allocate(points, sizeof(points));

    int attr = -1;
    attr = m_program->attributeLocation("aPos");
    m_program->setAttributeBuffer(attr, GL_FLOAT, 0, 2, sizeof(GLfloat) * 5);
    m_program->enableAttributeArray(attr);
    attr = m_program->attributeLocation("aColor");
    m_program->setAttributeBuffer(attr, GL_FLOAT, 0, 3, sizeof(GLfloat) * 5);
    m_program->enableAttributeArray(attr);

    m_vao->release();
    m_vbo->release();

}


CatmullRomSpline::~CatmullRomSpline()
{

}

void CatmullRomSpline::Render()
{
   // if(m_visible)
  //  {
        glEnable(GL_PROGRAM_POINT_SIZE);
        m_program->bind();
        {
            QOpenGLVertexArrayObject::Binder vaoBind(m_vao);
            glDrawArrays(GL_LINES_ADJACENCY, 0, 12);
        }
        m_program->release();
 //   }

}
 void CatmullRomSpline::Resize(int width, int height)
 {
    Q_UNUSED(width);
    Q_UNUSED(height);
 }
 void CatmullRomSpline::SetTranslateVec(QVector3D vec)
 {
    Q_UNUSED(vec);
 }

几何着色器的代码如下:


#version 330 core
layout (lines_adjacency) in;
layout (line_strip, max_vertices = 100) out;
in VS_OUT {
    vec3 color;
} gs_in[];

out vec3 fColor;


vec2 GetCatmullRomPosition(float t, vec2 p0, vec2 p1, vec2 p2, vec2 p3)
{
    vec2 a = 2 * p1;
    vec2 b = p2 - p0;
    vec2 c = 2 * p0 - 5 * p1 + 4 * p2 - p3;
    vec2 d = -p0 + 3 * p1 - 3 * p2 + p3;

    vec2 pos = 0.5f * (a + (b * t) + (c * t * t) + (d * t * t * t));

    return pos;
}

void GetCatmullRomSplinePos(vec2 p0, vec2 p1, vec2 p2, vec2 p3)
{
    float resolution = 0.01f;
    int loops = 100; //loops=1/resolution
    for (int i = 0; i < loops; i++)//<=loops
    {
        vec2 temppos = GetCatmullRomPosition(i * resolution, p0, p1, p2, p3);
        gl_Position= vec4(temppos.x, temppos.y, 0.0, 1.0);
        EmitVertex();
    }

    EndPrimitive();
}


void main() {

 fColor = gs_in[0].color;
 vec4 tempp0=gl_in[0].gl_Position;
 vec4 tempp1=gl_in[1].gl_Position;
 vec4 tempp2=gl_in[2].gl_Position;
 vec4 tempp3=gl_in[3].gl_Position;

GetCatmullRomSplinePos(vec2(tempp0.x,tempp0.y),vec2(tempp1.x,tempp1.y),vec2(tempp2.x,tempp2.y), vec2(tempp3.x,tempp3.y));


}

通过公式推导,我们知道catmull-rom样条曲线 需要至少四个点来进行计算,所以我们每次传入几何着色器的点数应该是4个;

所以我们需要解决的第一个问题就是:如何传递4个顶点到着色器中;

这里我们在绘制顶点的时候,采用GL_LINES_ADJACENCY 形式进行绘制;GL_LINES_ADJACENCY 与 GL_LINES 不同;

使用GL_LINES_ADJACENCY类型图元,在渲染管道中放入8个顶点,那么几何着色器将会运行两次;

现在假设我们想要绘制的顶点是:

P0(-0.6f, -0.8f)
P1( -0.3f, -0.4f)
P2( 0.3f, -0.4f)
P3(0.6f, -0.8f)

,那么我们直接用点(GL_POINTS)来绘制,效果是:

但是如果我们用GL_LINES_ADJACENCY 来绘制,并不能将其链接成折线段,因为GL_LINES_ADJACENCY 中四个顶点的第一个和最后一个并不会被绘制,而是只绘制中间的点,因此如果我们想要绘制四个点的连线,必须要重新组织顶点:

 float points[] = {
        //point       //color
        -0.6f, -0.8f, 1.0f, 0.0f, 0.0f,//--p0
        -0.6f, -0.8f, 1.0f, 0.0f, 0.0f,//--p0
        -0.3f, -0.4f, 1.0f, 0.0f, 0.0f,//--p1
        0.3f, -0.4f, 1.0f, 0.0f, 0.0f,//--p2  以上是第一组

        -0.6f, -0.8f, 1.0f, 0.0f, 0.0f,//--p0
        -0.3f, -0.4f, 1.0f, 0.0f, 0.0f,//--p1
        0.3f, -0.4f, 1.0f, 0.0f, 0.0f,//--p2
        0.6f, -0.8f, 1.0f, 0.0f, 0.0f,//--p3以上是第二组

        -0.3f, -0.4f, 1.0f, 0.0f, 0.0f,//--p1
        0.3f, -0.4f, 1.0f, 0.0f, 0.0f,//--p2
        0.6f, -0.8f, 1.0f, 0.0f, 0.0f,//--p3
        0.6f, -0.8f, 1.0f, 0.0f, 0.0f//--p3 以上是第三组
    };

第一个和最后一个顶点是为了做边界处理;

相信上面这组数据很容易看出来规律;

这样,每次传入四个顶点,如果不开启几何着色器中的曲线生成算法,直接绘制那么绘制效果如下:

 

着色器中的具体函数,比较简单不需要再细说了。绘制曲线效果如下:

 


695856371Web网页设计师②群 | 喜欢本站的朋友可以收藏本站,或者加入我们大家一起来交流技术!

0条评论

Loading...


发表评论

电子邮件地址不会被公开。 必填项已用*标注

自定义皮肤 主体内容背景
打开支付宝扫码付款购买视频教程
遇到问题联系客服QQ:419400980
注册梁钟霖个人博客