关于 QT 中的 QSGGeometryNode 和 WebAssembly

问题描述

我正在尝试使用 WebAssembly 在 Web 上部署我的项目,但遇到了一些问题。

该项目使用 QSGRenderNode 进行了自定义渲染并在网络上运行。

而且我收到错误“无效操作缓冲区大小不足”。

下面是我的代码

openglerenderer.h

#ifndef OPENglrENDERER_H
#define OPENglrENDERER_H

#include <qsgrendernode.h>
#include <QQuickItem>
#include "webaccess/render/baserender.h"

#if QT_CONfig(opengl)


class OpenglrenderNode : public QSGRenderNode
{
public:
    ~OpenglrenderNode();

    void render(const RenderState *state) override;
    void releaseResources() override;
    StateFlags changedStates() const override;
    RenderingFlags flags() const override;
    QRectF rect() const override;

    void sync(QQuickItem *item);

private:
    void init();
    int m_width = 0;
    int m_height = 0;
    bool beInit = false;
    BaseRender* m_render = nullptr;
};

#endif

#endif // OPENglrENDERER_H

openglerenderer.cpp

#include "openglrenderer.h"
#include <QQuickItem>

#if QT_CONfig(opengl)

#include <QOpenGLFunctions>
#include <QOpenGLExtraFunctions>
#include <QQuickWindow>

#include "webaccess/render/tutorial/les1.h"
#include "webaccess/render/tutorial/les2.h"
#include "webaccess/render/tutorial/les3.h"
#include "webaccess/render/tutorial/les4.h"

OpenglrenderNode::~OpenglrenderNode()
{
    releaseResources();
}

void OpenglrenderNode::releaseResources()
{
    if (m_render) {
        m_render->releaseResources();
    }
}

void OpenglrenderNode::init()
{
    if (m_render) {
        m_render->init();
        beInit = true;
    }
}

void OpenglrenderNode::render(const RenderState *state)
{
    if (!beInit)
        init();
    if (m_render) {
        m_render->render(state);
    }
}

QSGRenderNode::StateFlags OpenglrenderNode::changedStates() const
{
    return BlendState | ScissorState | stencilstate;
}

QSGRenderNode::RenderingFlags OpenglrenderNode::flags() const
{
    return BoundedRectRendering | DepthAwareRendering;
}

QRectF OpenglrenderNode::rect() const
{
    return QRect(0,m_width,m_height);
}

void OpenglrenderNode::sync(QQuickItem *item)
{
    m_width = static_cast<int>(item->width());
    m_height = static_cast<int>(item->height());
    if (!m_render) {
        m_render = static_cast<BaseRender*>(new les4{});
        if (m_render) {
            QObject::connect(item->window(),&QQuickWindow::beforeRendering,m_render,[&]() { m_render->beforeRender(); },Qt::DirectConnection);
        }
    }
    if (m_render) {
        m_render->sync(item);
        m_render->setViewportSize(item->size().toSize() * item->window()->devicePixelRatio());
        m_render->setPosition(item->position().toPoint());
        m_render->setwindow(item->window());
    }
}

#endif

les4.h

#ifndef LES4_H
#define LES4_H

#include "../baserender.h"

class QOpenGLTexture;
class QOpenGLShaderProgram;
class QOpenGLBuffer;
class QOpenGLVertexArrayObject;

class les4 : public BaseRender
{
public:
    les4();

    ~les4() override;
    virtual void init() override;
    virtual void render(const QSGRenderNode::RenderState *state) override;
    virtual void sync(QQuickItem *item) override;
    virtual void releaseResources() override;

    virtual void setViewportSize(QSize size) override { m_viewportSize = size; }
    virtual void setPosition(QPoint point) override { m_position = point; }
    virtual void setwindow(QQuickWindow* window) override { m_window = window; }
    virtual void beforeRender() override;

private:
    QSize m_viewportSize{};
    QPoint m_position{};
    QQuickWindow* m_window{};

    QOpenGLShaderProgram *m_program = nullptr;
    QOpenGLVertexArrayObject *m_vao = nullptr;
    QOpenGLBuffer *m_vbo = nullptr;
    QOpenGLBuffer *m_ibo = nullptr;

    int m_width = 0;
    int m_height = 0;
};

#endif // LES4_H

les4.cpp

#include "les4.h"
#include <QQuickWindow>
#include <QOpenGLContext>
#include <QOpenGLTexture>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLFunctions>
#include <QGuiApplication>

static const char *vertexShaderSource =
        "#version 100\n"
        "attribute vec3 aPos;\n"
        "attribute vec3 aColor;\n"
        "varying vec3 ourColor;\n"
        "void main() {\n"
        "   gl_Position = vec4(aPos.xyz,1.0);\n"
        "   ourColor = aColor;\n"
        "}";

static const char *fragmentShaderSource =
        "#version 100\n"
#if defined(Q_OS_HTML5) or defined(Q_OS_WASM) or defined(__EMSCRIPTEN__)
        "precision mediump float;\n"
#endif
        "varying vec3 ourColor;\n"
        "void main() {\n"
        "   gl_FragColor = vec4(ourColor,1.0);\n"
        "}";

static float vertices[] {
    // 位置              // 顏色
     0.5f,-0.5f,0.0f,1.0f,// 右下
    -0.5f,// 左下
     0.0f,0.5f,1.0f    // 頂部
};

static unsigned int indices[] {
    0,1,2
};

les4::les4()
{

}

les4::~les4()
{

}

void les4::init() {
    QSurfaceFormat fmt;
    fmt.setVersion(2,0);
    fmt.setRenderableType(QSurfaceFormat::OpenGLES);
    fmt.setMajorVersion(2);
    fmt.setMinorVersion(0);
    fmt.setRedBufferSize(5);
    fmt.setGreenBufferSize(6);
    fmt.setBlueBufferSize(5);
    fmt.setAlphaBufferSize(0);
    fmt.setDepthBufferSize(0);

    QSurfaceFormat::setDefaultFormat(fmt);

    QOpenGLContext *ctx = QOpenGLContext::currentContext();
    ctx->setFormat(fmt);
}

void les4::releaseResources() {
    delete m_program;
    m_program = nullptr;

    delete m_vbo;
    m_vbo = nullptr;

    delete m_ibo;
    m_ibo = nullptr;

    delete m_vao;
    m_vao = nullptr;
}

void les4::beforeRender() {

}

void les4::render(const QSGRenderNode::RenderState*) {

    QOpenGLContext *ctx = QOpenGLContext::currentContext();

#if defined(Q_OS_HTML5) or defined(Q_OS_WASM) or defined(__EMSCRIPTEN__)
const bool iscoreProfile  = false;
#else
const bool iscoreProfile  = ctx->format().profile() == QSurfaceFormat::CoreProfile;
#endif

    QOpenGLFunctions *f = ctx->functions();

    int y = (m_window->size()* m_window->devicePixelRatio()).height() - m_viewportSize.height() - m_position.y();
    f->glViewport(m_position.x(),y,m_viewportSize.width(),m_viewportSize.height());
    f->glClearColor(0.2f,0.3f,1.0f);
    f->glClear(GL_COLOR_BUFFER_BIT);

    auto setupVertAttrs = [this,f] {
        m_vbo->bind();
        f->glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,6*sizeof(float),(void*)0);
        f->glVertexAttribPointer(1,(void*)(3*sizeof(float)));
        f->glEnabLevertexAttribArray(0);
        f->glEnabLevertexAttribArray(1);
    };

    if (!m_program) {
        m_program = new QOpenGLShaderProgram;
        m_program->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex,vertexShaderSource);
        m_program->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment,fragmentShaderSource);
        m_program->bindAttributeLocation("aPos",0);
        m_program->bindAttributeLocation("aColor",1);
        m_program->link();

        m_vao = new QOpenGLVertexArrayObject;
        m_vao->create();

        m_vbo = new QOpenGLBuffer;
        m_vbo->create();

        m_ibo = new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer);
        m_ibo->create();
    }

    // non-premultiplied alpha
    f->glEnable(GL_BLEND);
    f->glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    // no backface culling
    f->gldisable(GL_CULL_FACE);
    // still need depth test to test against the items rendered in the opaque pass
    f->glEnable(GL_DEPTH_TEST);
    // but no need to write out anything to the depth buffer
    f->glDepthMask(GL_FALSE);
    // do not write out alpha
    f->glColorMask(GL_TRUE,GL_TRUE,GL_FALSE);
    // will always scissor
    f->glEnable(GL_SCISSOR_TEST);

    if (m_vao->isCreated())
        m_vao->bind();

    m_program->bind();

    m_vbo->bind();
    m_vbo->allocate(vertices,sizeof(vertices));
    m_ibo->bind();
    m_ibo->allocate(indices,sizeof(indices));

    setupVertAttrs();

    //scissor...
    //texture...
    f->glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,nullptr);
    f->glColorMask(GL_TRUE,GL_TRUE);
}

void les4::sync(QQuickItem *item) {
  //  qDebug() << "w:" << item->width() << " h:" << item->height();
    m_width = static_cast<int>(item->width());
    m_height = static_cast<int>(item->height());
}

请帮帮我。我被困在这里很长时间了。

解决方法

我想出了解决办法。 首先,我的元素中应该有三个索引。 函数 glDrawElements 的第二个参数应该是 3。 其次,webgl 有一个限制,即元素的类型应该是 GL_UNSIGNED_SHORT。