我读的书愈多,就愈亲近世界,愈明了生活的意义,愈觉得生活的重要。 —— 高尔基


需要先看:https://blog.csdn.net/qq_35865125/article/details/86485008 来理解qt quick场景图的渲染过程。以下内容主要来自http://doc.qt.io/qt-5/qtquick-visualcanvas-scenegraph.html , 并结合了自己的理解和实践。

Qt的场景图提供了两种方式来让用户实现与OpengGL的结合。一是,直接调用OpenGL命令函数,二是,在场景图中创建textured node。

QquickWindow类负责将qml文件中的内容渲染到屏幕上,在渲染过程中,会从渲染线程中发出信号:QQuickWindow::beforeRendering() and QQuickWindow::afterRendering(),用户可以接受这些信号,并在其他线程中执行调用OpenGl的原始函数的操作,来绘制一些东东,如果用户使用的是第一个信号,用户用opengl画出的东东会在qml场景的下面,否则会在上面。 这种方式的好处是不需要二外的framebuffer或内存。缺点是,“The downside is that Qt Quick decides when to call the signals and this is the only time the OpenGL application is allowed to draw。”。这种方法的一个官方的例子: Scene Graph - OpenGL Under QML

另一种方法:The other alternative is to create a QQuickFramebufferObject, render into it, and let it be displayed in the scene graph as a texture. The Scene Graph - Rendering FBOs example shows how this can be done. It is also possible to combine multiple rendering contexts and multiple threads to create content to be displayed in the scene graph. The Scene Graph - Rendering FBOs in a thread examples show how this can be done.

注意: When mixing OpenGL content with scene graph rendering, it is important the application does not leave the OpenGL context in a state with buffers bound, attributes enabled, special values in the z-buffer or stencil-buffer or similar. Doing so can result in unpredictable behavior.

注意: The OpenGL rendering code must be thread aware, as the rendering might be happening outside the GUI thread.

用上面提到的第一种方法时,需要注意:

1)需要在.pro文件中添加:

LIBS += -lglut

LIBS += -lGLU

需要在系统中安装opengl。

2) 需要在main中调用glutInit( &argc, argv );(#include <GL/glut.h>)。

3)资源回收问题:有必要详细了解QQuickWindow这个类。http://doc.qt.io/qt-5/qquickwindow.html

上图中,标出红线的部分我曾经使用过。类似后面我给出的例子,不同之处:我将写的qml文件传递给一个QquickView,在绘制出opengl图像后,调用QquckView的hide函数隐藏整个quickview。在一些性能较低的机器人上运行调用hide函数时,会遇到界面卡死问题。或许可以通过上图中提到的Resource Management部分的方法解决。

My example(调用opengl画一个箭头):---基于官方例子Scene Graph - OpenGL Under QML

自定义类的.h:

#ifndef SELFDEFSUBITEM_H
#define SELFDEFSUBITEM_H #include <QObject>
#include <QQuickItem>
#include <QtGui/QOpenGLFunctions> class MyRenderer : public QObject, protected QOpenGLFunctions
{
Q_OBJECT
public:
MyRenderer() ;
~MyRenderer(); void setViewportSize(const QSize &size);
void setWindow(QQuickWindow *window); void Init_Before_Paint_arm3d();
void Paint_Line(); void DrawLine(); public slots:
void paint(); private:
QSize m_viewportSize;
QQuickWindow *m_window; }; class SelfDefSubItem : public QQuickItem
{
Q_OBJECT public:
SelfDefSubItem();
~SelfDefSubItem(); static float x_rot,y_rot,z_rot;
static float zoomscale;
static float x_trans, y_trans; public slots:
void sync();
void cleanup(); private slots:
void handleWindowChanged(QQuickWindow *win); protected: private:
MyRenderer *m_renderer; }; #endif // SELFDEFSUBITEM_H

自定义类的cpp:

