QML窗口中的OpenGL场景

时间:2015-08-27 19:36:04

标签: c++ qt opengl qml

我正在尝试使用QML窗口在OpenGL中实现3D模型。 我面临的问题是当前显示器显示在一个单独的窗口中,我无法将其移植到现有的QML窗口。

任何人都可以告诉我哪里出错了吗?

display.h

#ifndef _MODEL_H_
#define _MODEL_H_

#include <qopenglwidget.h>
#include <qopenglfunctions.h>
#include <qopenglshaderprogram.h>
#include <qmatrix4x4.h>
#include <qvector3d.h>
#include "hind.h"

namespace lib {
namespace modd {

class Model : public QOpenGLWidget, protected QOpenGLFunctions
{
public:

Model();
~Model();
void cleanup();

protected:

void initializeGL();
void paintGL();
void resizeGL(int w, int h);

void render_model();

void clear_buffers();
void prepare_buffers_elements2D();
void prepare_buffers();
void render_model_buffers();

private:

lib::body::Bod* m_model;
lib::body::Source* m_source;
lib::Hind& context;

QSize m_viewportSize;

QOpenGLShaderProgram* m_program, *m_program_quadtri;
GLuint m_quadTri;
GLuint m_posAttr;
GLuint m_colAttr;
GLuint m_barycentric;
GLuint m_matProjUniform, m_matMvUniform;

QMatrix4x4 mat_modelview, mat_proj;
QMatrix4x4 mat_zRot;

QVector3D oview;
QVector3D iview, jview, kview;
QMatrix4x4 mat_tx_view;
QMatrix4x4 mat_scale;


int xlast, ylast;
static const int R = 59, G = 89, B = 152;
float colorR, colorG, colorB;

// vertex buffers
std::vector<float> vlines, vtriangles, vquadtriangles;
std::vector<float> bctriangles, bcquadtriangles;

// color buffers
std::vector<float> clines, ctriangles, cquadtriangles;

};

}
}

#endif

display.cpp

#include <qopenglwidget.h>
#include <qopenglfunctions.h>
#include <qopenglshaderprogram.h>
#include <QWheelEvent>
#include "display.h"

namespace lib {
namespace mod {

static const char *vertexShaderSource =
    "attribute highp vec4 posAttr;\n"
    "attribute lowp vec4 colAttr;\n"
    "attribute vec3 barycentric;\n"
    "varying lowp vec3 col;\n"
    "varying vec3 vBC;\n"
    "uniform highp mat4 mat_proj;\n"
    "uniform highp mat4 mat_mv;\n"
    "void main() {\n"
    "   col = colAttr.rgb;\n"
    "   gl_Position = mat_proj * mat_mv * posAttr;\n"
    "   vBC = barycentric;\n"
    "}\n";

static const char *fragmentShaderSource =
    "#extension GL_OES_standard_derivatives : enable\n"
    "uniform int quadTri;\n"
    "varying vec3 vBC;\n"
    "float edgeFactor(){\n"
    "   vec3 d = fwidth(vBC);\n"
    "   vec3 a3 = smoothstep(vec3(0.0), d*0.95, vBC);\n"
    "   if (quadTri == 0)\n"
    "   {\n"
    "       return min(min(a3.x, a3.y), a3.z);\n"
    "   } else if (quadTri == 1) {\n"
    "       return min(a3.x, a3.z);\n"
    "   }\n"
    "}\n"
    "varying lowp vec3 col;\n"
    "void main() {\n"
    "   gl_FragColor.rgb = mix(vec3(0.0), col, edgeFactor());\n"
    "   gl_FragColor.a = 1.0;\n"
    "}\n";


Model::Model() : m_model(0), m_source(0),context(lib::Hind::instance()), m_program(0), xlast(0), ylast(0)
{
    m_model = &context.model();
    m_source = &(m_model->source());
}

Model::~Model()
{
makeCurrent();
cleanup();
doneCurrent();
}

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

glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);

m_program = new QOpenGLShaderProgram(this);
bool result = m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
result = m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
m_program->link();

m_quadTri = m_program->uniformLocation("quadTri");
m_posAttr = m_program->attributeLocation("posAttr");
m_colAttr = m_program->attributeLocation("colAttr");
m_barycentric = m_program->attributeLocation("barycentric");

m_matProjUniform = m_program->uniformLocation("mat_proj");
m_matMvUniform = m_program->uniformLocation("mat_mv");

m_program->bind();


glClearColor(0.25, 0.25, 0.25, 1.0);

setMouseTracking(false);

oview = QVector3D(0.0, 0.0, 0.0);

iview = QVector3D(1.0, 0.0, 0.0);
jview = QVector3D(0.0, 1.0, 0.0);
kview = QVector3D(0.0, 0.0, -1.0);

colorR = R / 255.0;
colorG = G / 255.0;
colorB = B / 255.0;

prepare_buffers();
}

