Qt OpenGL(04)Sierpinski 镂垫 3D 版

三维 Siepinski 镂垫

在这里插入图片描述

把前面的二维Sierpinski程序转换成一个生成三维Sierpinski镂垫的程序,也就是说要绘制的镂垫不再只是限制在一个平面里。我们可仿效对二维镂垫所使用的两种方法中的任何一种。 即用一个四面体代替初始的三角形

相关代码

  • std::vector 容器比较使用于OpenGL

  • 连续绑定 多个数组数据的使用方法

    • glBufferData (GL_ARRAY_BUFFER,points.size () * sizeof(QVector3D)* 2,NULL,GL_STATIC_DRAW);
    • glBufferSubData (GL_ARRAY_BUFFER, 0, points.size () * sizeof(QVector3D), points.data () );
    • glBufferSubData (GL_ARRAY_BUFFER, points.size () * sizeof(QVector3D), colors.size () * sizeof(QVector3D), colors.data () );
    • 每个面使用一种颜色
    color3 base_colors[4] = {
        color3(1.0,0.0,0.0),
        color3(0.0,1.0,0.0),
        color3(0.0,0.0,1.0),
        color3(1.0,1.0,0.0),
    };
    
  • 利用 pos 的 z 值加深显示,修改片元着色器

  • 添加 model 矩阵,并旋转动态显示

  • 屏幕缩放比例获取
    qApp->devicePixelRatio ();

  • Qt 的高分辨率设置,见main.cpp

main.cpp

#include "Widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute (Qt::AA_EnableHighDpiScaling);
    QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec ();
}

Help.hpp

#ifndef HELPER_H
#define HELPER_H

#include <QVector3D>
typedef QVector3D point3;
typedef QVector3D color3;

extern std::vector<QVector3D> points;
extern std::vector<QVector3D> colors;

#include <QDebug>
#define qout if( 1 ) qDebug() << __FILE__ << __LINE__ << ": "

int colorindex;

color3 base_colors[4] = {
    color3(1.0,0.0,0.0),
    color3(0.0,1.0,0.0),
    color3(0.0,0.0,1.0),
    color3(1.0,1.0,0.0),
};

void triangle(point3 a, point3 b, point3 c) {
    static int i = 0;
    colors.emplace_back (base_colors[colorindex]);
    points.emplace_back (a);
    ++i;

    colors.emplace_back (base_colors[colorindex]);
    points.emplace_back (b);
    ++i;

    colors.emplace_back (base_colors[colorindex]);
    points.emplace_back (c);
    ++i;

}

void tetra(point3 a, point3 b, point3 c,point3 d) {
    colorindex = 0;
    triangle(a,b,c);
    colorindex = 1;
    triangle(a,c,d);
    colorindex = 2;
    triangle(a,b,d);
    colorindex = 3;
    triangle(b,d,c);
}

void divide_tetra(point3 a, point3 b, point3 c,point3 d, int m) {
    if(m > 0 )
    {
        point3  mid[6];
        mid[0] = (a+b)/2.0;
        mid[1] = (a+c)/2.0;
        mid[2] = (a+d)/2.0;
        mid[3] = (b+c)/2.0;
        mid[4] = (c+d)/2.0;
        mid[5] = (b+d)/2.0;

        // 通过细分生成4个四面体
        divide_tetra (a,      mid[0], mid[1], mid[2], m-1);
        divide_tetra (mid[0],      b, mid[3], mid[5], m-1);
        divide_tetra (mid[1], mid[3],      c, mid[4], m-1);
        divide_tetra (mid[2], mid[5], mid[4],      d, m-1);
    }
    else
        tetra (a,b,c,d);
}

#endif // WIDGET_H

Widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>


class Widget : public QOpenGLWidget,QOpenGLFunctions_3_3_Core
{
    Q_OBJECT

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

    // QOpenGLWidget interface
protected:
    virtual void initializeGL() override;
    virtual void paintGL() override;
    virtual void resizeGL(int w, int h) override;

private:
    unsigned int VAO,VBO;
    QOpenGLShaderProgram shaderProgram;

    // void (Widget::* p)();

    int min,max;

    double ratio;	// 存放屏幕的缩放比例,Qt 5.15
};
#endif // WIDGET_H

Widget.cpp

#include "Widget.h"
#include "Helper.hpp"
#include "qcoreapplication.h"
#include "qelapsedtimer.h"
#include "qmatrix4x4.h"
#include "qvector3d.h"
#include <QThread>
#include <QDebug>
#include <QRandomGenerator>
#include <algorithm>
#include <vector>
#include <QApplication>

#define qRandom   QRandomGenerator::global ()
#define qout if( 0 ) qDebug() << __FILE__ << __LINE__ << ": "

constexpr int NumTimesToSubdivide = 3;

