用于 WebGL 的 C++ 和 Javascript 之间的通信
Posted
技术标签:
【中文标题】用于 WebGL 的 C++ 和 Javascript 之间的通信【英文标题】:Communication between C++ and Javascript for WebGL 【发布时间】:2016-04-11 09:10:49 【问题描述】:我和我的朋友正在尝试在 C++ 和 javascript 之间进行交流。 我们希望使用嵌入在 C++/Qt(5.6 版)应用程序中的 WebGL 在给定位置渲染一些球体。
为此,我们使用QWebView
读取包含所有WebGL JS 代码的html 文件。这很好用,我们的应用程序中有一个很棒的高级 3D 渲染器。 问题在于 C++ 知道该位置,并且必须将其共享给 JavaScript。
更准确地说,C++ 知道我们需要显示的球体数量及其位置,并且必须将其告知 Javascript 端。最好的方法是什么?
注意:我们尝试使用 Qt Canvas3D,但与经典的 WebGL 相比它太慢了。
编辑 1 - 第一次尝试后
我尝试按照您写的内容进行操作,还阅读了一些示例(例如 one),但无法实现。
我创建了 QWebEngineView 的一个子类,我在其中进行所有初始化并放置我的数据。
.h:
#ifndef WEBGLVIEW_H
#define WEBGLVIEW_H
#include <QObject>
#include <QtWebEngineWidgets>
#include <QtWebChannel/QtWebChannel>
class WebGLView : public QWebEngineView
Q_OBJECT
Q_INVOKABLE int getNumber();
Q_PROPERTY(int num READ getNumber)
public:
WebGLView(QWidget *parent = 0);
private :
QWebChannel* m_channel;
;
#endif // WEBGLVIEW_H
.cpp:
#include "WebGLView.h"
#include <QCoreApplication>
#include <QUrl>
#include <QDebug>
WebGLView::WebGLView(QWidget *parent) :
QWebEngineView(parent)
// Set up the communications channel
//C++ to Java test
m_channel = new QWebChannel(this);
this->page()->setWebChannel(m_channel);
m_channel->registerObject(QString("test"),this);
QString path = QCoreApplication::applicationDirPath() + "/test6.html";
this->setUrl(QUrl::fromLocalFile(path));
int WebGLView::getNumber()
qDebug() << "getNumber";
return 10;
在JS的开头:
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
...
var JSobject;
if (typeof qt != 'undefined') new QWebChannel(qt.webChannelTransport, function(channel)
JSobject = channel.objects.test;
);
当我想访问值时:
if (typeof widget !== 'undefined')
var nspherefromc = JSobject.getNumber;
else var nspherefromc = 50;
当我运行它时:
getNumber 被调用一次,似乎是在调用 QWebChannel 之后出现的 我有警告:对象 'WebGLView' 的属性 'num'' 没有通知信号并且不是常量,HTML 中的值更新将被破坏! nspherefromc 是要显示的球体数量。显示 50 个,而不是 10 个。有什么想法吗?
编辑 2 - 第二次尝试
我仍然无法让它工作。 我尝试添加一个名为 more 的新变量,以查看是否调用了函数或输入了 if 语句:
var more = 0;
if (typeof qt != 'undefined')
new QWebChannel(qt.webChannelTransport, function(channel)
JSobject = channel.objects.test;
more = 1000;
);
我还有:
if (typeof JSobject !== 'undefined')
nspherefromc = JSobject.num;
else nspherefromc = 50;
...
var spheresNum = nspherefromc + more;//Number of Spheres
运行它时,我只有 50 个球体。 QWebChannel 中的函数没有被调用。我应该自己称呼它吗?什么时候 ? 我还尝试了 if(typeof qt != 'undefined') 语句中的更多调试,我得到了 1050 个球体。
编辑 3 - 使用 HTML 调试器
function init()
var JSobject;
var nspherefromc = 0;
if (typeof qt !== 'undefined')
new QWebChannel(qt.webChannelTransport, function(channel)
JSobject = channel.objects.test;
console.log(JSobject); //-> returns the object, I can access the functions and everything
nspherefromc = JSobject.num;
console.log("in the function " + nspherefromc); //prints 5000, what i sent from C++
more = 1000;
);
console.log(JSobject); // prints undefined
console.log(JSobject); // prints undefined
if (typeof JSobject !== 'undefined')
console.log("Yeaaaah"); //Not reached
nspherefromc = JSobject.num;
nspherefromc + 1;
...
console.log("when loading " + nspherefromc + " (more is = to " + more); // nsphere = 0 , more = 0
var spheresNum = nspherefromc + more;
这意味着在函数之外我无法再访问 JSobject。你知道为什么吗?
编辑 - 最后 当接收到来自 C++ 的数据时,openGL 已经初始化。因此,显示的球体数量不是 C++ 要求的。
【问题讨论】:
什么版本的 Qt ? Qt 5.6。感谢您的提问,我在说明中添加了它。 我在您编辑后编辑了我的答案。 从您的编辑号 3 开始:尝试在函数init()
之外定义 var JSobject
在将其放入 init() 之前也尝试过。结果一样...
【参考方案1】:
在 Qt5.6 中,如果你想让 C++ 部分和 JavaScript 进行通信,唯一的方法是在 QWebEngineView 上使用 QWebChannel。你在.cpp
文件中这样做:
m_pView = new QWebEngineView(this);
QWebChannel * channel = new QWebChannel(page);
m_pView->page()->setWebChannel(channel);
channel->registerObject(QString("TheNameOfTheObjectUsed"), this);
在这里,您只是说您注册了一个名为 TheNameOfTheObjectUsed
的对象,该对象将在 JS 端可用。现在,这是在 JS 端使用的代码部分:
new QWebChannel(qt.webChannelTransport, function (channel)
// now you retrieve your object
var JSobject = channel.objects.TheNameOfTheObjectUsed;
);
在你的情况下,你想要检索球体的数量、一些位置等。所以你需要在 C++ 端有一个方法,它返回一个字符串、一个整数、一个长整数......这就是它看起来像在 C++ 方面,在你的 .h
:
Q_INVOKABLE int getNumberOfSpheres();
Q_PROPERTY(int NumberOfSpheres READ getNumberOfSpheres);
现在,您可以在 JS 端获得这样的球体数量:
var nbSpheres = JSobject.NumberOfSpheres;
这是一个非常简单的解释,我建议您观看this video,这对我非常有用。另外,您可能想阅读更多关于 QWebChannel 提供的JavaScript API 以及关于QWebChannel 的文档;
希望有帮助!
修改后 1
在您的 .h 中,您需要添加(或更改):
int m_pNumber;
Q_PROPERTY(int num READ getNumber WRITE setNumber NOTIFY numChanged)
Q_INVOKABLE void setNumber(int number); // add this function to the cpp file as well
//add a signal for NOTIFY
signals:
void numChanged();
public slots:
void numHasChanged();
在 .cpp 的构造函数中:
connect(this, SIGNAL(numChanged()), this, SLOT(numHasChanged()));
在 cpp 本身中:
void WebGLView::setNumber(int number)
m_pNumber = number;
emit numChanged();
int WebGLView::getNumber()
return m_pNumber;
void WebGLView::numHasChanged()
// do anything here
在 JS 方面非常重要:
首先,请注意,您复制了一些代码而没有检查它,所以我认为您的意思是:
if (typeof JSobject !== 'undefined')
而不是
if (typeof widget !== 'undefined')
然后:
var nspherefromc = JSobject.num; // this is ok
var nspherefromc = JSobject.getNumber; // this is NOT ok
现在,每当您在 JS 中更改变量 num
时,都会发出一个信号 (numChanged
),您将能够通过 getNumber()
获取相应插槽中的值。
【讨论】:
这很有帮助!谢谢 !我开始看视频,现在我要试一试。再次感谢:) 很高兴为您提供帮助 :) 如果您在尝试时有任何其他问题,请不要犹豫! 我正在阻止...我确实像你一样,我什至阅读了其他有效的示例,但我仍然遇到问题。我该怎么做才能向您显示更多代码?评论或编辑? 嗯,只需使用您目前尝试过的内容编辑您的帖子(因为您需要 20 个代表在聊天中交谈) 感谢您的回答 :) 我现在正在尝试。快速提问:如果我们已经有了 Q_PROPERTY 编号,为什么还需要 m_pNumber?以上是关于用于 WebGL 的 C++ 和 Javascript 之间的通信的主要内容,如果未能解决你的问题,请参考以下文章
是否有用于 webgl 的 2d sprite 库? [关闭]