QT三维图形1

先说一下我们想要做什么,以及这个小的系列会讲些什么。

首先这个系列很小,我觉得大概也就几节罢了,不可能给大家把三维Opengl讲透,所以读者应该是有点基础的。

在做体渲染的时候,我们有时候只需要渲染里面的一部分内容,也就是说我们不需要把整个体空间都渲染出来,这个时候,我们就应该建立一个窗口,里面有一个可以移动的矩形体来调节我们想要渲染的内容,注意要是矩形的。

在我们已有的工程上,建立一个DockWidget。然后再定义一个具体的Opengl类:

class My3DDisplayWidget : public QOpenGLWidget,protected QOpenGLFunctions
同时继承自两个Opengl类,一个是控件,一个是功能。在里面声明这些函数:

`void initializeGL();
void paintGL();
void resizeGL(int width, int height);
void keyPressEvent(QKeyEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);`
复制代码

其中前三个是系统自动调用的,用来进行初始化,绘制以及大小改变的时候进行一些修改。

按键事件暂时用不到。我们主要使用鼠标事件。

然后定义私有变量:

`private:
        QOpenGLShaderProgram *program;
        QOpenGLBuffer vbo;
        GLfloat xRot, yRot, zRot;
        GLfloat translateX, translateY, translateZ;`
复制代码

这些私有变量第一个是用来设置着色器程序的,第二个是缓冲区,然后是x,y,z轴的旋转角度,以及针对x,y,z方向的平移量。

在构造函数中,我们定义:

`My3DDisplayWidget::My3DDisplayWidget(QWidget *parent)
        : QOpenGLWidget(parent)
{
        xRot = 0.0;
        yRot = 0.0;
        zRot = 0.0;
        translateX = 0;
        translateY = 0;
        translateZ = -3.0;
        setMinimumSize(240,240);

}`
复制代码

进行了一些数据的初始化工作。

然后开始做Opengl初始化:

`void My3DDisplayWidget::initializeGL()
{
        // 为当前环境初始化OpenGL函数
        initializeOpenGLFunctions();
        QSurfaceFormat surfaceFormat;
        surfaceFormat.setSamples(4);//多重采样
        setFormat(surfaceFormat); //setFormat是QOpenGLWidget的函数
                                                          //glEnable( GL_BLEND );
        glEnable(GL_DEPTH_TEST);
        //glClearColor(255, 25, 15, 255);
        glClearColor(0, 0, 0, 255);
        // 创建顶点着色器
        QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
        const char *vsrc =
                "#version 330                              \n"
                "in vec4 vPosition;                        \n"
                "in vec4 vColor;                           \n"
                "out vec4 color;                           \n"
                "uniform mat4 matrix;                      \n"
                "void main() {                             \n"
                "   color = vColor;                        \n"
                "   gl_Position = matrix * vPosition;      \n"
                "}                                         \n";
        vshader->compileSourceCode(vsrc);
        // 创建片段着色器
        QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
        const char *fsrc =
                "#version 330                               \n"
                "in vec4 color;                             \n"
                "out vec4 fColor;                           \n"
                "void main() {                              \n"
                "   fColor = color;                         \n"
                "}                                          \n";
        fshader->compileSourceCode(fsrc);

        // 创建着色器程序
        program = new QOpenGLShaderProgram;
        program->addShader(vshader);
        program->addShader(fshader);

        program->link();
        program->bind();
}`
复制代码

注意如果你的程序调用一直失败,就一定要在着色器的程序里加上:

“#version 330 \n”
来强调使用的着色器OpenGL版本。

resizeGL以及按键响应都不添加了,在这里没什么用。

因为鼠标事件和旋转有关,我们待会再讲。先看一下我们定义的立方体:

`// 顶点位置
GLfloat vertices[6][4][3] = {
        //{ {-0.8f, 0.8f, 0.8f}, {-0.8f, -0.8f, 0.8f}, {0.8f, -0.8f, 0.8f}, {0.8f, 0.8f, 0.8f} },
        //{ {0.8f, 0.8f, 0.8f}, {0.8f, -0.8f, 0.8f}, {0.8f, -0.8f, -0.8f}, {0.8f, 0.8f, -0.8f} },
        { { 0.5f, -0.5f, -0.5f },{ 0.5f, 0.5f, -0.5f },{ -0.5f, 0.5f, -0.5f },{ -0.5f, -0.5f, -0.5f } },
        { { -0.5f, 0.5f, 0.5f },{ -0.5f, -0.5f, 0.5f },{ -0.5f, -0.5f, -0.5f },{ -0.5f, 0.5f, -0.5f } },
        //{ {0.8f, 0.8f, 0.8f}, {0.8f, 0.8f, -0.8f}, {-0.8f, 0.5f, -0.8f}, {-0.8f, 0.8f, 0.8f} },
        { { 0.5f, -0.5f, 0.5f },{ 0.5f, -0.5f, -0.5f },{ -0.5f, -0.5f, -0.5f },{ -0.5f, -0.5f, 0.5f } }
};
// 顶点颜色
GLfloat colors[6][4][3] = {
        { { 1.0f, 0.0f, 0.0f },{ 0.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0f },{ 1.0f, 1.0f, 1.0f } },
        { { 1.0f, 0.0f, 0.0f },{ 0.0f, 1.0f, 0.0f },{ 1.0f, 1.0f, 1.0f },{ 0.0f, 0.0f, 1.0f } },
        { { 1.0f, 0.0f, 0.0f },{ 0.0f, 1.0f, 0.0f },{ 1.0f, 1.0f, 1.0f },{ 0.0f, 0.0f, 1.0f } },
};
GLfloat rvs[6][4][3] = {
        { { -0.4f, 0.4f, 0.4f },{ -0.4f, -0.4f, 0.4f },{ 0.4f, -0.4f, 0.4f },{ 0.4f, 0.4f, 0.4f } },
        { { 0.4f, 0.4f, 0.4f },{ 0.4f, -0.4f, 0.4f },{ 0.4f, -0.4f, -0.4f },{ 0.4f, 0.4f, -0.4f } },
        { { -0.4f, 0.4f, -0.4f },{ -0.4f, -0.4f, -0.4f },{ 0.4f, -0.4f, -0.4f },{ 0.4f, 0.4f, -0.4f } },
        { { -0.4f, 0.4f, 0.4f },{ -0.4f, -0.4f, 0.4f },{ -0.4f, -0.4f, -0.4f },{ -0.4f, 0.4f, -0.4f } },
        { { 0.4f, 0.4f, 0.4f },{ 0.4f, 0.4f, -0.4f },{ -0.4f, 0.4f, -0.4f },{ -0.4f, 0.4f, 0.4f } },
        { { 0.4f, -0.4f, 0.4f },{ 0.4f, -0.4f, -0.4f },{ -0.4f, -0.4f, -0.4f },{ -0.4f, -0.4f, 0.4f } }
};
GLfloat vertices2[6][4][3] = {};
GLfloat colors2[6][4][3] = {
        { { 1.0f, 0.0f, 0.0f },{ 0.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0f },{ 1.0f, 1.0f, 1.0f } },
        { { 1.0f, 0.0f, 0.0f },{ 0.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0f },{ 1.0f, 1.0f, 1.0f } },
        { { 1.0f, 0.0f, 0.0f },{ 0.0f, 0.0f, 1.0f },{ 0.0f, 1.0f, 0.0f },{ 1.0f, 1.0f, 1.0f } },
        { { 1.0f, 0.0f, 0.0f },{ 0.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0f },{ 1.0f, 1.0f, 1.0f } },
        { { 1.0f, 0.0f, 0.0f },{ 0.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0f },{ 1.0f, 1.0f, 1.0f } },
        { { 1.0f, 0.0f, 0.0f },{ 0.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0f },{ 1.0f, 1.0f, 1.0f } }
};`
复制代码

这里大立方体和内部小立方体的顶点和颜色坐标。注意我们的内部小立方体是可以进行大小的调节的,但是为什么这里还要定义成常量的赋值呢?这样做有一个好处:为了方便再赋值:即我们根据rvs这里面初始值的正负来判断里面的值是vertices的左边界还是右边界。

我们在DockWidget里面定义一个

`GLfloat centralRectPos[3] = { 0,0,0 };
GLfloat halfBoundaries[3] = { 0.5,0.5,0.5 };`
复制代码

这个变量的值先赋一个初始值,这两个数组代表了大立方体内部的小立方体的位置和大小。其中上面的代表中心点的位置,我们设置为0,0,0,即中心点,然后下面的代表长度的一半。即总长度是1.0,这样,初始值正好让小立方体和大立方体重合了。

之后我们在OpenGL类里面写一个更新边界的函数:

`void updateVetices() {
        for (int i = 0;i<6;i++) {
                for (int j = 0;j<4;j++) {
                        if (rvs[i][j][0] < 0) {
                                vertices2[i][j][0] = centralRectPos[0] - halfBoundaries[0];
                        }
                        else {
                                vertices2[i][j][0] = centralRectPos[0] + halfBoundaries[0];
                        }
                        if (rvs[i][j][1] < 0) {
                                vertices2[i][j][1] = centralRectPos[1] - halfBoundaries[1];
                        }
                        else {
                                vertices2[i][j][1] = centralRectPos[1] + halfBoundaries[1];
                        }
                        if (rvs[i][j][2] < 0) {
                                vertices2[i][j][2] = centralRectPos[2] - halfBoundaries[2];
                        }
                        else {
                                vertices2[i][j][2] = centralRectPos[2] + halfBoundaries[2];
                        }


                }
        }
}`
复制代码

它可以根据变化的中心点的量生成新的小立方体各个顶点的数组。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享