qt opengl 3d基本形状-螺旋管

30 篇文章 11 订阅

         螺旋管的做法和上一节的圆柱非常类似,就是在大圆径每转过一定角度时,将y值加上一定值。另个其纹理坐标生成的方法也和上一节一致。我做出的效果如下

其渲染器实现如下

#ifndef LUOXUANGUANRENDER_H
#define LUOXUANGUANRENDER_H

#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>
#include <QOpenGLExtraFunctions>
#define PI 3.14159265f
class LuoxuanGuanRender
{
public:
    LuoxuanGuanRender() = default;
    void initsize(float rBig,float rSmall,float h,float nCirclef,int nCol,int nRow,QImage &img);
    void initsize(float rBig,float rSmall,float h,float nCirclef,int nCol,int nRow);
    void render(QOpenGLExtraFunctions *f,QMatrix4x4 &pMatrix,QMatrix4x4 &vMatrix,QMatrix4x4 &mMatrix);

private:
    QOpenGLShaderProgram program_;
    QOpenGLBuffer vbo_;
    QVector<GLfloat> vertPoints_,textPoints_;
    QOpenGLTexture *texture_{nullptr};
    bool userTexture_ = false;
};

#endif // LUOXUANGUANRENDER_H
#include "luoxuanguanrender.h"

