├── .gitignore ├── MyEntity.qml ├── Qt3DTrackball.pro ├── README.md ├── main.cpp ├── main.qml ├── qml.qrc ├── trackballcameracontroller.cpp └── trackballcameracontroller.h /.gitignore: -------------------------------------------------------------------------------- 1 | # User-specific files 2 | *.suo 3 | *.user 4 | *.sln.docstates 5 | build_* 6 | build 7 | 8 | 3rd/windows 9 | 3rd/macos 10 | 11 | # Windows image file caches 12 | Thumbs.db 13 | ehthumbs.db 14 | 15 | # Folder config file 16 | Desktop.ini 17 | 18 | # Recycle Bin used on file shares 19 | $RECYCLE.BIN/ 20 | 21 | # Mac crap 22 | .DS_Store 23 | 24 | 25 | -------------------------------------------------------------------------------- /MyEntity.qml: -------------------------------------------------------------------------------- 1 | import Qt3D.Core 2.0 2 | import Qt3D.Render 2.0 3 | import Qt3D.Input 2.0 4 | import Qt3D.Extras 2.0 5 | 6 | import QtQuick 2.0 as QQ2 7 | import TrackballCameraController 1.0 8 | import QtQuick.Window 2.11 9 | 10 | Entity{ 11 | id: root 12 | property alias camera: camera 13 | 14 | Camera { 15 | id: camera 16 | projectionType: CameraLens.PerspectiveProjection 17 | fieldOfView: 45 18 | nearPlane : 0.1 19 | farPlane : 1000.0 20 | position: Qt.vector3d( 0.0, 0.0, 40.0 ) 21 | upVector: Qt.vector3d( 0.0, 1.0, 0.0 ) 22 | viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 ) 23 | } 24 | 25 | TrackballCameraController{ 26 | camera: camera 27 | windowSize: Qt.size(window.width, window.height) 28 | rotationSpeed: 2.0 29 | } 30 | 31 | components: [ 32 | RenderSettings { 33 | activeFrameGraph: ForwardRenderer { 34 | camera: camera 35 | clearColor: "transparent" 36 | } 37 | }, 38 | InputSettings { } 39 | ] 40 | 41 | PhongMaterial { 42 | id: material 43 | } 44 | 45 | // TorusMesh { 46 | // id: torusMesh 47 | // radius: 5 48 | // minorRadius: 1 49 | // rings: 100 50 | // slices: 20 51 | // } 52 | CuboidMesh{ 53 | id: cuboidMesh 54 | xExtent: 10 55 | yExtent: 10 56 | zExtent: 10 57 | } 58 | 59 | Transform { 60 | id: torusTransform 61 | //scale3D: Qt.vector3d(1.5, 1, 0.5) 62 | //rotation: fromAxisAndAngle(Qt.vector3d(1, 0, 0), 45) 63 | } 64 | 65 | Entity { 66 | id: torusEntity 67 | components: [ cuboidMesh, material, torusTransform ] 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Qt3DTrackball.pro: -------------------------------------------------------------------------------- 1 | QT += quick 3drender 3dinput 3dlogic 3dextras 2 | CONFIG += c++11 3 | 4 | # The following define makes your compiler emit warnings if you use 5 | # any feature of Qt which as been marked deprecated (the exact warnings 6 | # depend on your compiler). Please consult the documentation of the 7 | # deprecated API in order to know how to port your code away from it. 8 | DEFINES += QT_DEPRECATED_WARNINGS 9 | 10 | # You can also make your code fail to compile if you use deprecated APIs. 11 | # In order to do so, uncomment the following line. 12 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 13 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 14 | 15 | SOURCES += \ 16 | main.cpp \ 17 | trackballcameracontroller.cpp 18 | 19 | RESOURCES += qml.qrc 20 | 21 | # Additional import path used to resolve QML modules in Qt Creator's code model 22 | QML_IMPORT_PATH = 23 | 24 | # Additional import path used to resolve QML modules just for Qt Quick Designer 25 | QML_DESIGNER_IMPORT_PATH = 26 | 27 | # Default rules for deployment. 28 | qnx: target.path = /tmp/$${TARGET}/bin 29 | else: unix:!android: target.path = /opt/$${TARGET}/bin 30 | !isEmpty(target.path): INSTALLS += target 31 | 32 | HEADERS += \ 33 | trackballcameracontroller.h 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Qt3DTrackball 2 | Trackball camera manipulator for Qt3D. 3 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "trackballcameracontroller.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 8 | 9 | QGuiApplication app(argc, argv); 10 | 11 | qmlRegisterType("TrackballCameraController", 1, 0, "TrackballCameraController"); 12 | QQmlApplicationEngine engine; 13 | engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 14 | if (engine.rootObjects().isEmpty()) 15 | return -1; 16 | 17 | return app.exec(); 18 | } 19 | -------------------------------------------------------------------------------- /main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.11 2 | import QtQuick.Window 2.11 3 | import QtQuick.Scene3D 2.0 4 | import QtQuick.Controls 2.4 5 | 6 | Window { 7 | id: window 8 | visible: true 9 | width: 800 10 | height: 600 11 | title: qsTr("Qt3D Trackball") 12 | 13 | Scene3D{ 14 | id: scene3D 15 | anchors.fill: parent 16 | focus: true 17 | aspects: ["input", "logic"] 18 | cameraAspectRatioMode: Scene3D.AutomaticAspectRatio 19 | 20 | MyEntity{ 21 | id: rootEntity 22 | } 23 | 24 | } 25 | 26 | Button{ 27 | anchors{ 28 | right: parent.right; 29 | bottom: parent.bottom; 30 | margins: 10 31 | } 32 | text: "Home" 33 | onClicked: { 34 | rootEntity.camera.viewAll(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main.qml 4 | MyEntity.qml 5 | 6 | 7 | -------------------------------------------------------------------------------- /trackballcameracontroller.cpp: -------------------------------------------------------------------------------- 1 | #include "trackballcameracontroller.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | TrackballCameraController::TrackballCameraController(Qt3DCore::QNode *parent) 16 | : Qt3DExtras::QAbstractCameraController (parent) 17 | { 18 | Qt3DInput::QMouseHandler *mouseHandler = new Qt3DInput::QMouseHandler(this); 19 | mouseHandler->setSourceDevice(mouseDevice()); 20 | 21 | QObject::connect(mouseHandler, &Qt3DInput::QMouseHandler::pressed, 22 | [this](Qt3DInput::QMouseEvent *pressedEvent) { 23 | pressedEvent->setAccepted(true); 24 | m_mouseLastPosition = QPoint(pressedEvent->x(), pressedEvent->y()); 25 | m_mouseCurrentPosition = m_mouseLastPosition; 26 | }); 27 | 28 | QObject::connect(mouseHandler, &Qt3DInput::QMouseHandler::positionChanged, 29 | [this](Qt3DInput::QMouseEvent *positionChangedEvent) { 30 | positionChangedEvent->setAccepted(true); 31 | m_mouseCurrentPosition = QPoint(positionChangedEvent->x(), 32 | positionChangedEvent->y()); 33 | }); 34 | //keyboardDevice()->set 35 | } 36 | 37 | QVector3D TrackballCameraController::projectToTrackball(const QPoint &screenCoords) const 38 | { 39 | float sx = screenCoords.x(), sy = m_windowSize.height() - screenCoords.y(); 40 | 41 | QVector2D p2d(sx / m_windowSize.width() - 0.5f, sy / m_windowSize.height() - 0.5f); 42 | //qDebug()< 1? 1 : (x < -1? -1 : x); 59 | } 60 | 61 | void TrackballCameraController::createRotation(const QPoint &firstPoint, const QPoint &nextPoint, 62 | QVector3D &dir, float &angle) 63 | { 64 | auto lastPos3D = projectToTrackball(firstPoint).normalized(); 65 | auto currentPos3D = projectToTrackball(nextPoint).normalized(); 66 | 67 | // Compute axis of rotation: 68 | dir = QVector3D::crossProduct(currentPos3D, lastPos3D); 69 | 70 | // Approximate rotation angle: 71 | //qDebug()<<"dot:"<transform()->rotation(); 93 | 94 | auto rotatedAxis = currentRotation.rotatedVector(dir); 95 | angle *= m_rotationSpeed; 96 | 97 | theCamera->rotateAboutViewCenter(QQuaternion::fromAxisAndAngle(rotatedAxis, angle * M_1_PI * 180)); 98 | }else if(state.middleMouseButtonActive){ 99 | auto offset = m_mouseCurrentPosition - m_mouseLastPosition; 100 | qDebug()<<"offset:"<translate(QVector3D(-offset.x() / float(m_windowSize.width()) * ls, 102 | offset.y() / float(m_windowSize.height()) * ls, 103 | 0)); 104 | 105 | 106 | }else if(dt != 0){ 107 | qDebug()<<"dt:"<translate(QVector3D(state.txAxisValue * ls, 109 | state.tyAxisValue * ls, 110 | state.tzAxisValue * ls) * dt, 111 | Qt3DRender::QCamera::DontTranslateViewCenter); 112 | } 113 | m_mouseLastPosition = m_mouseCurrentPosition; 114 | } 115 | -------------------------------------------------------------------------------- /trackballcameracontroller.h: -------------------------------------------------------------------------------- 1 | #ifndef TRACKBALLCAMERACONTROLLER_H 2 | #define TRACKBALLCAMERACONTROLLER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class TrackballCameraController : public Qt3DExtras::QAbstractCameraController 10 | { 11 | Q_OBJECT 12 | public: 13 | Q_PROPERTY(QSize windowSize READ windowSize WRITE setWindowSize NOTIFY windowSizeChanged) 14 | Q_PROPERTY(float trackballSize READ trackballSize WRITE setTrackballSize NOTIFY trackballSizeChanged) 15 | Q_PROPERTY(float rotationSpeed READ rotationSpeed WRITE setRotationSpeed NOTIFY rotationSpeedChanged) 16 | 17 | TrackballCameraController(Qt3DCore::QNode *parent = nullptr); 18 | 19 | QSize windowSize() const 20 | { 21 | return m_windowSize; 22 | } 23 | 24 | float trackballSize() const 25 | { 26 | return m_trackballSize; 27 | } 28 | 29 | float rotationSpeed() const 30 | { 31 | return m_rotationSpeed; 32 | } 33 | 34 | public slots: 35 | void setWindowSize(QSize windowSize) 36 | { 37 | if (m_windowSize == windowSize) 38 | return; 39 | 40 | m_windowSize = windowSize; 41 | emit windowSizeChanged(m_windowSize); 42 | } 43 | 44 | void setTrackballSize(float trackballSize) 45 | { 46 | if (qFuzzyCompare(m_trackballSize, trackballSize)) 47 | return; 48 | 49 | m_trackballSize = trackballSize; 50 | emit trackballSizeChanged(m_trackballSize); 51 | } 52 | 53 | void setRotationSpeed(float rotationSpeed) 54 | { 55 | if (qFuzzyCompare(m_rotationSpeed, rotationSpeed)) 56 | return; 57 | 58 | m_rotationSpeed = rotationSpeed; 59 | emit rotationSpeedChanged(m_rotationSpeed); 60 | } 61 | 62 | signals: 63 | void windowSizeChanged(QSize windowSize); 64 | void trackballSizeChanged(float trackballSize); 65 | void rotationSpeedChanged(float rotationSpeed); 66 | 67 | protected: 68 | void moveCamera(const Qt3DExtras::QAbstractCameraController::InputState &state, float dt) override; 69 | QVector3D projectToTrackball(const QPoint &screenCoords) const; 70 | void createRotation(const QPoint &firstPoint, 71 | const QPoint &nextPoint, QVector3D &dir, float &angle); 72 | 73 | private: 74 | QPoint m_mouseLastPosition, m_mouseCurrentPosition; 75 | QSize m_windowSize; 76 | float m_trackballRadius = 1.0f; 77 | float m_panSpeed = 1.0f; 78 | float m_zoomSpeed = 1.0f; 79 | float m_rotationSpeed = 1.0f; 80 | float m_zoomCameraLimit = 1.0f; 81 | float m_trackballSize = 1.0f; 82 | }; 83 | 84 | #endif // TRACKBALLCAMERACONTROLLER_H 85 | --------------------------------------------------------------------------------