用于 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 库? [关闭]

将 YouTube 视频用于 webgl 纹理?

用于 Unity 和虚幻引擎的 Asm.js 与 WebGL

用于 webGL 的 Blender 到 json

虚拟互动WebGL平台的应用前景和导出方法

webgl核心要素