簡體   English   中英

Qt3D 幾何着色器在 QML 但不在 C++ 中工作

[英]Qt3D geometry shader working in QML but not in C++

更新

根據以下代碼,OpenGL 版本似乎至少是 4.3

QSurfaceFormat format = view.format();
int major = format.majorVersion();
int minor = format.minorVersion();

所以幾何着色器應該可以工作,問題似乎是別的。



原始問題

在嘗試回答與如何在 Qt3D 中創建廣告牌相關的問題時,我遇到了一個我找不到解決方案的問題。

我使用了GitHub 存儲庫中的代碼,其中包含 C++ 和 QML。 它完美地工作並展示了如何在 Qt3D 中實現廣告牌 - 至少在使用 QML 時。 這是代碼的屏幕截圖:

在此處輸入圖像描述


Now, the person asking the question I mentioned needs it to be in C++ so I tried to translate it since every QML class has a corresponding C++ class. 我只是在某種程度上成功了。 原始代碼使用幾何着色器來創建廣告牌。 當我不包括着色器的幾何部分時,我設法用這樣的預定義顏色在屏幕上繪制各個點(我圈出了這些點,以便您可以更好地看到它們):

在此處輸入圖像描述

但是一旦我包含幾何着色器,所有的點都會消失。 但是這個精確的着色器在 QML 下工作。

我將其歸結為幾何着色器是問題所在,因為當我將其注釋掉時,我得到了白點,但是當我添加它時,這些點不再顯示(顯然廣告牌也不是):

billboardShaderProgram->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl("qrc:/shaders/billboards.vert")));
//billboardShaderProgram->setGeometryShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl("qrc:/shaders/billboards.geom")));
billboardShaderProgram->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl("qrc:/shaders/billboards.frag")));

在檢查了 OpenGL 版本(似乎是 4.3)之后,問題一定是我如何在 C++ 中創建對象的其他問題。



代碼


您可以在 GitHub 上找到該項目。


或者,我將在此處添加相關類並盡量將它們保持在最低限度。

main.cpp

// Includes for framegraph
#include <Qt3DExtras/Qt3DWindow>
#include <Qt3DRender/QFrameGraphNode>
#include <Qt3DRender/QRenderSurfaceSelector>
#include <Qt3DRender/QViewport>
#include <Qt3DRender/QCameraSelector>
#include <Qt3DRender/QCamera>
#include <Qt3DRender/QCameraLens>
#include <Qt3DRender/QClearBuffers>
#include <Qt3DExtras/QForwardRenderer>

#include <Qt3DExtras/QFirstPersonCameraController>
#include <Qt3DInput/QInputSettings>

#include <Qt3DCore/QEntity>
#include <Qt3DExtras/QPlaneMesh>
#include <Qt3DExtras/QPhongMaterial>
#include <Qt3DRender/QGeometryRenderer>
#include <Qt3DCore/QTransform>
#include <Qt3DRender/QMaterial>
#include <Qt3DRender/QParameter>
#include <Qt3DRender/QTexture>
#include <Qt3DRender/QTextureImage>
#include <Qt3DRender/QEffect>
#include <Qt3DRender/QTechnique>
#include <Qt3DRender/QRenderPass>
#include <Qt3DRender/QShaderProgram>
#include <Qt3DExtras/QSphereMesh>
#include <Qt3DExtras/QCuboidMesh>
#include <Qt3DRender/QGraphicsApiFilter>
#include <Qt3DExtras/QTextureMaterial>

#include <QSurfaceFormat>

#include <QVector3D>
#include <QColor>

#include <QGuiApplication>

#include "billboardgeometry.h"

#include <QOpenGLContext>

Qt3DExtras::QFirstPersonCameraController * cameraController;

int windowWidth = 1600;
int windowHeight = 800;