#include "SelfDefSubItem.h"
#include <QtQuick/qquickwindow.h>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLContext>
#include <GL/glut.h>
#include <GL/glu.h>
#include <GL/gl.h> #include "stdio.h"
#include <fstream>
#include <iostream>
#include <string>
#include<vector> using namespace std; float SelfDefSubItem::x_rot=0.0;float SelfDefSubItem::y_rot=0.0;float SelfDefSubItem::z_rot=0.0; float SelfDefSubItem::zoomscale=1.0;
float SelfDefSubItem::x_trans = 0;
float SelfDefSubItem::y_trans = 0; SelfDefSubItem::SelfDefSubItem()
{
connect(this, &QQuickItem::windowChanged, this, &SelfDefSubItem::handleWindowChanged);
}
SelfDefSubItem::~SelfDefSubItem()
{
cleanup();
} void SelfDefSubItem::cleanup()
{
if (m_renderer)
{
delete m_renderer;
m_renderer = 0;
}
} void SelfDefSubItem::sync()
{
if (!m_renderer)
{
m_renderer = new MyRenderer();
connect(window(), &QQuickWindow::beforeRendering, m_renderer, &MyRenderer::paint, Qt::DirectConnection);
//connect(window(), &QQuickWindow::afterRendering, m_renderer, &SquircleRenderer::paint, Qt::DirectConnection);
}
m_renderer->setViewportSize(window()->size() * window()->devicePixelRatio());//
m_renderer->setWindow(window());
}
void SelfDefSubItem::handleWindowChanged(QQuickWindow *win)
{
if (win)
{
connect(win, &QQuickWindow::beforeSynchronizing, this, &SelfDefSubItem::sync, Qt::DirectConnection);
connect(win, &QQuickWindow::sceneGraphInvalidated, this, &SelfDefSubItem::cleanup, Qt::DirectConnection);
// If we allow QML to do the clearing, they would clear what we paint
// and nothing would show.
win->setClearBeforeRendering(false);
}
} ///////////////////////////////////////////
MyRenderer::MyRenderer()
{ }
void MyRenderer::paint()
{
m_window->resetOpenGLState();
initializeOpenGLFunctions();
glViewport(0, 0, m_viewportSize.width(), m_viewportSize.height());
Paint_Line();
} void MyRenderer::DrawLine()
{
int len = 750;
GLfloat mat_ambient_axis1[4] = { 0.8, 0, 0, 1.0 };
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_axis1);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_ambient_axis1); glLineWidth(18);//设置线段宽度 glPushMatrix();
glBegin(GL_LINES);
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(0.0, 0.0, len);
glEnd(); glTranslated(0.0, 0.0, len - 13); glutWireCone(16, 37, 31, 32);//void glutWireCone(GLdouble radius, GLdouble height, GLint slices, GLint stacks); 线框 圆锥体
glPopMatrix();
} void MyRenderer::Init_Before_Paint_arm3d()
{
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); //*****Defining Position and Colors for a Light Source*****:
GLfloat light_position[] = { 1.0, 10.0, 0.0, 0.0 };
GLfloat light_ambient[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
glLightfv(GL_LIGHT0, GL_POSITION, light_position); //specify the location of lighter
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); //specify light0's ambient color
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); //specify light0's diffuse color
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); //specify light0's specular color //glClearColor(1, 1, 1, 1.0);//specify the backgroud color!
glClearColor(7/255, 7/255, 18/255, 1.0);//specify the backgroud color! glShadeModel(GL_SMOOTH); GLfloat lmodel_ambient[] = { 0.4, 0.4, 0.3, 1.0 };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1100.0,1200.0, -1100.0, 1100.0, -1100, 1100);
glPointSize(1); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); gluLookAt(8.3, 1.56, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glScalef (SelfDefSubItem::zoomscale, SelfDefSubItem::zoomscale, SelfDefSubItem::zoomscale);//scaling in 3 direction
} void MyRenderer::Paint_Line()
{
initializeOpenGLFunctions();
Init_Before_Paint_arm3d(); DrawLine();//Call raw OpenGl command!
} MyRenderer::~MyRenderer()
{
//delete m_program;
} void MyRenderer::setViewportSize(const QSize &size)
{
m_viewportSize = size;
} void MyRenderer::setWindow(QQuickWindow *window)
{
m_window = window;
}

main.qml

import QtQuick 2.11
import QtQuick.Window 2.11
import SelfDefSubItem 1.0 Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World") SelfDefSubItem{
id:selfdef
}
}

几个注意的地方:

  1. connect(window(), &QQuickWindow::beforeRendering, m_renderer, &MyRenderer::paint, Qt::DirectConnection);

执行程序时,MyRenderer::paint函数会被执行好几次!!可能在渲染线程中会发出多个QQuickWindow::beforeRendering信号,具体过程尚未知道,需要进一步查资料,看qt公司的人怎么想的。

connect(this, &QQuickItem::windowChanged, this, &Arm3d::handleWindowChanged);

QQuickWindow负责将qml场景渲染出来,用户自己写的qml文件必须依附于它才能被渲染。QquickItem::window函数返回QquickItem自己所依附的那个QuickWindow。

Qt5 QtQuick系列----QtQuick的Secne Graph剖析(3)-- qml与OpenGl结合的更多相关文章

  1. Qt5 QtQuick系列----QtQuick的Secne Graph剖析(1)

    教是言词, 实不是道,道本无言, 言说是妄.------- 达摩 Qt 5提出了一个新的渲染底层,以替代Qt4时期的Graphics View,这个渲染底层就是Scene Graph.Scene Gr ...

  2. Qt5 QtQuick系列----QtQuick的Secne Graph剖析(2)--自定义QML类型 (继承QQuickItem)

    "当下即永恒"  --- 佚名 Qt用户可以方便地使用QML中的Rectangle等基本类型,但是当不够用时,或,需要开发更高级的界面时,可以自己定义QML类型. 自定义QML类型 ...

  3. 【java集合框架源码剖析系列】java源码剖析之TreeSet

    本博客将从源码的角度带领大家学习TreeSet相关的知识. 一TreeSet类的定义: public class TreeSet<E> extends AbstractSet<E&g ...

  4. 【java集合框架源码剖析系列】java源码剖析之HashSet

    注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本.本博客将从源码角度带领大家学习关于HashSet的知识. 一HashSet的定义: public class HashSet&l ...

  5. 【java集合框架源码剖析系列】java源码剖析之TreeMap

    注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本.本博客将从源码角度带领大家学习关于TreeMap的知识. 一TreeMap的定义: public class TreeMap&l ...

  6. 【java集合框架源码剖析系列】java源码剖析之ArrayList

    注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本. 本博客将从源码角度带领大家学习关于ArrayList的知识. 一ArrayList类的定义: public class Arr ...

  7. 【java集合框架源码剖析系列】java源码剖析之LinkedList

    注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本. 在实际项目中LinkedList也是使用频率非常高的一种集合,本博客将从源码角度带领大家学习关于LinkedList的知识. ...

  8. 【java集合框架源码剖析系列】java源码剖析之HashMap

    前言:之所以打算写java集合框架源码剖析系列博客是因为自己反思了一下阿里内推一面的失败(估计没过,因为写此博客已距阿里巴巴一面一个星期),当时面试完之后感觉自己回答的挺好的,而且据面试官最后说的这几 ...

  9. NetworkX系列教程(1)-创建graph

    小书匠Graph图论 研究中经常涉及到图论的相关知识,而且常常面对某些术语时,根本不知道在说什么.前不久接触了NetworkX这个graph处理工具,发现这个工具已经解决绝大部分的图论问题(也许只是我 ...

随机推荐

  1. Vue --- 项目创建

    目录 创建Vue项目之前的准备 创建Vue项目 重新构建项目 项目目录介绍 项目的生命周期 Vue文件式组件 配置自定义全局样式 路由逻辑跳转 生命周期钩子 路由传参的两种方式 创建Vue项目之前的准 ...

  2. LeetCode 785. Is Graph Bipartite?

    原题链接在这里:https://leetcode.com/problems/is-graph-bipartite/ 题目: Given an undirected graph, return true ...

  3. mysql ERROR 1862 (HY000): 密码超时错误解决 Your password has expired.To log in you must change it using a client that supports expired password

    工具链接可能报错,使用黑窗口链接后: 1. SET PASSWORD = PASSWORD("xinmima"); 2. flush privileges; 使用新密码链接即可.

  4. C# list常用的几个操作 改变list中某个元素的值 替换某一段数据

    1.改变list中某个元素的值 public class tb_SensorRecordModel { public int ID { get; set; } public decimal Value ...

  5. vue-cli3 ios10白屏问题解决思路

    在出现了这个问题之后先不要盲目的去瞎试,根据网上的方法试了个遍也没解决问题 先看报的是什么错,再针对的解决问题 首先出现的报错是 SyntaxError: Unexpected token '*'  ...

  6. javascript巧用注释保存html文本结构

    在js中,肯定会遇到js代码里面有html接口的时候,骚年们都有哪些写法? 刚学JS的写法: <script> var strHtml="<div id=\"te ...

  7. 在GitHub上使用Hexo 搭建自己的博客

    1.下载Node.js安装文件(现在电脑基本都是64位的,我就放64位的下载地址):https://nodejs.org/dist/v8.9.4/node-v8.9.4-x64.msi 或者自行到官网 ...

  8. vue+element 表格导出Excel文件

    https://www.cnblogs.com/bobodeboke/p/8867481.html  非常感谢 这个大佬 才让我搞到了Blob.js 和 Export2Excel.js 如果最后运行时 ...

  9. 程序日志-应用程序-特定 权限设置并未向在应用程序容器 不可用 SID (不可用)中运行的地址 LocalHost (使用 LRPC) 中的用户 NT AUTHORITY\SYSTEM SID (S-1-5-18)授予针对 CLSID 为 {D63B10C5-BB46-4990-A94F-E40B9D520

    应用程序-特定 权限设置并未向在应用程序容器 不可用 SID (不可用)中运行的地址 LocalHost (使用 LRPC) 中的用户 NT AUTHORITY\SYSTEM SID (S-1-5-1 ...

  10. ICEM-带柱底座

    原视频下载地址:https://pan.baidu.com/s/1c2KgCBA 密码: ixk8