我正在尝试使用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);
}
}
}
}