void LuoxuanGuanRender::initsize(float rBig, float rSmall, float h, float nCirclef, int nCol, int nRow, QImage &img)
{
    userTexture_ = true;
    program_.addCacheableShaderFromSourceFile(QOpenGLShader::Vertex,"vsrc.vert");
    program_.addCacheableShaderFromSourceFile(QOpenGLShader::Fragment,"fsrc.frag");
    program_.link();

    float angdegTotal=nCirclef*360.0f;//大圆周总度数
    float angdegColSpan=360.0f/nCol;//小圆周每份的角度跨度
    float angdegRowSpan=angdegTotal/nRow;//大圆周每份的角度跨度
    float A=(rBig-rSmall)/2;//用于旋转的小圆半径
    float D=rSmall+A;//旋转轨迹形成的大圆周半径
    QVector<GLfloat> originVertPoints,originTextPoints;
    for(float angdegCol=0;::ceil(angdegCol)<360+angdegColSpan;angdegCol+=angdegColSpan)
    {
        double a=angdegCol * PI / 180;//当前小圆弧度
        float t=angdegCol/360;//当前角度对应的t坐标
        for(float angdegRow=0;::ceil(angdegRow)<angdegTotal+angdegRowSpan;angdegRow+=angdegRowSpan)//重复了一列顶点,方便了索引的计算
        {
            float yVec=(angdegRow/angdegTotal)*h;//根据旋转角度增加y的值
            double u=angdegRow * PI /180;//当前大圆周弧度
            float y=A*::cos(a);
            float x=(D+A*::sin(a))*::sin(u);
            float z=(D+A*::sin(a))*::cos(u);
            //将计算出来的XYZ坐标加入存放顶点坐标的ArrayList
            originVertPoints << x << y + yVec << z;

            float s=angdegRow/360;//当前角度对应的s坐标
            originTextPoints << s << t;
        }
    }

    for(int i=0;i<nCol-1;i++){//按照卷绕成三角形的需要
        for(int j=0;j<nRow;j++){//生成顶点编号列表
            int index=i*(nRow+1)+j;//当前四边形第一顶点编号
            vertPoints_ << originVertPoints.at((index+1)*3 + 0); //第一个三角形三个顶点的编号入列表
            vertPoints_ << originVertPoints.at((index+1)*3 + 1);
            vertPoints_ << originVertPoints.at((index+1)*3 + 2);
            vertPoints_ << originVertPoints.at((index+nRow+1)*3 + 0);
            vertPoints_ << originVertPoints.at((index+nRow+1)*3 + 1);
            vertPoints_ << originVertPoints.at((index+nRow+1)*3 + 2);
            vertPoints_ << originVertPoints.at((index+nRow+2)*3 + 0);
            vertPoints_ << originVertPoints.at((index+nRow+2)*3 + 1);
            vertPoints_ << originVertPoints.at((index+nRow+2)*3 + 2);

            textPoints_ << originTextPoints.at((index +1)*2 + 0); //第一个三角形颜色
            textPoints_ << originTextPoints.at((index +1)*2 + 1);
            textPoints_ << originTextPoints.at((index +1)*2 + 2);
            textPoints_ << originTextPoints.at((index +1)*2 + 3);
            textPoints_ << originTextPoints.at((index+nRow+1)*2 + 0);
            textPoints_ << originTextPoints.at((index+nRow+1)*2 + 1);
            textPoints_ << originTextPoints.at((index+nRow+1)*2 + 2);
            textPoints_ << originTextPoints.at((index+nRow+1)*2 + 3);
            textPoints_ << originTextPoints.at((index+nRow+2)*2 + 0);
            textPoints_ << originTextPoints.at((index+nRow+2)*2 + 1);
            textPoints_ << originTextPoints.at((index+nRow+2)*2 + 2);
            textPoints_ << originTextPoints.at((index+nRow+2)*2 + 3);

            vertPoints_ << originVertPoints.at((index+1)*3 + 0); //第二个三角形三个顶点的编号入列表
            vertPoints_ << originVertPoints.at((index+1)*3 + 1);
            vertPoints_ << originVertPoints.at((index+1)*3 + 2);
            vertPoints_ << originVertPoints.at(index*3 + 0);
            vertPoints_ << originVertPoints.at(index*3 + 1);
            vertPoints_ << originVertPoints.at(index*3 + 2);
            vertPoints_ << originVertPoints.at((index+nRow+1)*3 + 0);
            vertPoints_ << originVertPoints.at((index+nRow+1)*3 + 1);
            vertPoints_ << originVertPoints.at((index+nRow+1)*3 + 2);

            textPoints_ << originTextPoints.at((index+1)*2 + 0); //第二个三角形纹理坐标
            textPoints_ << originTextPoints.at((index+1)*2 + 1);
            textPoints_ << originTextPoints.at((index+1)*2 + 2);
            textPoints_ << originTextPoints.at((index+1)*2 + 3);
            textPoints_ << originTextPoints.at(index*2 + 0);
            textPoints_ << originTextPoints.at(index*2 + 1);
            textPoints_ << originTextPoints.at(index*2 + 2);
            textPoints_ << originTextPoints.at(index*2 + 3);
            textPoints_ << originTextPoints.at((index+nRow+1)*2 + 0);
            textPoints_ << originTextPoints.at((index+nRow+1)*2 + 1);
            textPoints_ << originTextPoints.at((index+nRow+1)*2 + 2);
            textPoints_ << originTextPoints.at((index+nRow+1)*2 + 3);
        }
    }

    QVector<GLfloat> vboVec;
    vboVec << vertPoints_ << textPoints_;
    vbo_.create();
    vbo_.bind();
    vbo_.allocate(vboVec.data(),vboVec.count() * sizeof(GLfloat));

    texture_ = new QOpenGLTexture(img);
    texture_->setWrapMode(QOpenGLTexture::ClampToEdge);
    texture_->setMinMagFilters(QOpenGLTexture::NearestMipMapNearest,QOpenGLTexture::LinearMipMapNearest);
}

void LuoxuanGuanRender::initsize(float rBig, float rSmall, float h, float nCirclef, int nCol, int nRow)
{
    userTexture_ = false;
    program_.addCacheableShaderFromSourceFile(QOpenGLShader::Vertex,"lvsrc.vert");
    program_.addCacheableShaderFromSourceFile(QOpenGLShader::Fragment,"lfsrc.frag");
    program_.link();

    float angdegTotal=nCirclef*360.0f;//总度数
    float angdegColSpan=360.0f/nCol;
    float angdegRowSpan=angdegTotal/nRow;
    float A=(rBig-rSmall)/2;//用于旋转的小圆半径
    float D=rSmall+A;//旋转轨迹形成的大圆周半径
    QVector<GLfloat> originVertPoints,originColorPoints;
    for(float angdegCol=0;::ceil(angdegCol)<360+angdegColSpan;angdegCol+=angdegColSpan)
    {
        double a=angdegCol * PI / 180;//当前小圆弧度
        for(float angdegRow=0;::ceil(angdegRow)<angdegTotal+angdegRowSpan;angdegRow+=angdegRowSpan)//重复了一列顶点,方便了索引的计算
        {
            float yVec=(angdegRow/angdegTotal)*h;//根据旋转角度增加y的值
            double u=angdegRow * PI /180;//当前大圆周弧度
            float y=A*::cos(a);
            float x=(D+A*::sin(a))*::sin(u);
            float z=(D+A*::sin(a))*::cos(u);
            //将计算出来的XYZ坐标加入存放顶点坐标的ArrayList
            originVertPoints << x << y + yVec << z;
            originColorPoints << 1.0 << 1.0 << 1.0 << 1.0;
        }
    }

    for(int i=0;i<nCol;i++){//按照卷绕成三角形的需要
        for(int j=0;j<nRow;j++){//生成顶点编号列表
            int index=i*(nRow+1)+j;//当前四边形第一顶点编号
            vertPoints_ << originVertPoints.at((index+1)*3 + 0); //第一个三角形三个顶点的编号入列表
            vertPoints_ << originVertPoints.at((index+1)*3 + 1);
            vertPoints_ << originVertPoints.at((index+1)*3 + 2);
            vertPoints_ << originVertPoints.at((index+nRow+1)*3 + 0);
            vertPoints_ << originVertPoints.at((index+nRow+1)*3 + 1);
            vertPoints_ << originVertPoints.at((index+nRow+1)*3 + 2);
            vertPoints_ << originVertPoints.at((index+nRow+2)*3 + 0);
            vertPoints_ << originVertPoints.at((index+nRow+2)*3 + 1);
            vertPoints_ << originVertPoints.at((index+nRow+2)*3 + 2);

            textPoints_ << originColorPoints.at((index +1)*2 + 0); //第一个三角形颜色
            textPoints_ << originColorPoints.at((index +1)*2 + 1);
            textPoints_ << originColorPoints.at((index +1)*2 + 2);
            textPoints_ << originColorPoints.at((index +1)*2 + 3);
            textPoints_ << originColorPoints.at((index+nRow+1)*2 + 0);
            textPoints_ << originColorPoints.at((index+nRow+1)*2 + 1);
            textPoints_ << originColorPoints.at((index+nRow+1)*2 + 2);
            textPoints_ << originColorPoints.at((index+nRow+1)*2 + 3);
            textPoints_ << originColorPoints.at((index+nRow+2)*2 + 0);
            textPoints_ << originColorPoints.at((index+nRow+2)*2 + 1);
            textPoints_ << originColorPoints.at((index+nRow+2)*2 + 2);
            textPoints_ << originColorPoints.at((index+nRow+2)*2 + 3);

            vertPoints_ << originVertPoints.at((index+1)*3 + 0); //第二个三角形三个顶点的编号入列表
            vertPoints_ << originVertPoints.at((index+1)*3 + 1);
            vertPoints_ << originVertPoints.at((index+1)*3 + 2);
            vertPoints_ << originVertPoints.at(index*3 + 0);
            vertPoints_ << originVertPoints.at(index*3 + 1);
            vertPoints_ << originVertPoints.at(index*3 + 2);
            vertPoints_ << originVertPoints.at((index+nRow+1)*3 + 0);
            vertPoints_ << originVertPoints.at((index+nRow+1)*3 + 1);
            vertPoints_ << originVertPoints.at((index+nRow+1)*3 + 2);

            textPoints_ << originColorPoints.at((index+1)*2 + 0); //第二个三角形纹理坐标
            textPoints_ << originColorPoints.at((index+1)*2 + 1);
            textPoints_ << originColorPoints.at((index+1)*2 + 2);
            textPoints_ << originColorPoints.at((index+1)*2 + 3);
            textPoints_ << originColorPoints.at(index*2 + 0);
            textPoints_ << originColorPoints.at(index*2 + 1);
            textPoints_ << originColorPoints.at(index*2 + 2);
            textPoints_ << originColorPoints.at(index*2 + 3);
            textPoints_ << originColorPoints.at((index+nRow+1)*2 + 0);
            textPoints_ << originColorPoints.at((index+nRow+1)*2 + 1);
            textPoints_ << originColorPoints.at((index+nRow+1)*2 + 2);
            textPoints_ << originColorPoints.at((index+nRow+1)*2 + 3);
        }
    }

    QVector<GLfloat> vboVec;
    vboVec << vertPoints_ << textPoints_;
    vbo_.create();
    vbo_.bind();
    vbo_.allocate(vboVec.data(),vboVec.count() * sizeof(GLfloat));
}

