C++ 和 Javascript for WebGL 之间的通信

Communication between C++ and Javascript for WebGL

我和我的朋友正在尝试在 C++ 和 Javascript 之间进行通信。 我们想在给定位置渲染一些球体,并在 C++/Qt(5.6 版)应用程序中嵌入 WebGL。

为此,我们使用 QWebView 读取 HTML 文件,其中包含 WebGL 的所有 JS 代码。这很好用,我们的应用程序中有一个很棒的高级 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;}

当我运行它时:

有什么想法吗?

编辑 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') sttement 中尝试了更多调试,我得到了 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++ 要求的数量。

在Qt5.6中,如果要让C++部分和JavaScript通信,只能使用QWebChannel on a QWebEngineView。你在 .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++ 端有一个方法,其中 returns 一个字符串、一个整数、一个长整数。 .. 这就是 C++ 端的样子,在你的 .h:

Q_INVOKABLE int getNumberOfSpheres();
Q_PROPERTY(int NumberOfSpheres READ getNumberOfSpheres);

现在,您在 JS 端获得了这样的球体数量:

var nbSpheres = JSobject.NumberOfSpheres;

这是一个很简单的讲解,推荐大家观看this video which was very useful to me. Also, you might want to read more about the JavaScript API provided by QWebChannel, as well as the documentation about 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()