Qt3DCore::QEntity *createScene() {
    Qt3DCore::QEntity *root = new Qt3DCore::QEntity();

    cameraController = new Qt3DExtras::QFirstPersonCameraController(root);

    // Add plane
    Qt3DCore::QEntity *planeEntity = new Qt3DCore::QEntity(root);
    Qt3DExtras::QPlaneMesh *planeMesh = new Qt3DExtras::QPlaneMesh(planeEntity);
    planeMesh->setWidth(20);
    planeMesh->setHeight(20);
    Qt3DExtras::QPhongMaterial *planeMaterial = new Qt3DExtras::QPhongMaterial(planeEntity);
    planeMaterial->setAmbient(QColor(0, 0, 0.7 * 255, 0.1 * 255));
    planeEntity->addComponent(planeMesh);
    planeEntity->addComponent(planeMaterial);

    // Add sphere
    Qt3DCore::QEntity *sphereEntity = new Qt3DCore::QEntity(root);
    Qt3DExtras::QSphereMesh *sphereMesh = new Qt3DExtras::QSphereMesh(sphereEntity);
    Qt3DExtras::QPhongMaterial *sphereMaterial = new Qt3DExtras::QPhongMaterial(sphereEntity);
    sphereMaterial->setAmbient(Qt::red);
    Qt3DCore::QTransform *sphereTransform = new Qt3DCore::QTransform(sphereEntity);
    sphereTransform->setTranslation(QVector3D(0., 5., 0.));
    sphereEntity->addComponent(sphereMesh);
    sphereEntity->addComponent(sphereMaterial);
    sphereEntity->addComponent(sphereTransform);

    // Add cube
    Qt3DCore::QEntity *cubeEntity = new Qt3DCore::QEntity(root);
    Qt3DExtras::QCuboidMesh *cubeMesh = new Qt3DExtras::QCuboidMesh(cubeEntity);
    Qt3DExtras::QPhongMaterial *cubeMaterial = new Qt3DExtras::QPhongMaterial(cubeEntity);
    cubeMaterial->setAmbient(Qt::gray);
    Qt3DCore::QTransform *cubeTransform = new Qt3DCore::QTransform();
    cubeTransform->setTranslation(QVector3D(2., 2., 5.));
    cubeEntity->addComponent(cubeMesh);
    cubeEntity->addComponent(cubeMaterial);
    cubeEntity->addComponent(cubeTransform);

    // Add Billboard
    Qt3DCore::QEntity *billboardEntity = new Qt3DCore::QEntity(root);

    // Create billboard geometry
    QVector<QVector3D> pos;
    pos << QVector3D(1, 1, 0);
    pos << QVector3D(-1, 2, 8);
    pos << QVector3D(1, 1, 7);
    pos << QVector3D(0, 0, 4);
    BillboardGeometry *billboardGeometry = new BillboardGeometry(billboardEntity);
    billboardGeometry->setPoints(pos);
    Qt3DRender::QGeometryRenderer *billboardRenderer = new Qt3DRender::QGeometryRenderer(billboardEntity);
    billboardRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Points);
    billboardRenderer->setGeometry(billboardGeometry);
    billboardRenderer->setVertexCount(billboardGeometry->count());

    Qt3DCore::QTransform *billboardTransform = new Qt3DCore::QTransform(billboardEntity);
    billboardTransform->setTranslation(QVector3D(0., 1.5, 0.));

    // Billboard material

    // Image of billboard material
    Qt3DRender::QMaterial *billboardMaterial = new Qt3DRender::QMaterial(billboardEntity);
    Qt3DRender::QTexture2D* texture = new Qt3DRender::QTexture2D();
    Qt3DRender::QTextureImage* textureImage = new Qt3DRender::QTextureImage(texture);
    textureImage->setSource(QUrl(QStringLiteral("qrc:/success-kid.png")));
    texture->addTextureImage(textureImage);

    // Parameters of billboard material
    Qt3DRender::QParameter* billboardParam1 = new Qt3DRender::QParameter(QStringLiteral("tex0"), texture);
    Qt3DRender::QParameter* billboardParam2 = new Qt3DRender::QParameter(QStringLiteral("WIN_SCALE"), QSize(1600, 800));
    Qt3DRender::QParameter* billboardParam3 = new Qt3DRender::QParameter(QStringLiteral("BB_SIZE"), QSize(100, 100));
    billboardMaterial->addParameter(billboardParam1);
    billboardMaterial->addParameter(billboardParam2);
    billboardMaterial->addParameter(billboardParam3);

    // Effect of material
    Qt3DRender::QEffect* billboardEffect = new Qt3DRender::QEffect();
    Qt3DRender::QTechnique* billboardTechnique = new Qt3DRender::QTechnique();
    billboardTechnique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL);
    billboardTechnique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::CoreProfile);
    billboardTechnique->graphicsApiFilter()->setMajorVersion(3);
    billboardTechnique->graphicsApiFilter()->setMinorVersion(1);
    // You need the filter key because the QForwardRenderer employed as the default framegraph by the Qt3DWindow
    // extends QTechniqueFilter and filters for this key exactly. Without it, the material gets discarded.
    Qt3DRender::QFilterKey* filterKey = new Qt3DRender::QFilterKey(billboardMaterial);
    filterKey->setName(QStringLiteral("renderingStyle"));
    filterKey->setValue(QStringLiteral("forward"));
    billboardTechnique->addFilterKey(filterKey);
    Qt3DRender::QRenderPass* billboardRenderPass = new Qt3DRender::QRenderPass();
    Qt3DRender::QShaderProgram* billboardShaderProgram = new Qt3DRender::QShaderProgram();
    billboardShaderProgram->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl("qrc:/shaders/billboards.vert")));
    //billboardShaderProgram->setGeometryShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl("qrc:/shaders/billboards.geom")));
    billboardShaderProgram->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl("qrc:/shaders/billboards.frag")));
    billboardRenderPass->setShaderProgram(billboardShaderProgram);
    billboardTechnique->addRenderPass(billboardRenderPass);
    billboardEffect->addTechnique(billboardTechnique);
    billboardMaterial->setEffect(billboardEffect);

    billboardEntity->addComponent(billboardRenderer);
    billboardEntity->addComponent(billboardMaterial);
    billboardEntity->addComponent(billboardTransform);

    return root;
}

