With Qt3D, we can use signals and slots in order to connect a per-frame callback.
In short, we setup a QFrameAction
on our root entity. We set up a handler and a slot to be called when the signal is emitted.
We can use this to handle lower level functions in the graphcis pipeline such as manually updating the data in a vertex buffer.
# BufferSyncHandler.h
class BufferSyncHandler: public QObject {
public:
BufferSyncHandler();
~BufferSyncHandler();
public slots:
void SyncPositions(float dt)
};
# BufferSyncHandler.cpp
#include "BufferSyncHandler.h"
#include <iostream>
#include <stdio.h>
using namespace std;
BufferSyncHandler::BufferSyncHandler() { }
BufferSyncHandler::~BufferSyncHandler() { }
void BufferSyncHandler::SyncPositions(float dt) { cout << "Time elapsed since last call" << dt << endl; }
The following boiler plate code is adapted from the Qt3D basicshapes
example. Note that I have connected the QFrameAction triggered
signal to our handler.
#include "scenemodifier.h"
#include <QGuiApplication>
#include <Qt3DRender/qcamera.h>
#include <Qt3DCore/qentity.h>
#include <Qt3DRender/qcameralens.h>
#include <QtWidgets/QApplication>
#include <QtWidgets/QWidget>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QCheckBox>
#include <QtWidgets/QCommandLinkButton>
#include <QtGui/QScreen>
#include <Qt3DInput/QInputAspect>
#include <Qt3DExtras/qtorusmesh.h>
#include <Qt3DRender/qmesh.h>
#include <Qt3DRender/qtechnique.h>
#include <Qt3DRender/qmaterial.h>
#include <Qt3DRender/qeffect.h>
#include <Qt3DRender/qtexture.h>
#include <Qt3DRender/qrenderpass.h>
#include <Qt3DRender/qsceneloader.h>
#include <Qt3DRender/qpointlight.h>
#include <Qt3DLogic/qframeaction.h>
#include <Qt3DCore/qtransform.h>
#include <Qt3DCore/qaspectengine.h>
#include <Qt3DRender/qrenderaspect.h>
#include <Qt3DExtras/qforwardrenderer.h>
#include <Qt3DExtras/qt3dwindow.h>
#include <Qt3DExtras/qfirstpersoncameracontroller.h>
#include "MassBufferSyncHandler.h"
int main(int argc, char **argv)
{
QApplication app(argc, argv);
Qt3DExtras::Qt3DWindow *view = new Qt3DExtras::Qt3DWindow();
view->defaultFrameGraph()->setClearColor(QColor(QRgb(0x4d4d4f)));
QWidget *container = QWidget::createWindowContainer(view);
QSize screenSize = view->screen()->size();
container->setMinimumSize(QSize(200, 100));
container->setMaximumSize(screenSize);
QWidget *widget = new QWidget;
QHBoxLayout *hLayout = new QHBoxLayout(widget);
QVBoxLayout *vLayout = new QVBoxLayout();
vLayout->setAlignment(Qt::AlignTop);
hLayout->addLayout(vLayout);
hLayout->addWidget(container, 1);
widget->setWindowTitle(QStringLiteral("Basic shapes"));
Qt3DInput::QInputAspect *input = new Qt3DInput::QInputAspect;
view->registerAspect(input);
// Root entity
Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
// Camera
Qt3DRender::QCamera *cameraEntity = view->camera();
cameraEntity->lens()->setPerspectiveProjection(45.0f, 16.0f / 9.0f, 0.1f, 1000.0f);
cameraEntity->setPosition(QVector3D(0, 0.0f, 20.0f));
cameraEntity->setUpVector(QVector3D(0, 1.0f, 0.0f));
cameraEntity->setViewCenter(QVector3D(0, 0, 0));
Qt3DCore::QEntity *lightEntity = new Qt3DCore::QEntity(rootEntity);
Qt3DRender::QPointLight *light = new Qt3DRender::QPointLight(lightEntity);
light->setColor("white");
light->setIntensity(1);
lightEntity->addComponent(light);
Qt3DCore::QTransform *lightTransform = new Qt3DCore::QTransform(lightEntity);
lightTransform->setTranslation(cameraEntity->position());
lightEntity->addComponent(lightTransform);
// For camera controls
Qt3DExtras::QFirstPersonCameraController *camController = new Qt3DExtras::QFirstPersonCameraController(rootEntity);
camController->setCamera(cameraEntity);
// Scenemodifier
SceneModifier *modifier = new SceneModifier(rootEntity);
// Sync handler
BufferSyncHandler *mbSync = new BufferSyncHandler();
// Create a frame action and set it to our root entity
Qt3DLogic::QFrameAction *fa = new Qt3DLogic::QFrameAction;
rootEntity->addComponent(fa);
// Connect the QFrameAction triggered signal to the slot on our handler.
fa->connect(fa, &Qt3DLogic::QFrameAction::triggered, mbSync, &MassBufferSyncHandler::SyncMassPositions);
// Set root object of the scene
view->setRootEntity(rootEntity);
// Create control widgets
QCommandLinkButton *info = new QCommandLinkButton();
info->setText(QStringLiteral("Qt3D ready-made meshes"));
info->setDescription(QString::fromLatin1("Qt3D provides several ready-made meshes, like torus, cylinder, cone, "
"cube, plane and sphere."));
info->setIconSize(QSize(0, 0));
QCheckBox *cuboidCB = new QCheckBox(widget);
cuboidCB->setChecked(true);
cuboidCB->setText(QStringLiteral("Cuboid"));
vLayout->addWidget(cuboidCB);
QObject::connect(cuboidCB, &QCheckBox::stateChanged,
modifier, &SceneModifier::enableCuboid);
cuboidCB->setChecked(true);
// Show window
widget->show();
widget->resize(1200, 800);
return app.exec();
}