void Model::paintGL()
{
m_program->setUniformValue(m_matProjUniform, mat_proj);
m_program->setUniformValue(m_matMvUniform, mat_modelview);


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

render_model_buffers();
}

void Model::resizeGL(int w, int h)
{
mat_proj.setToIdentity();
mat_proj.ortho(-1000, 1000, -1000, 1000, -1000, 1000);

glViewport(0, 0, w, h);
}
void Model::clear_buffers()
{
vlines.clear();
vtriangles.clear();
vquadtriangles.clear();

bctriangles.clear();
bcquadtriangles.clear();

clines.clear();
ctriangles.clear();
cquadtriangles.clear();
}

void Model::prepare_buffers_elements2D()
{
    using namespace lib::body;

    const Nodes& nodes = m_source->getNodes();
    const Elements2D& elements2D = m_source->getElements2D();

    float vbElem[4*3];
    float vbElem2[4*3];

    int numElementsTriThick = 0, numElementsQuadThick = 0;

    for (Elements2D::const_iterator it = elements2D.begin(); it != elements2D.end(); ++it)
    {
        const Id& id = elements2D.curId(it);

        const Element2D* pElement2D = elements2D.curDef(it);

        const ElemDef& elemDef = pElement2D->get();

        int i = 0;
        for (ElemDef::const_iterator it = elemDef.begin(); it != elemDef.end(); ++it)
        {
            const Id& id = *it;

            auto iter = nodes.getContainer().find(id);

            if (iter != nodes.getContainer().end())
            {
                Node* pNode = iter->second;

                vbElem[3*i + 0] = pNode->getCoordX();
                vbElem[3*i + 1] = pNode->getCoordY();
                vbElem[3*i + 2] = pNode->getCoordZ();
            }

            ++i;
        }
        if (pElement2D->getType() == ElementType::ELT_TRI)
        {
            for (int i = 0; i < 3; ++i)
            {
                // push vertex coords into vtriangles
                vtriangles.push_back(vbElem[3*i + 0]);
                vtriangles.push_back(vbElem[3*i + 1]);
                vtriangles.push_back(vbElem[3*i + 2]);

                // push color rgb into ctriangles
                ctriangles.push_back(colorR);
                ctriangles.push_back(colorG);
                ctriangles.push_back(colorB);

                // push barycentric coords into bctriangles
                QVector3D p(vbElem[3*( (i+0) % 3 ) + 0], vbElem[3*( (i+0) % 3 ) + 1], vbElem[3*( (i+0) % 3 ) + 2]);
                QVector3D v1(vbElem[3*( (i+1) % 3 ) + 0], vbElem[3*( (i+1) % 3 ) + 1], vbElem[3*( (i+1) % 3 ) + 2]);
                QVector3D v2(vbElem[3*( (i+2) % 3 ) + 0], vbElem[3*( (i+2) % 3 ) + 1], vbElem[3*( (i+2) % 3 ) + 2]);

                float h = p.distanceToLine(v1, v2-v1);

                for (int n = 0; n < i; ++n)
                {
                    bctriangles.push_back(0.0);
                }
                bctriangles.push_back(h);
                for (int n = 0; n < 2-i; ++n)
                {
                    bctriangles.push_back(0.0);
                }
            }
        }
        else if (pElement2D->getType() == ElementType::ELT_TRI_THICK)
        {
            ++numElementsTriThick;
        }
        else if (pElement2D->getType() == ElementType::ELT_QUAD)
        {
            int ii[3] = { 0, 1, 2};

            for (int tri = 0; tri < 2; ++tri)
            {
                for (int i = 0; i < 3; ++i)
                {
                    // push vertex coords into vquadtriangles
                    vquadtriangles.push_back(vbElem[3*ii[i] + 0]);
                    vquadtriangles.push_back(vbElem[3*ii[i] + 1]);
                    vquadtriangles.push_back(vbElem[3*ii[i] + 2]);

                    // push color rgb into cquadtriangles
                    cquadtriangles.push_back(colorR);
                    cquadtriangles.push_back(colorG);
                    cquadtriangles.push_back(colorB);

                    // push barycentric coords into bcquadtriangles
                    QVector3D p(vbElem[3*( ii[(i+0) % 3] ) + 0], vbElem[3*( ii[(i+0) % 3] ) + 1], vbElem[3*( ii[(i+0) % 3] ) + 2]);
                    QVector3D v1(vbElem[3*( ii[(i+1) % 3] ) + 0], vbElem[3*( ii[(i+1) % 3] ) + 1], vbElem[3*( ii[(i+1) % 3] ) + 2]);
                    QVector3D v2(vbElem[3*( ii[(i+2) % 3] ) + 0], vbElem[3*( ii[(i+2) % 3] ) + 1], vbElem[3*( ii[(i+2) % 3] ) + 2]);

                    float h = p.distanceToLine(v1, v2-v1);

                    for (int n = 0; n < i; ++n)
                    {
                        bcquadtriangles.push_back(0.0);
                    }
                    bcquadtriangles.push_back(h);
                    for (int n = 0; n < 2-i; ++n)
                    {
                        bcquadtriangles.push_back(0.0);
                    }
                }
                ii[0] = 2;
                ii[1] = 3;
                ii[2] = 0;
            }

        }
        else if (pElement2D->getType() == ElementType::ELT_QUAD_THICK)
        {
            ++numElementsQuadThick;
        }
    }
}
void Model::prepare_buffers()
{
prepare_buffers_elements2D();
}

void Model::render_model_buffers()
{
    m_program->enableAttributeArray(m_posAttr);
    m_program->enableAttributeArray(m_colAttr);

    m_program->setUniformValue(m_quadTri, 0);

    // render GL_LINES

    m_program->setAttributeArray(m_posAttr, GL_FLOAT, vlines.data(), 3);
    m_program->setAttributeArray(m_colAttr, GL_FLOAT, clines.data(), 3);

    std::vector<float>::size_type numLineVertices = vlines.size() / 3;
    glDrawArrays(GL_LINES, 0, numLineVertices);

    // render GL_TRIANGLES

    m_program->enableAttributeArray(m_barycentric);
    m_program->setAttributeArray(m_posAttr, GL_FLOAT, vtriangles.data(), 3);
    m_program->setAttributeArray(m_colAttr, GL_FLOAT, ctriangles.data(), 3);
    m_program->setAttributeArray(m_barycentric, GL_FLOAT, bctriangles.data(), 3);

    std::vector<float>::size_type numTriangleVertices = vtriangles.size() / 3;
    glDrawArrays(GL_TRIANGLES, 0, numTriangleVertices);

    m_program->disableAttributeArray(m_barycentric);

    // render GL_TRIANGLES for quads

    m_program->enableAttributeArray(m_barycentric);
    m_program->setAttributeArray(m_posAttr, GL_FLOAT, vquadtriangles.data(), 3);
    m_program->setAttributeArray(m_colAttr, GL_FLOAT, cquadtriangles.data(), 3);
    m_program->setAttributeArray(m_barycentric, GL_FLOAT, bcquadtriangles.data(), 3);
    m_program->setUniformValue(m_quadTri, 1);

    std::vector<float>::size_type numQuadTriangleVertices = vquadtriangles.size() / 3;
    glDrawArrays(GL_TRIANGLES, 0, numQuadTriangleVertices);

    m_program->disableAttributeArray(m_barycentric);



    // render wireframes in black
    m_program->disableAttributeArray(m_colAttr);
    m_program->disableAttributeArray(m_posAttr);
}

void Model::cleanup()
{
m_program->release();
delete m_program;
m_program = 0;
}
}
}

view.h

#include <QQuickItem>
#include "Hind.h"
#include "display.h"

namespace lib {
namespace mod {

class modd : public QQuickItem
{
Q_OBJECT

private:

lib::body::Bod* m_model;
lib::body::Source* m_source;
lib::Hind& context;

QSize m_viewportSize;

Model *modelDisplayGLWidget;

public:
modd();
~modd();

public slots:

void sync();
void paint();
void cleanup();

private slots:

void handleWindowChanged(QQuickWindow*);
};

}
}

view.cpp

#include <qquickwindow.h>
#include <qquickitem.h>
#include "modd.h"
#include "display.h"

namespace lib {
namespace mod {
using namespace std;

modd::modd() : m_model(0), m_source(0), context(lib::Hind::instance()), model(0)
{
    connect( this, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(handleWindowChanged(QQuickWindow*)) );

    m_model = &context.model();
    m_source = &(m_model->me());

     modelDisplayGLWidget = new Model;
     modelDisplayGLWidget->show();

}

modd::~modd()
{
    delete modelDisplayGLWidget;
}

void modd::sync()
{
    connect( window(), SIGNAL(beforeRendering()), this, SLOT(paint()), Qt::DirectConnection );
    m_viewportSize = window()->size() * window()->devicePixelRatio();

}

void modd::paint(){}

void modd::cleanup(){}

void modd::handleWindowChanged(QQuickWindow* win)
{
    if (win)
    {
        connect( win, SIGNAL(beforeSynchronizing()), this, SLOT(sync()), Qt::DirectConnection);
        connect(win, SIGNAL(sceneGraphInvalidated()), this, SLOT(cleanup()), Qt::DirectConnection);
    }
}
}
}

0 个答案:

没有答案