int main(int argc, char* argv[])
{
    QGuiApplication app(argc, argv);

    Qt3DExtras::Qt3DWindow view;
    view.resize(windowWidth, windowHeight);
    Qt3DExtras::QForwardRenderer *renderer = (Qt3DExtras::QForwardRenderer *)view.activeFrameGraph();
    renderer->setClearColor("black");

    Qt3DRender::QCamera *camera = view.camera();
    camera->setProjectionType(Qt3DRender::QCameraLens::PerspectiveProjection);
    camera->setFieldOfView(45);
    // Cast to float to ensure float division
    camera->setAspectRatio(windowWidth / (float) windowHeight);
    camera->setNearPlane(0.1f);
    camera->setFarPlane(100.f);
    camera->setPosition(QVector3D(0., 10., 20.));
    camera->setViewCenter(QVector3D(0., 0., 0.));
    camera->setUpVector(QVector3D(0., 1., 0.));

    Qt3DCore::QEntity *root = createScene();
    view.setRootEntity(root);
    cameraController->setCamera(camera);

    view.setTitle("Billboards");
    view.show();

    return app.exec();
}

billboardgeometry.h

#ifndef BILLBOARDGEOMETRY_H
#define BILLBOARDGEOMETRY_H

#include <Qt3DRender/QGeometry>
#include <Qt3DRender/QBuffer>

#include <QVector3D>


class BillboardGeometry : public Qt3DRender::QGeometry
{
  Q_OBJECT

  Q_PROPERTY(int count READ count NOTIFY countChanged)

public:
  BillboardGeometry( Qt3DCore::QNode *parent = nullptr );

  void setPoints( const QVector<QVector3D> &vertices );

  int count();

signals:
    void countChanged(int count);

private:
  Qt3DRender::QAttribute *mPositionAttribute = nullptr;
  Qt3DRender::QBuffer *mVertexBuffer = nullptr;
  int mVertexCount = 0;
};

#endif // BILLBOARDGEOMETRY_H

billboardgeometry.cpp

#include "billboardgeometry.h"

#include <Qt3DRender/QAttribute>


