diff --git a/src/quick3d/qquick3dcamera.cpp b/src/quick3d/qquick3dcamera.cpp
index b5c8c967bd498a90d199d332d2af00835d79922d..76e1a16d64b9ab382ceaeb7e60e0af4b6cdf4f14 100644
--- a/src/quick3d/qquick3dcamera.cpp
+++ b/src/quick3d/qquick3dcamera.cpp
@@ -272,7 +272,21 @@ QVector3D QQuick3DCamera::mapFromViewport(const QVector3D &viewportPos,
 
 void QQuick3DCamera::lookAt(const QVector3D &scenePos)
 {
-    this->setRotation(QQuick3DQuaternionUtils::lookAt(scenePosition(), forward(), scenePos, up()));
+    // Assumption: we never want the camera to roll.
+    // We use Euler angles here to avoid roll to sneak in through numerical instability.
+
+    const auto &targetPosition = scenePos;
+    auto sourcePosition = scenePosition();
+
+    QVector3D targetVector = sourcePosition - targetPosition;
+
+    float yaw = qRadiansToDegrees(atan2(targetVector.x(), targetVector.z()));
+
+    QVector2D p(targetVector.x(), targetVector.z()); // yaw vector projected to horizontal plane
+    float pitch = qRadiansToDegrees(atan2(p.length(), targetVector.y())) - 90;
+
+    const float previousRoll = eulerRotation().z();
+    setEulerRotation(QVector3D(pitch, yaw, previousRoll));
 }
 
 /*!
@@ -282,7 +296,7 @@ void QQuick3DCamera::lookAt(const QVector3D &scenePos)
     Sets the rotation value of a camera to be directed at \a node.
 */
 
-void QQuick3DCamera::lookAt(const QQuick3DNode *node)
+void QQuick3DCamera::lookAt(QQuick3DNode *node)
 {
     if (!node)
         return;
diff --git a/src/quick3d/qquick3dcamera_p.h b/src/quick3d/qquick3dcamera_p.h
index 3bb923dbb7d9647510b22e59ac54c87d6446d2e9..aa8b15105d2f6ecf08fabe8ef83cf4bf9f02b756 100644
--- a/src/quick3d/qquick3dcamera_p.h
+++ b/src/quick3d/qquick3dcamera_p.h
@@ -70,7 +70,7 @@ public:
                               qreal height);
 
     Q_REVISION(1) Q_INVOKABLE void lookAt(const QVector3D &scenePos);
-    Q_REVISION(1) Q_INVOKABLE void lookAt(const QQuick3DNode *node);
+    Q_REVISION(1) Q_INVOKABLE void lookAt(QQuick3DNode *node);
 
     QSSGRenderCamera *cameraNode() const;
     void setCameraNode(QSSGRenderCamera *camera) { m_cameraNode = camera; }
diff --git a/src/quick3d/qquick3dnode_p.h b/src/quick3d/qquick3dnode_p.h
index ea4dc8125fd0da63baddf73c22c03b08b1a6c140..a11a2e3cb96d8605ee5188c059409b875b1a249a 100644
--- a/src/quick3d/qquick3dnode_p.h
+++ b/src/quick3d/qquick3dnode_p.h
@@ -173,4 +173,6 @@ private:
 
 QT_END_NAMESPACE
 
+QML_DECLARE_TYPE(QQuick3DNode)
+
 #endif // QSSGNODE_H
diff --git a/src/quick3d/qquick3dquaternionutils.cpp b/src/quick3d/qquick3dquaternionutils.cpp
index 80bf004702ecfde5b564e0275b1ed4bb4453583f..5c0e0f0f3bfd866e4a501b715f1dbc8c622c24e6 100644
--- a/src/quick3d/qquick3dquaternionutils.cpp
+++ b/src/quick3d/qquick3dquaternionutils.cpp
@@ -74,12 +74,15 @@ QT_BEGIN_NAMESPACE
  */
 
 /*!
-    \qmlmethod quaternion Quick3D::Quaternion::lookAt(vector3d sourcePosition, vector3d sourceDirection,
-                                                      vector3d targetPosition, vector3d upDirection)
-    Creates a quaternion from \a sourcePosition, \a sourceDirection, \a targetPosition, and
+    \qmlmethod quaternion Quick3D::Quaternion::lookAt(vector3d sourcePosition, vector3d targetPosition,
+                                                      vector3d forwardDirection, vector3d upDirection)
+    Creates a quaternion from \a sourcePosition, \a targetPosition, \a forwardDirection, and
     \a upDirection.  This is used for getting a rotation value for pointing at a particular target,
     and can be used to point a camera at a position in a scene.
 
+    \a forwardDirection defaults to \c Qt.vector3d(0, 0, -1)
+    \a upDirection defaults to \c Qt.vector3d(0, 1, 0)
+
     Returns the resulting quaternion.
  */
 
@@ -109,20 +112,20 @@ QQuaternion QQuick3DQuaternionUtils::fromEulerAngles(const QVector3D &eulerAngle
 }
 
 QQuaternion QQuick3DQuaternionUtils::lookAt(const QVector3D &sourcePosition,
-                                            const QVector3D &sourceDirection,
                                             const QVector3D &targetPosition,
+                                            const QVector3D &forwardDirection,
                                             const QVector3D &upDirection)
 {
-    QVector3D targetDirection = sourcePosition - targetPosition;
+    QVector3D targetDirection = targetPosition - sourcePosition;
     targetDirection.normalize();
 
-    QVector3D rotationAxis = QVector3D::crossProduct(sourceDirection, targetDirection);
+    QVector3D rotationAxis = QVector3D::crossProduct(forwardDirection, targetDirection);
 
     const QVector3D normalizedAxis = rotationAxis.normalized();
-    if (normalizedAxis.lengthSquared() == 0)
+    if (qFuzzyIsNull(normalizedAxis.lengthSquared()))
         rotationAxis = upDirection;
 
-    float dot = QVector3D::dotProduct(sourceDirection, targetDirection);
+    float dot = QVector3D::dotProduct(forwardDirection, targetDirection);
     float rotationAngle = qRadiansToDegrees(qAcos(dot));
 
     return QQuaternion::fromAxisAndAngle(rotationAxis, rotationAngle);
diff --git a/src/quick3d/qquick3dquaternionutils_p.h b/src/quick3d/qquick3dquaternionutils_p.h
index 2bcd55367a51cddf96b32c1775549eaa30425b1f..4bac4e83e1f09ff75656f064ef252161945b4084 100644
--- a/src/quick3d/qquick3dquaternionutils_p.h
+++ b/src/quick3d/qquick3dquaternionutils_p.h
@@ -71,8 +71,9 @@ public:
     Q_INVOKABLE static QQuaternion fromEulerAngles(const QVector3D &eulerAngles);
 
     Q_REVISION(1) Q_INVOKABLE static QQuaternion lookAt(const QVector3D &sourcePosition,
-                                                        const QVector3D &sourceDirection,
                                                         const QVector3D &targetPosition,
+                                                        const QVector3D &forwardDirection
+                                                        = QVector3D(0, 0, -1),
                                                         const QVector3D &upDirection
                                                         = QVector3D(0, 1, 0));
 
diff --git a/tests/manual/cameralookat/main.qml b/tests/manual/cameralookat/main.qml
index 6e4200d9bd24770c84f1b959acc6e6b8977a3d0d..59f1fab8e6a71478ebcc70df75ccbc03a5b147ae 100644
--- a/tests/manual/cameralookat/main.qml
+++ b/tests/manual/cameralookat/main.qml
@@ -44,6 +44,9 @@ Window {
         PerspectiveCamera {
             id: sceneCamera
             z: 300
+            x: -200
+            y: 100
+            eulerRotation: Qt.vector3d(-15, -30, 0)
         }
 
         Model {
@@ -86,7 +89,7 @@ Window {
         Button {
             text: "Cube"
             onClicked: {
-                sceneCamera.rotation = Quaternion.lookAt(sceneCamera.scenePosition, sceneCamera.forward, cube.scenePosition, sceneCamera.up);
+                sceneCamera.rotation = Quaternion.lookAt(sceneCamera.scenePosition, cube.scenePosition)
             }
         }
         Button {