// std::vector 是内存连续的容器,比较适合opengl 的数据绑定
std::vector<QVector3D> points;
std::vector<QVector3D> colors;

Widget::Widget(QWidget *parent)
    : QOpenGLWidget(parent)
{
    setWindowTitle ("04_Siepinski_Recursion_3D");
    resize (300,300);

    int NumTriangles = std::pow(4,NumTimesToSubdivide+1) * 3;
    qout << NumTriangles;

    points.reserve (NumTriangles);	// 最后优化才添加的代码
    colors.reserve (NumTriangles);  // 最后优化才添加的代码
    qout << points.size () << points.capacity ();  // 大小 和 容量

    p = &Widget::update;

    ratio = qApp->devicePixelRatio ();

}

Widget::~Widget()
{
    makeCurrent ();
    glDeleteBuffers (1,&VBO);
    glDeleteVertexArrays (1,&VAO);
    doneCurrent ();
}

void Widget::initializeGL()
{
    initializeOpenGLFunctions ();

    const char *version =(const char *) glGetString (GL_VERSION);
    qout << QString(version);

    QVector3D vertices[4] = {
//        QVector3D(-1.0,-1.0,-1.0),
//        QVector3D( 1.0,-1.0,-1.0),
//        QVector3D( 0.0, 1.0,-1.0),
//        QVector3D( 0.0, 0.0, 1.0)

        QVector3D( 0.0f, 0.0f, -1.0f),
        QVector3D( 0.0f, 0.942809f, 0.333333f),
        QVector3D(-0.816497f, -0.471405f, 0.333333f),
        QVector3D( 0.816497f, -0.471405f, 0.333333f)
    };
    // 参考 https://blog.csdn.net/zhanxi1992/article/details/105771685中的数据
    QElapsedTimer timer;
    timer.start ();

    // 对初始的4面体进行细分
    divide_tetra (vertices[0],vertices[1],vertices[2],vertices[3],NumTimesToSubdivide);

    qout << timer.elapsed ();

    glGenBuffers (1,&VBO);
    glBindBuffer (GL_ARRAY_BUFFER,VBO);
    glBufferData (GL_ARRAY_BUFFER,points.size () * sizeof(QVector3D)* 2,NULL,GL_STATIC_DRAW);

    glBufferSubData (GL_ARRAY_BUFFER,
                     0,
                     points.size () * sizeof(QVector3D),
                     points.data () );

    glBufferSubData (GL_ARRAY_BUFFER,
                     points.size () * sizeof(QVector3D),
                     colors.size () * sizeof(QVector3D),
                     colors.data () );

    glGenVertexArrays (1,&VAO);
    glBindVertexArray(VAO);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(QVector3D), (void*)0);
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(QVector3D), (void*)(points.size () * sizeof(QVector3D)));
    glEnableVertexAttribArray(1);

    shaderProgram.addShaderFromSourceFile (QOpenGLShader::Vertex,  ":/shader.vert");
    shaderProgram.addShaderFromSourceFile (QOpenGLShader::Fragment,":/shader.frag");
    shaderProgram.link ();

    glBindBuffer (GL_ARRAY_BUFFER,0);

//    glPolygonMode (GL_FRONT_AND_BACK,GL_LINE);

    // 使能 深度测试
    glEnable(GL_DEPTH_TEST);
}

int count = 3;
QMatrix4x4 model;
void Widget::paintGL()
{
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);   // 设置背景色
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    shaderProgram.bind ();
    shaderProgram.setUniformValue ("u_color",1.0f, 0.5f, 0.2f, 1.0f);
    model.rotate ( 2, 1.0, 1.0, 1.0);
    glViewport ((max-min)/2 ,0,min,min);
    shaderProgram.setUniformValue ("model",model);
    glBindVertexArray(VAO);


    // 绘制三角形扇形
    glDrawArrays (GL_TRIANGLES,0,(int)points.size ());

    QThread::currentThread ()->msleep (50);
//    (this->*p)();
    update ();
}

void Widget::resizeGL(int w, int h)
{
    qout << "resizeGL";
    min = std::min (w,h) * ratio;
    max = std::max (w,h) * ratio;
}

顶点着色器

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
out  vec4 Color;

uniform mat4 model;

void main()
{
   gl_Position = model * vec4(aPos.x, aPos.y, aPos.z, 1.0);
   Color = vec4( aColor.xyz * (1-gl_Position.z)/2,1.0);
};

片元着色器

#version 330 core
out vec4 FragColor;
uniform vec4 u_color;
in vec4 Color;

void main()
{
//    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
    FragColor = Color;
}

总结

  • std::vector 使用十分方便
  • glViewport ((max-min)/2 ,0,min,min); 要在渲染过程调用才有用处【奇怪】
  • Qt 的高分辨率设置,windows屏幕的缩放比率获取,见widget.cpp
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值