BillboardGeometry::BillboardGeometry( Qt3DCore::QNode *parent )
  : Qt3DRender::QGeometry( parent )
  , mPositionAttribute( new Qt3DRender::QAttribute( this ) )
  , mVertexBuffer( new Qt3DRender::QBuffer( Qt3DRender::QBuffer::VertexBuffer, this ) )
{

  mPositionAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute );
  mPositionAttribute->setBuffer( mVertexBuffer );
  mPositionAttribute->setVertexBaseType( Qt3DRender::QAttribute::Float );
  mPositionAttribute->setVertexSize( 3 );
  mPositionAttribute->setName( Qt3DRender::QAttribute::defaultPositionAttributeName() );

  addAttribute( mPositionAttribute );

}

int BillboardGeometry::count()
{
  return mVertexCount;
}

void BillboardGeometry::setPoints(const QVector<QVector3D> &vertices)
{
  QByteArray vertexBufferData;
  vertexBufferData.resize( vertices.size() * 3 * sizeof( float ) );
  float *rawVertexArray = reinterpret_cast<float *>( vertexBufferData.data() );
  int idx = 0;
  for ( const auto &v : vertices )
  {
    rawVertexArray[idx++] = v.x();
    rawVertexArray[idx++] = v.y();
    rawVertexArray[idx++] = v.z();
  }

  mVertexCount = vertices.count();
  mVertexBuffer->setData( vertexBufferData );

  emit countChanged(mVertexCount);
}

billboard.vert

#version 150

uniform mat4 modelViewProjection;

in vec3 vertexPosition;

void main(void)
{
    gl_Position = modelViewProjection * vec4(vertexPosition, 1);
}

billboard.geom

#version 150

layout (points) in;
layout (triangle_strip, max_vertices = 4) out;

uniform mat4 modelViewProjection;

uniform vec2 BB_SIZE;    // billboard size in pixels
uniform vec2 WIN_SCALE;  // the size of the viewport in pixels

out vec2 UV;

void main (void)
{

    vec4 P = gl_in[0].gl_Position;
    P /= P.w;
    
    //vec2 size = vec2(0.5,0.5);
    vec2 size = BB_SIZE / WIN_SCALE;
    
    gl_Position = P;
    gl_Position.xy += vec2(-0.5,-0.5) * size;
    UV = vec2(0,0);
    EmitVertex();
    
    gl_Position = P;
    gl_Position.xy += vec2(0.5,-0.5) * size;
    UV = vec2(1,0);
    EmitVertex();
    
    gl_Position = P;
    gl_Position.xy += vec2(-0.5,+0.5) * size;
    UV = vec2(0,1);
    EmitVertex();
    
    gl_Position = P;
    gl_Position.xy += vec2(+0.5,+0.5) * size;
    UV = vec2(1,1);
    EmitVertex();
    
    EndPrimitive();
}

billboard.frag

#version 150

uniform sampler2D tex0;

in vec2 UV;

void main(void)
{
    //gl_FragColor = texture(tex0, UV);
    gl_FragColor = vec4(1, 1, 1, 1);
}

shaders.qrc

<RCC>
    <qresource prefix="/shaders">
        <file>billboards.frag</file>
        <file>billboards.vert</file>
        <file>billboards.geom</file>
    </qresource>
</RCC>

billboards.pro

TEMPLATE = app
QT += 3dcore 3drender 3dinput 3dquick qml quick 3dquickextras 3dextras

SOURCES += \
        main.cpp \
    billboardgeometry.cpp

RESOURCES += qml.qrc \
    shaders.qrc


# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

HEADERS += \
    billboardgeometry.h

success-kid.jpg

在此處輸入圖像描述

GitHub 用戶wonder-skismailsunni通過指出代碼中的錯誤為我解決了這個問題:

Qt3DRender::QParameter* billboardParam2 = new Qt3DRender::QParameter(QStringLiteral("WIN_SCALE"), QSize(1600, 800));
Qt3DRender::QParameter* billboardParam3 = new Qt3DRender::QParameter(QStringLiteral("BB_SIZE"), QSize(100, 100));

在這兩行中,它需要是QSizeF而不是QSize - 瞧,着色器正在工作!

或者,這里已經存在一個 C++ 端口。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM