Revision control
Copy as Markdown
// Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qjoint.h"
#include "qjoint_p.h"
QT_BEGIN_NAMESPACE
namespace Qt3DCore {
QJointPrivate::QJointPrivate()
: QNodePrivate()
, m_inverseBindMatrix()
, m_rotation()
, m_translation()
, m_scale(1.0f, 1.0f, 1.0f)
{
}
/*!
\qmltype Joint
\inqmlmodule Qt3D.Core
\inherits Node
\nativetype Qt3DCore::QJoint
\since 5.10
\brief Used to transforms parts of skinned meshes.
The Joint node is used to build skeletons as part of the skinned mesh
support in Qt 3D. A joint can be transformed by way of its scale, rotation
and translation properties. Any mesh vertices that are bound to the joint
will have their transformations updated accordingly.
*/
/*!
\qmlproperty vector3d Joint::scale
Holds the uniform scale of the joint.
*/
/*!
\qmlproperty quaternion Joint::rotation
Holds the rotation of the joint as quaternion.
*/
/*!
\qmlproperty vector3d Joint::translation
Holds the translation of the joint as vector3d.
*/
/*!
\qmlproperty real Joint::rotationX
Holds the x rotation of the joint as an Euler angle.
*/
/*!
\qmlproperty real Joint::rotationY
Holds the y rotation of the joint as an Euler angle.
*/
/*!
\qmlproperty real Joint::rotationZ
Holds the z rotation of the joint as an Euler angle.
*/
/*!
\qmlproperty matrix4x4 Joint::inverseBindMatrix
Holds the inverse bind matrix of the joint. This is used to transform
vertices from model space into the space of this joint so they can
subsequently be multiplied by the joint's global transform to perform
the skinning operation.
*/
/*!
\class Qt3DCore::QJoint
\inmodule Qt3DCore
\inherits Qt3DCore::QNode
\since 5.10
\brief Used to transforms parts of skinned meshes.
The QJoint node is used to build skeletons as part of the skinned mesh
support in Qt 3D. A joint can be transformed by way of its scale, rotation
and translation properties. Any mesh vertices that are bound to the joint
will have their transformations updated accordingly.
*/
/*!
Constructs a new QJoint with \a parent.
*/
QJoint::QJoint(Qt3DCore::QNode *parent)
: QNode(*new QJointPrivate, parent)
{
}
/*! \internal */
QJoint::~QJoint()
{
}
/*!
\property Qt3DCore::QJoint::scale
Holds the scale of the joint.
*/
QVector3D QJoint::scale() const
{
Q_D(const QJoint);
return d->m_scale;
}
/*!
\property Qt3DCore::QJoint::rotation
Holds the rotation of the joint as QQuaternion.
*/
QQuaternion QJoint::rotation() const
{
Q_D(const QJoint);
return d->m_rotation;
}
/*!
\property Qt3DCore::QJoint::translation
Holds the translation of the joint as QVector3D.
*/
QVector3D QJoint::translation() const
{
Q_D(const QJoint);
return d->m_translation;
}
/*!
\property Qt3DCore::QJoint::inverseBindMatrix
Holds the inverse bind matrix of the joint. This is used to transform
vertices from model space into the space of this joint so they can
subsequently be multiplied by the joint's global transform to perform
the skinning operation.
*/
QMatrix4x4 QJoint::inverseBindMatrix() const
{
Q_D(const QJoint);
return d->m_inverseBindMatrix;
}
/*!
\property Qt3DCore::QJoint::rotationX
Holds the x rotation of the joint as an Euler angle.
*/
float QJoint::rotationX() const
{
Q_D(const QJoint);
return d->m_eulerRotationAngles.x();
}
/*!
\property Qt3DCore::QJoint::rotationY
Holds the y rotation of the joint as an Euler angle.
*/
float QJoint::rotationY() const
{
Q_D(const QJoint);
return d->m_eulerRotationAngles.y();
}
/*!
\property Qt3DCore::QJoint::rotationZ
Holds the z rotation of the joint as an Euler angle.
*/
float QJoint::rotationZ() const
{
Q_D(const QJoint);
return d->m_eulerRotationAngles.z();
}
void QJoint::setScale(const QVector3D &scale)
{
Q_D(QJoint);
if (scale == d->m_scale)
return;
d->m_scale = scale;
emit scaleChanged(scale);
}
void QJoint::setRotation(const QQuaternion &rotation)
{
Q_D(QJoint);
if (rotation == d->m_rotation)
return;
d->m_rotation = rotation;
const QVector3D oldRotation = d->m_eulerRotationAngles;
d->m_eulerRotationAngles = d->m_rotation.toEulerAngles();
emit rotationChanged(rotation);
const bool wasBlocked = blockNotifications(true);
if (!qFuzzyCompare(d->m_eulerRotationAngles.x(), oldRotation.x()))
emit rotationXChanged(d->m_eulerRotationAngles.x());
if (!qFuzzyCompare(d->m_eulerRotationAngles.y(), oldRotation.y()))
emit rotationYChanged(d->m_eulerRotationAngles.y());
if (!qFuzzyCompare(d->m_eulerRotationAngles.z(), oldRotation.z()))
emit rotationZChanged(d->m_eulerRotationAngles.z());
blockNotifications(wasBlocked);
}
void QJoint::setTranslation(const QVector3D &translation)
{
Q_D(QJoint);
if (translation == d->m_translation)
return;
d->m_translation = translation;
emit translationChanged(translation);
}
void QJoint::setInverseBindMatrix(const QMatrix4x4 &inverseBindMatrix)
{
Q_D(QJoint);
if (d->m_inverseBindMatrix == inverseBindMatrix)
return;
d->m_inverseBindMatrix = inverseBindMatrix;
emit inverseBindMatrixChanged(inverseBindMatrix);
}
void QJoint::setRotationX(float rotationX)
{
Q_D(QJoint);
if (qFuzzyCompare(d->m_eulerRotationAngles.x(), rotationX))
return;
const auto eulers = QVector3D(rotationX,
d->m_eulerRotationAngles.y(),
d->m_eulerRotationAngles.z());
const QQuaternion r = QQuaternion::fromEulerAngles(eulers);
setRotation(r);
}
void QJoint::setRotationY(float rotationY)
{
Q_D(QJoint);
if (qFuzzyCompare(d->m_eulerRotationAngles.y(), rotationY))
return;
const auto eulers = QVector3D(d->m_eulerRotationAngles.x(),
rotationY,
d->m_eulerRotationAngles.z());
const QQuaternion r = QQuaternion::fromEulerAngles(eulers);
setRotation(r);
}
void QJoint::setRotationZ(float rotationZ)
{
Q_D(QJoint);
if (qFuzzyCompare(d->m_eulerRotationAngles.z(), rotationZ))
return;
const auto eulers = QVector3D(d->m_eulerRotationAngles.x(),
d->m_eulerRotationAngles.y(),
rotationZ);
const QQuaternion r = QQuaternion::fromEulerAngles(eulers);
setRotation(r);
}
void QJoint::setName(const QString &name)
{
Q_D(QJoint);
if (d->m_name == name)
return;
d->m_name = name;
emit nameChanged(name);
}
/*!
Sets the transform matrix for this joint to the identity matrix.
*/
void QJoint::setToIdentity()
{
setScale(QVector3D(1.0f, 1.0f, 1.0f));
setRotation(QQuaternion());
setTranslation(QVector3D());
}
/*!
Adds \a joint as a child of this joint. If \a joint has no parent, then
this joint takes ownership of it. Child joints are in the coordinate system
of their parent joint.
*/
void QJoint::addChildJoint(QJoint *joint)
{
Q_D(QJoint);
if (!d->m_childJoints.contains(joint)) {
d->m_childJoints.push_back(joint);
// Force creation in backend by setting parent
if (!joint->parent())
joint->setParent(this);
// Ensures proper bookkeeping
d->registerDestructionHelper(joint, &QJoint::removeChildJoint, d->m_childJoints);
if (d->m_changeArbiter != nullptr)
d->update();
}
}
/*!
Removes \a joint from this joint's list of children. The child joint is not
destroyed.
*/
void QJoint::removeChildJoint(QJoint *joint)
{
Q_D(QJoint);
if (d->m_childJoints.contains(joint)) {
if (d->m_changeArbiter != nullptr)
d->update();
d->m_childJoints.removeOne(joint);
// Remove bookkeeping connection
d->unregisterDestructionHelper(joint);
}
}
/*!
The vector of joints this joint has as children.
*/
QList<QJoint *> QJoint::childJoints() const
{
Q_D(const QJoint);
return d->m_childJoints;
}
/*!
\property Qt3DCore::QJoint::name
\brief the name of the joint.
Holds the name of the joint, which can be used to identify the joint
within a skeleton.
*/
/*!
Returns the name of the joint.
*/
QString QJoint::name() const
{
Q_D(const QJoint);
return d->m_name;
}
} // namespace Qt3DCore
QT_END_NAMESPACE
#include "moc_qjoint.cpp"