void LuoxuanGuanRender::render(QOpenGLExtraFunctions *f, QMatrix4x4 &pMatrix, QMatrix4x4 &vMatrix, QMatrix4x4 &mMatrix)
{
    f->glEnable(GL_DEPTH_TEST);
    f->glEnable(GL_CULL_FACE);
    program_.bind();
    vbo_.bind();
    if(userTexture_){
        f->glActiveTexture(GL_TEXTURE0);
        program_.setUniformValue("uPMatrix",pMatrix);
        program_.setUniformValue("uVMatrix",vMatrix);
        program_.setUniformValue("uMMatrix",mMatrix);
        program_.setUniformValue("sTexture",0);

        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),2,2*sizeof(GLfloat));
        texture_->bind();
        f->glDrawArrays(GL_TRIANGLES,0,vertPoints_.count() / 3);
        program_.disableAttributeArray(0);
        program_.disableAttributeArray(1);

        texture_->release();
    }else{
        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),4,4*sizeof(GLfloat));
        f->glDrawArrays(GL_LINES,0,vertPoints_.count() / 3);
        program_.disableAttributeArray(0);
        program_.disableAttributeArray(1);
    }
    vbo_.release();
    program_.release();
    f->glDisable(GL_CULL_FACE);
    f->glDisable(GL_DEPTH_TEST);
}

 其shader实现如下,带图片纹理

#version 330
uniform mat4 uPMatrix,uVMatrix,uMMatrix;
layout (location = 0)in vec3 aPosition;
layout (location = 1)in vec2 aTexture;
smooth out vec2 vTexture;

void main(void)
{
    gl_Position = uPMatrix * uVMatrix * uMMatrix * vec4(aPosition,1);
    vTexture = aTexture;
}
#version 330
uniform sampler2D sTexture;
in vec2 vTexture;
out vec4 fragColor;

void main(void)
{
    fragColor = texture2D(sTexture,vTexture);
}

不带纹理

#version 330
uniform mat4 uPMatrix,uVMatrix,uMMatrix;
layout (location = 0)in vec3 aPosition;
layout (location = 1)in vec4 aColor;
smooth out vec4 vColor;

void main(void)
{
    gl_Position = uPMatrix * uVMatrix * uMMatrix * vec4(aPosition,1);
    vColor = aColor;
}
#version 330
in vec4 vColor;
out vec4 fragColor;

void main(void)
{
    fragColor = vColor;
}

其使用方法和上一节一样,只是参数传递有一些不一样而已

#ifndef WIDGET_H
#define WIDGET_H

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

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

protected:
    void initializeGL() override;
    void resizeGL(int w, int h) override;
    void paintGL() override;

private:
    QTimer tm_;
    LuoxuanGuanRender render_;
    QMatrix4x4 pMatrix_;
    QVector3D camera_;
    qreal angleX_ = 0,angleY_ = 0,angleZ_ = 0;

private slots:
    void slotTimeout();
};

#endif // WIDGET_H
#include "widget.h"

Widget::Widget(QWidget *parent)
    : QOpenGLWidget(parent)
{
    connect(&tm_,SIGNAL(timeout()),this,SLOT(slotTimeout()));
    tm_.start(60);
}

Widget::~Widget()
{

}

void Widget::initializeGL()
{
//    render_.initsize(1.8,1.0,7,3.3,10,80,QImage("texture.png"));
    render_.initsize(1.8,1.0,7,3.3,10,80);
    camera_.setX(0);
    camera_.setY(0);
    camera_.setZ(10);
}

void Widget::resizeGL(int w, int h)
{
    pMatrix_.setToIdentity();
    pMatrix_.perspective(45,float(w)/h,0.01f,100.0f);
}

void Widget::paintGL()
{
    QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();
    f->glClearColor(0.0f,0.0f,0.0f,0.0f);
    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.rotate(angleX_,1,0,0);
    mMatrix.translate(0,-3.2,0);
    mMatrix.rotate(angleY_,0,1,0);
//    mMatrix.rotate(angleZ_,0,0,1);
    render_.render(f,pMatrix_,vMatrix,mMatrix);
}

void Widget::slotTimeout()
{
    angleX_ += 5;
    angleY_ += 5;
    angleZ_ += 5;
    update();
}

到此结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值